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_BUFFERED && setup.soft_scrolling)
242 BX2 = SCR_FIELDX + 1;
243 BY2 = SCR_FIELDY + 1;
247 drawto_field = fieldbuffer;
249 else /* DRAW_BACKBUFFER */
255 BX2 = SCR_FIELDX - 1;
256 BY2 = SCR_FIELDY - 1;
260 drawto_field = backbuffer;
264 static void RedrawPlayfield_RND()
266 if (game.envelope_active)
269 DrawLevel(REDRAW_ALL);
273 void RedrawPlayfield()
275 if (game_status != GAME_MODE_PLAYING)
278 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
279 RedrawPlayfield_EM(TRUE);
280 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
281 RedrawPlayfield_SP(TRUE);
282 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
283 RedrawPlayfield_RND();
285 BlitScreenToBitmap(backbuffer);
287 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
291 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
293 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
295 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
298 void DrawMaskedBorder_FIELD()
300 if (global.border_status >= GAME_MODE_TITLE &&
301 global.border_status <= GAME_MODE_PLAYING &&
302 border.draw_masked[global.border_status])
303 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
306 void DrawMaskedBorder_DOOR_1()
308 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
309 (global.border_status != GAME_MODE_EDITOR ||
310 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
311 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
314 void DrawMaskedBorder_DOOR_2()
316 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
317 global.border_status != GAME_MODE_EDITOR)
318 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
321 void DrawMaskedBorder_DOOR_3()
323 /* currently not available */
326 void DrawMaskedBorder_ALL()
328 DrawMaskedBorder_FIELD();
329 DrawMaskedBorder_DOOR_1();
330 DrawMaskedBorder_DOOR_2();
331 DrawMaskedBorder_DOOR_3();
334 void DrawMaskedBorder(int redraw_mask)
336 /* never draw masked screen borders on borderless screens */
337 if (effectiveGameStatus() == GAME_MODE_LOADING ||
338 effectiveGameStatus() == GAME_MODE_TITLE)
341 /* never draw masked screen borders when displaying request outside door */
342 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
343 global.use_envelope_request)
346 if (redraw_mask & REDRAW_ALL)
347 DrawMaskedBorder_ALL();
350 if (redraw_mask & REDRAW_FIELD)
351 DrawMaskedBorder_FIELD();
352 if (redraw_mask & REDRAW_DOOR_1)
353 DrawMaskedBorder_DOOR_1();
354 if (redraw_mask & REDRAW_DOOR_2)
355 DrawMaskedBorder_DOOR_2();
356 if (redraw_mask & REDRAW_DOOR_3)
357 DrawMaskedBorder_DOOR_3();
361 static void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
363 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
364 int fx = FX, fy = FY;
365 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
366 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
368 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
369 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
370 int dx_var = dx * TILESIZE_VAR / TILESIZE;
371 int dy_var = dy * TILESIZE_VAR / TILESIZE;
374 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
375 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
377 if (EVEN(SCR_FIELDX))
379 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
380 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
382 fx += (dx_var > 0 ? TILEX_VAR : 0);
389 if (EVEN(SCR_FIELDY))
391 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
392 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
394 fy += (dy_var > 0 ? TILEY_VAR : 0);
401 if (full_lev_fieldx <= SCR_FIELDX)
403 if (EVEN(SCR_FIELDX))
404 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
406 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
409 if (full_lev_fieldy <= SCR_FIELDY)
411 if (EVEN(SCR_FIELDY))
412 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
414 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
417 if (border.draw_masked[GAME_MODE_PLAYING])
419 if (buffer != backbuffer)
421 /* copy playfield buffer to backbuffer to add masked border */
422 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
423 DrawMaskedBorder(REDRAW_FIELD);
426 BlitBitmap(backbuffer, target_bitmap,
427 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
432 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
436 void BlitScreenToBitmap(Bitmap *target_bitmap)
438 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
439 BlitScreenToBitmap_EM(target_bitmap);
440 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
441 BlitScreenToBitmap_SP(target_bitmap);
442 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
443 BlitScreenToBitmap_RND(target_bitmap);
449 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
451 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
452 redraw_mask |= REDRAW_FIELD;
455 // never redraw single tiles, always redraw the whole field
456 // (redrawing single tiles up to a certain threshold was faster on old,
457 // now legacy graphics, but slows things down on modern graphics now)
458 // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
459 if (redraw_mask & REDRAW_TILES)
460 redraw_mask |= REDRAW_FIELD;
464 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
465 /* (force full redraw) */
466 if (game_status == GAME_MODE_PLAYING)
467 redraw_mask |= REDRAW_FIELD;
470 if (redraw_mask & REDRAW_FIELD)
471 redraw_mask &= ~REDRAW_TILES;
473 if (redraw_mask == REDRAW_NONE)
478 if (redraw_mask & REDRAW_ALL)
479 printf("[REDRAW_ALL]");
480 if (redraw_mask & REDRAW_FIELD)
481 printf("[REDRAW_FIELD]");
482 if (redraw_mask & REDRAW_TILES)
483 printf("[REDRAW_TILES]");
484 if (redraw_mask & REDRAW_DOOR_1)
485 printf("[REDRAW_DOOR_1]");
486 if (redraw_mask & REDRAW_DOOR_2)
487 printf("[REDRAW_DOOR_2]");
488 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
489 printf("[REDRAW_FROM_BACKBUFFER]");
490 printf(" [%d]\n", FrameCounter);
493 if (redraw_mask & REDRAW_TILES &&
494 game_status == GAME_MODE_PLAYING &&
495 border.draw_masked[GAME_MODE_PLAYING])
496 redraw_mask |= REDRAW_FIELD;
498 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
500 static boolean last_frame_skipped = FALSE;
501 boolean skip_even_when_not_scrolling = TRUE;
502 boolean just_scrolling = (ScreenMovDir != 0);
503 boolean verbose = FALSE;
505 if (global.fps_slowdown_factor > 1 &&
506 (FrameCounter % global.fps_slowdown_factor) &&
507 (just_scrolling || skip_even_when_not_scrolling))
509 redraw_mask &= ~REDRAW_MAIN;
511 last_frame_skipped = TRUE;
514 printf("FRAME SKIPPED\n");
518 if (last_frame_skipped)
519 redraw_mask |= REDRAW_FIELD;
521 last_frame_skipped = FALSE;
524 printf("frame not skipped\n");
528 /* synchronize X11 graphics at this point; if we would synchronize the
529 display immediately after the buffer switching (after the XFlush),
530 this could mean that we have to wait for the graphics to complete,
531 although we could go on doing calculations for the next frame */
535 /* never draw masked border to backbuffer when using playfield buffer */
536 if (game_status != GAME_MODE_PLAYING ||
537 redraw_mask & REDRAW_FROM_BACKBUFFER ||
538 buffer == backbuffer)
539 DrawMaskedBorder(redraw_mask);
541 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
543 if (redraw_mask & REDRAW_ALL)
545 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
547 redraw_mask = REDRAW_NONE;
550 if (redraw_mask & REDRAW_FIELD)
552 if (game_status != GAME_MODE_PLAYING ||
553 redraw_mask & REDRAW_FROM_BACKBUFFER)
555 BlitBitmap(backbuffer, window,
556 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
560 BlitScreenToBitmap_RND(window);
563 redraw_mask &= ~REDRAW_MAIN;
566 if (redraw_mask & REDRAW_DOORS)
568 if (redraw_mask & REDRAW_DOOR_1)
569 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
571 if (redraw_mask & REDRAW_DOOR_2)
572 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
574 if (redraw_mask & REDRAW_DOOR_3)
575 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
577 redraw_mask &= ~REDRAW_DOORS;
580 if (redraw_mask & REDRAW_MICROLEVEL)
582 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
583 SX, SY + 10 * TILEY);
585 redraw_mask &= ~REDRAW_MICROLEVEL;
588 if (redraw_mask & REDRAW_TILES)
594 int dx_var = dx * TILESIZE_VAR / TILESIZE;
595 int dy_var = dy * TILESIZE_VAR / TILESIZE;
597 int fx = FX, fy = FY;
599 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
600 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
602 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
604 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
605 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
607 if (EVEN(SCR_FIELDX))
609 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
611 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
620 fx += (dx_var > 0 ? TILEX_VAR : 0);
624 if (EVEN(SCR_FIELDY))
626 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
628 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
637 fy += (dy_var > 0 ? TILEY_VAR : 0);
641 for (x = 0; x < scr_fieldx; x++)
642 for (y = 0 ; y < scr_fieldy; y++)
643 if (redraw[redraw_x1 + x][redraw_y1 + y])
644 BlitBitmap(buffer, window,
645 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
646 TILEX_VAR, TILEY_VAR,
647 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
649 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
652 if (redraw_mask & REDRAW_FPS) /* display frames per second */
657 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
658 if (!global.fps_slowdown)
661 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
663 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
666 for (x = 0; x < MAX_BUF_XSIZE; x++)
667 for (y = 0; y < MAX_BUF_YSIZE; y++)
670 redraw_mask = REDRAW_NONE;
673 static void FadeCrossSaveBackbuffer()
675 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
678 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
680 static int fade_type_skip = FADE_TYPE_NONE;
681 void (*draw_border_function)(void) = NULL;
682 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
683 int x, y, width, height;
684 int fade_delay, post_delay;
686 if (fade_type == FADE_TYPE_FADE_OUT)
688 if (fade_type_skip != FADE_TYPE_NONE)
690 /* skip all fade operations until specified fade operation */
691 if (fade_type & fade_type_skip)
692 fade_type_skip = FADE_TYPE_NONE;
697 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
699 FadeCrossSaveBackbuffer();
705 redraw_mask |= fade_mask;
707 if (fade_type == FADE_TYPE_SKIP)
709 fade_type_skip = fade_mode;
714 fade_delay = fading.fade_delay;
715 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
717 if (fade_type_skip != FADE_TYPE_NONE)
719 /* skip all fade operations until specified fade operation */
720 if (fade_type & fade_type_skip)
721 fade_type_skip = FADE_TYPE_NONE;
726 if (global.autoplay_leveldir)
731 if (fade_mask == REDRAW_FIELD)
736 height = FULL_SYSIZE;
738 if (border.draw_masked_when_fading)
739 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
741 DrawMaskedBorder_FIELD(); /* draw once */
743 else /* REDRAW_ALL */
751 if (!setup.fade_screens ||
753 fading.fade_mode == FADE_MODE_NONE)
755 if (fade_mode == FADE_MODE_FADE_OUT)
758 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
760 redraw_mask &= ~fade_mask;
765 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
766 draw_border_function);
768 redraw_mask &= ~fade_mask;
771 void FadeIn(int fade_mask)
773 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
774 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
776 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
779 void FadeOut(int fade_mask)
781 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
782 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
784 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
786 global.border_status = game_status;
789 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
791 static struct TitleFadingInfo fading_leave_stored;
794 fading_leave_stored = fading_leave;
796 fading = fading_leave_stored;
799 void FadeSetEnterMenu()
801 fading = menu.enter_menu;
803 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
806 void FadeSetLeaveMenu()
808 fading = menu.leave_menu;
810 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
813 void FadeSetEnterScreen()
815 fading = menu.enter_screen[game_status];
817 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
820 void FadeSetNextScreen()
822 fading = menu.next_screen;
824 // (do not overwrite fade mode set by FadeSetEnterScreen)
825 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
828 void FadeSetLeaveScreen()
830 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
833 void FadeSetFromType(int type)
835 if (type & TYPE_ENTER_SCREEN)
836 FadeSetEnterScreen();
837 else if (type & TYPE_ENTER)
839 else if (type & TYPE_LEAVE)
843 void FadeSetDisabled()
845 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
847 fading = fading_none;
850 void FadeSkipNextFadeIn()
852 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
855 void FadeSkipNextFadeOut()
857 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
860 void SetWindowBackgroundImageIfDefined(int graphic)
862 if (graphic_info[graphic].bitmap)
863 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
866 void SetMainBackgroundImageIfDefined(int graphic)
868 if (graphic_info[graphic].bitmap)
869 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
872 void SetDoorBackgroundImageIfDefined(int graphic)
874 if (graphic_info[graphic].bitmap)
875 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
878 void SetWindowBackgroundImage(int graphic)
880 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
881 graphic_info[graphic].bitmap ?
882 graphic_info[graphic].bitmap :
883 graphic_info[IMG_BACKGROUND].bitmap);
886 void SetMainBackgroundImage(int graphic)
888 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
889 graphic_info[graphic].bitmap ?
890 graphic_info[graphic].bitmap :
891 graphic_info[IMG_BACKGROUND].bitmap);
894 void SetDoorBackgroundImage(int graphic)
896 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
897 graphic_info[graphic].bitmap ?
898 graphic_info[graphic].bitmap :
899 graphic_info[IMG_BACKGROUND].bitmap);
902 void SetPanelBackground()
904 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
906 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
907 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
909 SetDoorBackgroundBitmap(bitmap_db_panel);
912 void DrawBackground(int x, int y, int width, int height)
914 /* "drawto" might still point to playfield buffer here (hall of fame) */
915 ClearRectangleOnBackground(backbuffer, x, y, width, height);
917 if (IN_GFX_FIELD_FULL(x, y))
918 redraw_mask |= REDRAW_FIELD;
919 else if (IN_GFX_DOOR_1(x, y))
920 redraw_mask |= REDRAW_DOOR_1;
921 else if (IN_GFX_DOOR_2(x, y))
922 redraw_mask |= REDRAW_DOOR_2;
923 else if (IN_GFX_DOOR_3(x, y))
924 redraw_mask |= REDRAW_DOOR_3;
927 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
929 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
931 if (font->bitmap == NULL)
934 DrawBackground(x, y, width, height);
937 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
939 struct GraphicInfo *g = &graphic_info[graphic];
941 if (g->bitmap == NULL)
944 DrawBackground(x, y, width, height);
949 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
950 /* (when entering hall of fame after playing) */
951 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
953 /* !!! maybe this should be done before clearing the background !!! */
954 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
956 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
957 SetDrawtoField(DRAW_BUFFERED);
960 SetDrawtoField(DRAW_BACKBUFFER);
963 void MarkTileDirty(int x, int y)
965 int xx = redraw_x1 + x;
966 int yy = redraw_y1 + y;
971 redraw[xx][yy] = TRUE;
972 redraw_mask |= REDRAW_TILES;
975 void SetBorderElement()
979 BorderElement = EL_EMPTY;
981 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
983 for (x = 0; x < lev_fieldx; x++)
985 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
986 BorderElement = EL_STEELWALL;
988 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
994 void FloodFillLevel(int from_x, int from_y, int fill_element,
995 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
996 int max_fieldx, int max_fieldy)
1000 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1001 static int safety = 0;
1003 /* check if starting field still has the desired content */
1004 if (field[from_x][from_y] == fill_element)
1009 if (safety > max_fieldx * max_fieldy)
1010 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1012 old_element = field[from_x][from_y];
1013 field[from_x][from_y] = fill_element;
1015 for (i = 0; i < 4; i++)
1017 x = from_x + check[i][0];
1018 y = from_y + check[i][1];
1020 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1021 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1027 void SetRandomAnimationValue(int x, int y)
1029 gfx.anim_random_frame = GfxRandom[x][y];
1032 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1034 /* animation synchronized with global frame counter, not move position */
1035 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1036 sync_frame = FrameCounter;
1038 return getAnimationFrame(graphic_info[graphic].anim_frames,
1039 graphic_info[graphic].anim_delay,
1040 graphic_info[graphic].anim_mode,
1041 graphic_info[graphic].anim_start_frame,
1045 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
1046 Bitmap **bitmap, int *x, int *y,
1047 boolean get_backside)
1049 struct GraphicInfo *g = &graphic_info[graphic];
1050 Bitmap *src_bitmap = g->bitmap;
1051 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1052 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1053 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
1055 if (tilesize == gfx.standard_tile_size)
1056 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1057 else if (tilesize == game.tile_size)
1058 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
1060 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1062 if (g->offset_y == 0) /* frames are ordered horizontally */
1064 int max_width = g->anim_frames_per_line * g->width;
1065 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1067 src_x = pos % max_width;
1068 src_y = src_y % g->height + pos / max_width * g->height;
1070 else if (g->offset_x == 0) /* frames are ordered vertically */
1072 int max_height = g->anim_frames_per_line * g->height;
1073 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1075 src_x = src_x % g->width + pos / max_height * g->width;
1076 src_y = pos % max_height;
1078 else /* frames are ordered diagonally */
1080 src_x = src_x + frame * g->offset_x;
1081 src_y = src_y + frame * g->offset_y;
1084 *bitmap = src_bitmap;
1085 *x = src_x * tilesize / TILESIZE;
1086 *y = src_y * tilesize / TILESIZE;
1089 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1090 int *x, int *y, boolean get_backside)
1092 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1096 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1097 Bitmap **bitmap, int *x, int *y)
1099 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1102 void getFixedGraphicSource(int graphic, int frame,
1103 Bitmap **bitmap, int *x, int *y)
1105 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1108 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1110 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1113 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1114 int *x, int *y, boolean get_backside)
1116 struct GraphicInfo *g = &graphic_info[graphic];
1117 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1118 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1120 if (TILESIZE_VAR != TILESIZE)
1121 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1124 *bitmap = g->bitmap;
1126 if (g->offset_y == 0) /* frames are ordered horizontally */
1128 int max_width = g->anim_frames_per_line * g->width;
1129 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1131 *x = pos % max_width;
1132 *y = src_y % g->height + pos / max_width * g->height;
1134 else if (g->offset_x == 0) /* frames are ordered vertically */
1136 int max_height = g->anim_frames_per_line * g->height;
1137 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1139 *x = src_x % g->width + pos / max_height * g->width;
1140 *y = pos % max_height;
1142 else /* frames are ordered diagonally */
1144 *x = src_x + frame * g->offset_x;
1145 *y = src_y + frame * g->offset_y;
1149 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1151 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1154 void DrawGraphic(int x, int y, int graphic, int frame)
1157 if (!IN_SCR_FIELD(x, y))
1159 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1160 printf("DrawGraphic(): This should never happen!\n");
1165 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1168 MarkTileDirty(x, y);
1171 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1174 if (!IN_SCR_FIELD(x, y))
1176 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1177 printf("DrawGraphic(): This should never happen!\n");
1182 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1184 MarkTileDirty(x, y);
1187 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1193 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1195 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1198 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1204 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1205 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1208 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1211 if (!IN_SCR_FIELD(x, y))
1213 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1214 printf("DrawGraphicThruMask(): This should never happen!\n");
1219 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1222 MarkTileDirty(x, y);
1225 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1228 if (!IN_SCR_FIELD(x, y))
1230 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1231 printf("DrawGraphicThruMask(): This should never happen!\n");
1236 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1238 MarkTileDirty(x, y);
1241 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1247 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1249 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1253 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1254 int graphic, int frame)
1256 struct GraphicInfo *g = &graphic_info[graphic];
1260 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1262 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1266 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1268 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1270 MarkTileDirty(x / tilesize, y / tilesize);
1273 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1279 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1280 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1283 void DrawMiniGraphic(int x, int y, int graphic)
1285 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1286 MarkTileDirty(x / 2, y / 2);
1289 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1294 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1295 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1298 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1299 int graphic, int frame,
1300 int cut_mode, int mask_mode)
1305 int width = TILEX, height = TILEY;
1308 if (dx || dy) /* shifted graphic */
1310 if (x < BX1) /* object enters playfield from the left */
1317 else if (x > BX2) /* object enters playfield from the right */
1323 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1329 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1331 else if (dx) /* general horizontal movement */
1332 MarkTileDirty(x + SIGN(dx), y);
1334 if (y < BY1) /* object enters playfield from the top */
1336 if (cut_mode==CUT_BELOW) /* object completely above top border */
1344 else if (y > BY2) /* object enters playfield from the bottom */
1350 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1356 else if (dy > 0 && cut_mode == CUT_ABOVE)
1358 if (y == BY2) /* object completely above bottom border */
1364 MarkTileDirty(x, y + 1);
1365 } /* object leaves playfield to the bottom */
1366 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1368 else if (dy) /* general vertical movement */
1369 MarkTileDirty(x, y + SIGN(dy));
1373 if (!IN_SCR_FIELD(x, y))
1375 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1376 printf("DrawGraphicShifted(): This should never happen!\n");
1381 width = width * TILESIZE_VAR / TILESIZE;
1382 height = height * TILESIZE_VAR / TILESIZE;
1383 cx = cx * TILESIZE_VAR / TILESIZE;
1384 cy = cy * TILESIZE_VAR / TILESIZE;
1385 dx = dx * TILESIZE_VAR / TILESIZE;
1386 dy = dy * TILESIZE_VAR / TILESIZE;
1388 if (width > 0 && height > 0)
1390 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1395 dst_x = FX + x * TILEX_VAR + dx;
1396 dst_y = FY + y * TILEY_VAR + dy;
1398 if (mask_mode == USE_MASKING)
1399 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1402 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1405 MarkTileDirty(x, y);
1409 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1410 int graphic, int frame,
1411 int cut_mode, int mask_mode)
1416 int width = TILEX_VAR, height = TILEY_VAR;
1419 int x2 = x + SIGN(dx);
1420 int y2 = y + SIGN(dy);
1422 /* movement with two-tile animations must be sync'ed with movement position,
1423 not with current GfxFrame (which can be higher when using slow movement) */
1424 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1425 int anim_frames = graphic_info[graphic].anim_frames;
1427 /* (we also need anim_delay here for movement animations with less frames) */
1428 int anim_delay = graphic_info[graphic].anim_delay;
1429 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1431 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1432 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1434 /* re-calculate animation frame for two-tile movement animation */
1435 frame = getGraphicAnimationFrame(graphic, sync_frame);
1437 /* check if movement start graphic inside screen area and should be drawn */
1438 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1440 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1442 dst_x = FX + x1 * TILEX_VAR;
1443 dst_y = FY + y1 * TILEY_VAR;
1445 if (mask_mode == USE_MASKING)
1446 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1449 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1452 MarkTileDirty(x1, y1);
1455 /* check if movement end graphic inside screen area and should be drawn */
1456 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1458 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1460 dst_x = FX + x2 * TILEX_VAR;
1461 dst_y = FY + y2 * TILEY_VAR;
1463 if (mask_mode == USE_MASKING)
1464 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1467 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1470 MarkTileDirty(x2, y2);
1474 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1475 int graphic, int frame,
1476 int cut_mode, int mask_mode)
1480 DrawGraphic(x, y, graphic, frame);
1485 if (graphic_info[graphic].double_movement) /* EM style movement images */
1486 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1488 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1491 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1492 int frame, int cut_mode)
1494 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1497 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1498 int cut_mode, int mask_mode)
1500 int lx = LEVELX(x), ly = LEVELY(y);
1504 if (IN_LEV_FIELD(lx, ly))
1506 SetRandomAnimationValue(lx, ly);
1508 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1509 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1511 /* do not use double (EM style) movement graphic when not moving */
1512 if (graphic_info[graphic].double_movement && !dx && !dy)
1514 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1515 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1518 else /* border element */
1520 graphic = el2img(element);
1521 frame = getGraphicAnimationFrame(graphic, -1);
1524 if (element == EL_EXPANDABLE_WALL)
1526 boolean left_stopped = FALSE, right_stopped = FALSE;
1528 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1529 left_stopped = TRUE;
1530 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1531 right_stopped = TRUE;
1533 if (left_stopped && right_stopped)
1535 else if (left_stopped)
1537 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1538 frame = graphic_info[graphic].anim_frames - 1;
1540 else if (right_stopped)
1542 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1543 frame = graphic_info[graphic].anim_frames - 1;
1548 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1549 else if (mask_mode == USE_MASKING)
1550 DrawGraphicThruMask(x, y, graphic, frame);
1552 DrawGraphic(x, y, graphic, frame);
1555 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1556 int cut_mode, int mask_mode)
1558 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1559 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1560 cut_mode, mask_mode);
1563 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1566 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1569 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1572 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1575 void DrawLevelElementThruMask(int x, int y, int element)
1577 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1580 void DrawLevelFieldThruMask(int x, int y)
1582 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1585 /* !!! implementation of quicksand is totally broken !!! */
1586 #define IS_CRUMBLED_TILE(x, y, e) \
1587 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1588 !IS_MOVING(x, y) || \
1589 (e) == EL_QUICKSAND_EMPTYING || \
1590 (e) == EL_QUICKSAND_FAST_EMPTYING))
1592 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1597 int width, height, cx, cy;
1598 int sx = SCREENX(x), sy = SCREENY(y);
1599 int crumbled_border_size = graphic_info[graphic].border_size;
1602 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1604 for (i = 1; i < 4; i++)
1606 int dxx = (i & 1 ? dx : 0);
1607 int dyy = (i & 2 ? dy : 0);
1610 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1613 /* check if neighbour field is of same crumble type */
1614 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1615 graphic_info[graphic].class ==
1616 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1618 /* return if check prevents inner corner */
1619 if (same == (dxx == dx && dyy == dy))
1623 /* if we reach this point, we have an inner corner */
1625 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1627 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1628 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1629 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1630 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1632 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1633 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1636 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1641 int width, height, bx, by, cx, cy;
1642 int sx = SCREENX(x), sy = SCREENY(y);
1643 int crumbled_border_size = graphic_info[graphic].border_size;
1644 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1645 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1648 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1650 /* draw simple, sloppy, non-corner-accurate crumbled border */
1652 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1653 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1654 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1655 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1657 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1658 FX + sx * TILEX_VAR + cx,
1659 FY + sy * TILEY_VAR + cy);
1661 /* (remaining middle border part must be at least as big as corner part) */
1662 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1663 crumbled_border_size >= TILESIZE / 3)
1666 /* correct corners of crumbled border, if needed */
1668 for (i = -1; i <= 1; i += 2)
1670 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1671 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1672 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1675 /* check if neighbour field is of same crumble type */
1676 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1677 graphic_info[graphic].class ==
1678 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1680 /* no crumbled corner, but continued crumbled border */
1682 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1683 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1684 int b1 = (i == 1 ? crumbled_border_size_var :
1685 TILESIZE_VAR - 2 * crumbled_border_size_var);
1687 width = crumbled_border_size_var;
1688 height = crumbled_border_size_var;
1690 if (dir == 1 || dir == 2)
1705 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1707 FX + sx * TILEX_VAR + cx,
1708 FY + sy * TILEY_VAR + cy);
1713 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1715 int sx = SCREENX(x), sy = SCREENY(y);
1718 static int xy[4][2] =
1726 if (!IN_LEV_FIELD(x, y))
1729 element = TILE_GFX_ELEMENT(x, y);
1731 /* crumble field itself */
1732 if (IS_CRUMBLED_TILE(x, y, element))
1734 if (!IN_SCR_FIELD(sx, sy))
1737 for (i = 0; i < 4; i++)
1739 int xx = x + xy[i][0];
1740 int yy = y + xy[i][1];
1742 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1745 /* check if neighbour field is of same crumble type */
1746 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1747 graphic_info[graphic].class ==
1748 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1751 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1754 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1755 graphic_info[graphic].anim_frames == 2)
1757 for (i = 0; i < 4; i++)
1759 int dx = (i & 1 ? +1 : -1);
1760 int dy = (i & 2 ? +1 : -1);
1762 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1766 MarkTileDirty(sx, sy);
1768 else /* center field not crumbled -- crumble neighbour fields */
1770 for (i = 0; i < 4; i++)
1772 int xx = x + xy[i][0];
1773 int yy = y + xy[i][1];
1774 int sxx = sx + xy[i][0];
1775 int syy = sy + xy[i][1];
1777 if (!IN_LEV_FIELD(xx, yy) ||
1778 !IN_SCR_FIELD(sxx, syy))
1781 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1784 element = TILE_GFX_ELEMENT(xx, yy);
1786 if (!IS_CRUMBLED_TILE(xx, yy, element))
1789 graphic = el_act2crm(element, ACTION_DEFAULT);
1791 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1793 MarkTileDirty(sxx, syy);
1798 void DrawLevelFieldCrumbled(int x, int y)
1802 if (!IN_LEV_FIELD(x, y))
1805 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1806 GfxElement[x][y] != EL_UNDEFINED &&
1807 GFX_CRUMBLED(GfxElement[x][y]))
1809 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1814 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1816 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1819 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1822 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1823 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1824 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1825 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1826 int sx = SCREENX(x), sy = SCREENY(y);
1828 DrawGraphic(sx, sy, graphic1, frame1);
1829 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1832 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1834 int sx = SCREENX(x), sy = SCREENY(y);
1835 static int xy[4][2] =
1844 for (i = 0; i < 4; i++)
1846 int xx = x + xy[i][0];
1847 int yy = y + xy[i][1];
1848 int sxx = sx + xy[i][0];
1849 int syy = sy + xy[i][1];
1851 if (!IN_LEV_FIELD(xx, yy) ||
1852 !IN_SCR_FIELD(sxx, syy) ||
1853 !GFX_CRUMBLED(Feld[xx][yy]) ||
1857 DrawLevelField(xx, yy);
1861 static int getBorderElement(int x, int y)
1865 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1866 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1867 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1868 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1869 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1870 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1871 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1873 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1874 int steel_position = (x == -1 && y == -1 ? 0 :
1875 x == lev_fieldx && y == -1 ? 1 :
1876 x == -1 && y == lev_fieldy ? 2 :
1877 x == lev_fieldx && y == lev_fieldy ? 3 :
1878 x == -1 || x == lev_fieldx ? 4 :
1879 y == -1 || y == lev_fieldy ? 5 : 6);
1881 return border[steel_position][steel_type];
1884 void DrawScreenElement(int x, int y, int element)
1886 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1887 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1890 void DrawLevelElement(int x, int y, int element)
1892 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1893 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1896 void DrawScreenField(int x, int y)
1898 int lx = LEVELX(x), ly = LEVELY(y);
1899 int element, content;
1901 if (!IN_LEV_FIELD(lx, ly))
1903 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1906 element = getBorderElement(lx, ly);
1908 DrawScreenElement(x, y, element);
1913 element = Feld[lx][ly];
1914 content = Store[lx][ly];
1916 if (IS_MOVING(lx, ly))
1918 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1919 boolean cut_mode = NO_CUTTING;
1921 if (element == EL_QUICKSAND_EMPTYING ||
1922 element == EL_QUICKSAND_FAST_EMPTYING ||
1923 element == EL_MAGIC_WALL_EMPTYING ||
1924 element == EL_BD_MAGIC_WALL_EMPTYING ||
1925 element == EL_DC_MAGIC_WALL_EMPTYING ||
1926 element == EL_AMOEBA_DROPPING)
1927 cut_mode = CUT_ABOVE;
1928 else if (element == EL_QUICKSAND_FILLING ||
1929 element == EL_QUICKSAND_FAST_FILLING ||
1930 element == EL_MAGIC_WALL_FILLING ||
1931 element == EL_BD_MAGIC_WALL_FILLING ||
1932 element == EL_DC_MAGIC_WALL_FILLING)
1933 cut_mode = CUT_BELOW;
1935 if (cut_mode == CUT_ABOVE)
1936 DrawScreenElement(x, y, element);
1938 DrawScreenElement(x, y, EL_EMPTY);
1941 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1942 else if (cut_mode == NO_CUTTING)
1943 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1946 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1948 if (cut_mode == CUT_BELOW &&
1949 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1950 DrawLevelElement(lx, ly + 1, element);
1953 if (content == EL_ACID)
1955 int dir = MovDir[lx][ly];
1956 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1957 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1959 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1962 else if (IS_BLOCKED(lx, ly))
1967 boolean cut_mode = NO_CUTTING;
1968 int element_old, content_old;
1970 Blocked2Moving(lx, ly, &oldx, &oldy);
1973 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1974 MovDir[oldx][oldy] == MV_RIGHT);
1976 element_old = Feld[oldx][oldy];
1977 content_old = Store[oldx][oldy];
1979 if (element_old == EL_QUICKSAND_EMPTYING ||
1980 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1981 element_old == EL_MAGIC_WALL_EMPTYING ||
1982 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1983 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1984 element_old == EL_AMOEBA_DROPPING)
1985 cut_mode = CUT_ABOVE;
1987 DrawScreenElement(x, y, EL_EMPTY);
1990 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1992 else if (cut_mode == NO_CUTTING)
1993 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1996 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1999 else if (IS_DRAWABLE(element))
2000 DrawScreenElement(x, y, element);
2002 DrawScreenElement(x, y, EL_EMPTY);
2005 void DrawLevelField(int x, int y)
2007 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2008 DrawScreenField(SCREENX(x), SCREENY(y));
2009 else if (IS_MOVING(x, y))
2013 Moving2Blocked(x, y, &newx, &newy);
2014 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2015 DrawScreenField(SCREENX(newx), SCREENY(newy));
2017 else if (IS_BLOCKED(x, y))
2021 Blocked2Moving(x, y, &oldx, &oldy);
2022 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2023 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2027 void DrawMiniElement(int x, int y, int element)
2031 graphic = el2edimg(element);
2032 DrawMiniGraphic(x, y, graphic);
2035 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2037 int x = sx + scroll_x, y = sy + scroll_y;
2039 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2040 DrawMiniElement(sx, sy, EL_EMPTY);
2041 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2042 DrawMiniElement(sx, sy, Feld[x][y]);
2044 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2047 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2048 int x, int y, int xsize, int ysize,
2049 int tile_width, int tile_height)
2053 int dst_x = startx + x * tile_width;
2054 int dst_y = starty + y * tile_height;
2055 int width = graphic_info[graphic].width;
2056 int height = graphic_info[graphic].height;
2057 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2058 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2059 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2060 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2061 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2062 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2063 boolean draw_masked = graphic_info[graphic].draw_masked;
2065 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2067 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2069 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2073 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2074 inner_sx + (x - 1) * tile_width % inner_width);
2075 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2076 inner_sy + (y - 1) * tile_height % inner_height);
2079 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2082 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2086 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2087 int x, int y, int xsize, int ysize, int font_nr)
2089 int font_width = getFontWidth(font_nr);
2090 int font_height = getFontHeight(font_nr);
2092 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2093 font_width, font_height);
2096 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2098 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2099 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2100 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2101 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2102 boolean no_delay = (tape.warp_forward);
2103 unsigned int anim_delay = 0;
2104 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2105 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2106 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2107 int font_width = getFontWidth(font_nr);
2108 int font_height = getFontHeight(font_nr);
2109 int max_xsize = level.envelope[envelope_nr].xsize;
2110 int max_ysize = level.envelope[envelope_nr].ysize;
2111 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2112 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2113 int xend = max_xsize;
2114 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2115 int xstep = (xstart < xend ? 1 : 0);
2116 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2119 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2121 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2122 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2123 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2124 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2127 SetDrawtoField(DRAW_BUFFERED);
2129 BlitScreenToBitmap(backbuffer);
2131 SetDrawtoField(DRAW_BACKBUFFER);
2133 for (yy = 0; yy < ysize; yy++)
2134 for (xx = 0; xx < xsize; xx++)
2135 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2137 DrawTextBuffer(sx + font_width, sy + font_height,
2138 level.envelope[envelope_nr].text, font_nr, max_xsize,
2139 xsize - 2, ysize - 2, 0, mask_mode,
2140 level.envelope[envelope_nr].autowrap,
2141 level.envelope[envelope_nr].centered, FALSE);
2143 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2146 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2150 void ShowEnvelope(int envelope_nr)
2152 int element = EL_ENVELOPE_1 + envelope_nr;
2153 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2154 int sound_opening = element_info[element].sound[ACTION_OPENING];
2155 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2156 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2157 boolean no_delay = (tape.warp_forward);
2158 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2159 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2160 int anim_mode = graphic_info[graphic].anim_mode;
2161 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2162 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2164 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2166 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2168 if (anim_mode == ANIM_DEFAULT)
2169 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2171 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2174 Delay(wait_delay_value);
2176 WaitForEventToContinue();
2178 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2180 if (anim_mode != ANIM_NONE)
2181 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2183 if (anim_mode == ANIM_DEFAULT)
2184 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2186 game.envelope_active = FALSE;
2188 SetDrawtoField(DRAW_BUFFERED);
2190 redraw_mask |= REDRAW_FIELD;
2194 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2196 int border_size = request.border_size;
2197 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2198 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2199 int sx = sx_center - request.width / 2;
2200 int sy = sy_center - request.height / 2;
2202 if (add_border_size)
2212 void DrawEnvelopeRequest(char *text)
2214 char *text_final = text;
2215 char *text_door_style = NULL;
2216 int graphic = IMG_BACKGROUND_REQUEST;
2217 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2218 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2219 int font_nr = FONT_REQUEST;
2220 int font_width = getFontWidth(font_nr);
2221 int font_height = getFontHeight(font_nr);
2222 int border_size = request.border_size;
2223 int line_spacing = request.line_spacing;
2224 int line_height = font_height + line_spacing;
2225 int text_width = request.width - 2 * border_size;
2226 int text_height = request.height - 2 * border_size;
2227 int line_length = text_width / font_width;
2228 int max_lines = text_height / line_height;
2229 int width = request.width;
2230 int height = request.height;
2231 int tile_size = request.step_offset;
2232 int x_steps = width / tile_size;
2233 int y_steps = height / tile_size;
2237 if (request.wrap_single_words)
2239 char *src_text_ptr, *dst_text_ptr;
2241 text_door_style = checked_malloc(2 * strlen(text) + 1);
2243 src_text_ptr = text;
2244 dst_text_ptr = text_door_style;
2246 while (*src_text_ptr)
2248 if (*src_text_ptr == ' ' ||
2249 *src_text_ptr == '?' ||
2250 *src_text_ptr == '!')
2251 *dst_text_ptr++ = '\n';
2253 if (*src_text_ptr != ' ')
2254 *dst_text_ptr++ = *src_text_ptr;
2259 *dst_text_ptr = '\0';
2261 text_final = text_door_style;
2264 setRequestPosition(&sx, &sy, FALSE);
2266 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2268 for (y = 0; y < y_steps; y++)
2269 for (x = 0; x < x_steps; x++)
2270 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2271 x, y, x_steps, y_steps,
2272 tile_size, tile_size);
2274 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2275 line_length, -1, max_lines, line_spacing, mask_mode,
2276 request.autowrap, request.centered, FALSE);
2278 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2279 RedrawGadget(tool_gadget[i]);
2281 // store readily prepared envelope request for later use when animating
2282 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2284 if (text_door_style)
2285 free(text_door_style);
2288 void AnimateEnvelopeRequest(int anim_mode, int action)
2290 int graphic = IMG_BACKGROUND_REQUEST;
2291 boolean draw_masked = graphic_info[graphic].draw_masked;
2292 int delay_value_normal = request.step_delay;
2293 int delay_value_fast = delay_value_normal / 2;
2294 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2295 boolean no_delay = (tape.warp_forward);
2296 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2297 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
2298 unsigned int anim_delay = 0;
2300 int width = request.width;
2301 int height = request.height;
2302 int tile_size = request.step_offset;
2303 int max_xsize = width / tile_size;
2304 int max_ysize = height / tile_size;
2305 int max_xsize_inner = max_xsize - 2;
2306 int max_ysize_inner = max_ysize - 2;
2308 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2309 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2310 int xend = max_xsize_inner;
2311 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2312 int xstep = (xstart < xend ? 1 : 0);
2313 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2316 if (setup.quick_doors)
2323 if (action == ACTION_OPENING)
2324 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2325 else if (action == ACTION_CLOSING)
2326 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2329 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2331 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2332 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2333 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2334 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2335 int src_x = sx_center - width / 2;
2336 int src_y = sy_center - height / 2;
2337 int dst_x = sx_center - xsize * tile_size / 2;
2338 int dst_y = sy_center - ysize * tile_size / 2;
2339 int xsize_size_left = (xsize - 1) * tile_size;
2340 int ysize_size_top = (ysize - 1) * tile_size;
2341 int max_xsize_pos = (max_xsize - 1) * tile_size;
2342 int max_ysize_pos = (max_ysize - 1) * tile_size;
2345 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2347 for (yy = 0; yy < 2; yy++)
2349 for (xx = 0; xx < 2; xx++)
2351 int src_xx = src_x + xx * max_xsize_pos;
2352 int src_yy = src_y + yy * max_ysize_pos;
2353 int dst_xx = dst_x + xx * xsize_size_left;
2354 int dst_yy = dst_y + yy * ysize_size_top;
2355 int xx_size = (xx ? tile_size : xsize_size_left);
2356 int yy_size = (yy ? tile_size : ysize_size_top);
2359 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2360 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2362 BlitBitmap(bitmap_db_cross, backbuffer,
2363 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2367 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2372 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2377 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2379 int last_game_status = game_status; /* save current game status */
2380 int graphic = IMG_BACKGROUND_REQUEST;
2381 int sound_opening = SND_REQUEST_OPENING;
2382 int sound_closing = SND_REQUEST_CLOSING;
2383 int anim_mode = graphic_info[graphic].anim_mode;
2384 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2385 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2387 if (game_status == GAME_MODE_PLAYING)
2388 BlitScreenToBitmap(backbuffer);
2390 SetDrawtoField(DRAW_BACKBUFFER);
2392 // SetDrawBackgroundMask(REDRAW_NONE);
2394 if (action == ACTION_OPENING)
2396 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2398 if (req_state & REQ_ASK)
2400 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2401 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2403 else if (req_state & REQ_CONFIRM)
2405 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2407 else if (req_state & REQ_PLAYER)
2409 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2410 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2411 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2412 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2415 DrawEnvelopeRequest(text);
2417 if (game_status != GAME_MODE_MAIN)
2421 /* force DOOR font inside door area */
2422 game_status = GAME_MODE_PSEUDO_DOOR;
2424 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2426 if (action == ACTION_OPENING)
2428 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2430 if (anim_mode == ANIM_DEFAULT)
2431 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2433 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2438 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2440 if (anim_mode != ANIM_NONE)
2441 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2443 if (anim_mode == ANIM_DEFAULT)
2444 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2447 game.envelope_active = FALSE;
2449 game_status = last_game_status; /* restore current game status */
2451 if (action == ACTION_CLOSING)
2453 if (game_status != GAME_MODE_MAIN)
2456 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2459 // SetDrawBackgroundMask(last_draw_background_mask);
2461 redraw_mask |= REDRAW_FIELD;
2463 if (game_status == GAME_MODE_MAIN)
2468 if (action == ACTION_CLOSING &&
2469 game_status == GAME_MODE_PLAYING &&
2470 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2471 SetDrawtoField(DRAW_BUFFERED);
2474 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2478 int graphic = el2preimg(element);
2480 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2481 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2484 void DrawLevel(int draw_background_mask)
2488 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2489 SetDrawBackgroundMask(draw_background_mask);
2493 for (x = BX1; x <= BX2; x++)
2494 for (y = BY1; y <= BY2; y++)
2495 DrawScreenField(x, y);
2497 redraw_mask |= REDRAW_FIELD;
2500 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2504 for (x = 0; x < size_x; x++)
2505 for (y = 0; y < size_y; y++)
2506 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2508 redraw_mask |= REDRAW_FIELD;
2511 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2513 boolean show_level_border = (BorderElement != EL_EMPTY);
2514 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2515 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2516 int tile_size = preview.tile_size;
2517 int preview_width = preview.xsize * tile_size;
2518 int preview_height = preview.ysize * tile_size;
2519 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2520 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2521 int real_preview_width = real_preview_xsize * tile_size;
2522 int real_preview_height = real_preview_ysize * tile_size;
2523 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2524 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2527 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2530 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2532 dst_x += (preview_width - real_preview_width) / 2;
2533 dst_y += (preview_height - real_preview_height) / 2;
2535 for (x = 0; x < real_preview_xsize; x++)
2537 for (y = 0; y < real_preview_ysize; y++)
2539 int lx = from_x + x + (show_level_border ? -1 : 0);
2540 int ly = from_y + y + (show_level_border ? -1 : 0);
2541 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2542 getBorderElement(lx, ly));
2544 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2545 element, tile_size);
2549 redraw_mask |= REDRAW_MICROLEVEL;
2552 #define MICROLABEL_EMPTY 0
2553 #define MICROLABEL_LEVEL_NAME 1
2554 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2555 #define MICROLABEL_LEVEL_AUTHOR 3
2556 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2557 #define MICROLABEL_IMPORTED_FROM 5
2558 #define MICROLABEL_IMPORTED_BY_HEAD 6
2559 #define MICROLABEL_IMPORTED_BY 7
2561 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2563 int max_text_width = SXSIZE;
2564 int font_width = getFontWidth(font_nr);
2566 if (pos->align == ALIGN_CENTER)
2567 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2568 else if (pos->align == ALIGN_RIGHT)
2569 max_text_width = pos->x;
2571 max_text_width = SXSIZE - pos->x;
2573 return max_text_width / font_width;
2576 static void DrawPreviewLevelLabelExt(int mode)
2578 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2579 char label_text[MAX_OUTPUT_LINESIZE + 1];
2580 int max_len_label_text;
2581 int font_nr = pos->font;
2584 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2587 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2588 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2589 mode == MICROLABEL_IMPORTED_BY_HEAD)
2590 font_nr = pos->font_alt;
2592 max_len_label_text = getMaxTextLength(pos, font_nr);
2594 if (pos->size != -1)
2595 max_len_label_text = pos->size;
2597 for (i = 0; i < max_len_label_text; i++)
2598 label_text[i] = ' ';
2599 label_text[max_len_label_text] = '\0';
2601 if (strlen(label_text) > 0)
2602 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2605 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2606 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2607 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2608 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2609 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2610 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2611 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2612 max_len_label_text);
2613 label_text[max_len_label_text] = '\0';
2615 if (strlen(label_text) > 0)
2616 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2618 redraw_mask |= REDRAW_MICROLEVEL;
2621 static void DrawPreviewLevelExt(boolean restart)
2623 static unsigned int scroll_delay = 0;
2624 static unsigned int label_delay = 0;
2625 static int from_x, from_y, scroll_direction;
2626 static int label_state, label_counter;
2627 unsigned int scroll_delay_value = preview.step_delay;
2628 boolean show_level_border = (BorderElement != EL_EMPTY);
2629 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2630 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2631 int last_game_status = game_status; /* save current game status */
2638 if (preview.anim_mode == ANIM_CENTERED)
2640 if (level_xsize > preview.xsize)
2641 from_x = (level_xsize - preview.xsize) / 2;
2642 if (level_ysize > preview.ysize)
2643 from_y = (level_ysize - preview.ysize) / 2;
2646 from_x += preview.xoffset;
2647 from_y += preview.yoffset;
2649 scroll_direction = MV_RIGHT;
2653 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2654 DrawPreviewLevelLabelExt(label_state);
2656 /* initialize delay counters */
2657 DelayReached(&scroll_delay, 0);
2658 DelayReached(&label_delay, 0);
2660 if (leveldir_current->name)
2662 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2663 char label_text[MAX_OUTPUT_LINESIZE + 1];
2664 int font_nr = pos->font;
2665 int max_len_label_text = getMaxTextLength(pos, font_nr);
2667 if (pos->size != -1)
2668 max_len_label_text = pos->size;
2670 strncpy(label_text, leveldir_current->name, max_len_label_text);
2671 label_text[max_len_label_text] = '\0';
2673 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2674 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2677 game_status = last_game_status; /* restore current game status */
2682 /* scroll preview level, if needed */
2683 if (preview.anim_mode != ANIM_NONE &&
2684 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2685 DelayReached(&scroll_delay, scroll_delay_value))
2687 switch (scroll_direction)
2692 from_x -= preview.step_offset;
2693 from_x = (from_x < 0 ? 0 : from_x);
2696 scroll_direction = MV_UP;
2700 if (from_x < level_xsize - preview.xsize)
2702 from_x += preview.step_offset;
2703 from_x = (from_x > level_xsize - preview.xsize ?
2704 level_xsize - preview.xsize : from_x);
2707 scroll_direction = MV_DOWN;
2713 from_y -= preview.step_offset;
2714 from_y = (from_y < 0 ? 0 : from_y);
2717 scroll_direction = MV_RIGHT;
2721 if (from_y < level_ysize - preview.ysize)
2723 from_y += preview.step_offset;
2724 from_y = (from_y > level_ysize - preview.ysize ?
2725 level_ysize - preview.ysize : from_y);
2728 scroll_direction = MV_LEFT;
2735 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2738 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2739 /* redraw micro level label, if needed */
2740 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2741 !strEqual(level.author, ANONYMOUS_NAME) &&
2742 !strEqual(level.author, leveldir_current->name) &&
2743 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2745 int max_label_counter = 23;
2747 if (leveldir_current->imported_from != NULL &&
2748 strlen(leveldir_current->imported_from) > 0)
2749 max_label_counter += 14;
2750 if (leveldir_current->imported_by != NULL &&
2751 strlen(leveldir_current->imported_by) > 0)
2752 max_label_counter += 14;
2754 label_counter = (label_counter + 1) % max_label_counter;
2755 label_state = (label_counter >= 0 && label_counter <= 7 ?
2756 MICROLABEL_LEVEL_NAME :
2757 label_counter >= 9 && label_counter <= 12 ?
2758 MICROLABEL_LEVEL_AUTHOR_HEAD :
2759 label_counter >= 14 && label_counter <= 21 ?
2760 MICROLABEL_LEVEL_AUTHOR :
2761 label_counter >= 23 && label_counter <= 26 ?
2762 MICROLABEL_IMPORTED_FROM_HEAD :
2763 label_counter >= 28 && label_counter <= 35 ?
2764 MICROLABEL_IMPORTED_FROM :
2765 label_counter >= 37 && label_counter <= 40 ?
2766 MICROLABEL_IMPORTED_BY_HEAD :
2767 label_counter >= 42 && label_counter <= 49 ?
2768 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2770 if (leveldir_current->imported_from == NULL &&
2771 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2772 label_state == MICROLABEL_IMPORTED_FROM))
2773 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2774 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2776 DrawPreviewLevelLabelExt(label_state);
2779 game_status = last_game_status; /* restore current game status */
2782 void DrawPreviewLevelInitial()
2784 DrawPreviewLevelExt(TRUE);
2787 void DrawPreviewLevelAnimation()
2789 DrawPreviewLevelExt(FALSE);
2792 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2793 int graphic, int sync_frame, int mask_mode)
2795 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2797 if (mask_mode == USE_MASKING)
2798 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2800 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2803 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2804 int graphic, int sync_frame,
2807 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2809 if (mask_mode == USE_MASKING)
2810 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2812 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2815 inline void DrawGraphicAnimation(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_VAR, FY + y * TILEY_VAR,
2823 graphic, GfxFrame[lx][ly], NO_MASKING);
2825 MarkTileDirty(x, y);
2828 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2830 int lx = LEVELX(x), ly = LEVELY(y);
2832 if (!IN_SCR_FIELD(x, y))
2835 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2836 graphic, GfxFrame[lx][ly], NO_MASKING);
2837 MarkTileDirty(x, y);
2840 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2842 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2845 void DrawLevelElementAnimation(int x, int y, int element)
2847 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2849 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2852 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2854 int sx = SCREENX(x), sy = SCREENY(y);
2856 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2859 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2862 DrawGraphicAnimation(sx, sy, graphic);
2865 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2866 DrawLevelFieldCrumbled(x, y);
2868 if (GFX_CRUMBLED(Feld[x][y]))
2869 DrawLevelFieldCrumbled(x, y);
2873 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2875 int sx = SCREENX(x), sy = SCREENY(y);
2878 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2881 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2883 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2886 DrawGraphicAnimation(sx, sy, graphic);
2888 if (GFX_CRUMBLED(element))
2889 DrawLevelFieldCrumbled(x, y);
2892 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2894 if (player->use_murphy)
2896 /* this works only because currently only one player can be "murphy" ... */
2897 static int last_horizontal_dir = MV_LEFT;
2898 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2900 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2901 last_horizontal_dir = move_dir;
2903 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2905 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2907 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2913 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2916 static boolean equalGraphics(int graphic1, int graphic2)
2918 struct GraphicInfo *g1 = &graphic_info[graphic1];
2919 struct GraphicInfo *g2 = &graphic_info[graphic2];
2921 return (g1->bitmap == g2->bitmap &&
2922 g1->src_x == g2->src_x &&
2923 g1->src_y == g2->src_y &&
2924 g1->anim_frames == g2->anim_frames &&
2925 g1->anim_delay == g2->anim_delay &&
2926 g1->anim_mode == g2->anim_mode);
2929 void DrawAllPlayers()
2933 for (i = 0; i < MAX_PLAYERS; i++)
2934 if (stored_player[i].active)
2935 DrawPlayer(&stored_player[i]);
2938 void DrawPlayerField(int x, int y)
2940 if (!IS_PLAYER(x, y))
2943 DrawPlayer(PLAYERINFO(x, y));
2946 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2948 void DrawPlayer(struct PlayerInfo *player)
2950 int jx = player->jx;
2951 int jy = player->jy;
2952 int move_dir = player->MovDir;
2953 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2954 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2955 int last_jx = (player->is_moving ? jx - dx : jx);
2956 int last_jy = (player->is_moving ? jy - dy : jy);
2957 int next_jx = jx + dx;
2958 int next_jy = jy + dy;
2959 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2960 boolean player_is_opaque = FALSE;
2961 int sx = SCREENX(jx), sy = SCREENY(jy);
2962 int sxx = 0, syy = 0;
2963 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2965 int action = ACTION_DEFAULT;
2966 int last_player_graphic = getPlayerGraphic(player, move_dir);
2967 int last_player_frame = player->Frame;
2970 /* GfxElement[][] is set to the element the player is digging or collecting;
2971 remove also for off-screen player if the player is not moving anymore */
2972 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2973 GfxElement[jx][jy] = EL_UNDEFINED;
2975 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2979 if (!IN_LEV_FIELD(jx, jy))
2981 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2982 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2983 printf("DrawPlayerField(): This should never happen!\n");
2988 if (element == EL_EXPLOSION)
2991 action = (player->is_pushing ? ACTION_PUSHING :
2992 player->is_digging ? ACTION_DIGGING :
2993 player->is_collecting ? ACTION_COLLECTING :
2994 player->is_moving ? ACTION_MOVING :
2995 player->is_snapping ? ACTION_SNAPPING :
2996 player->is_dropping ? ACTION_DROPPING :
2997 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2999 if (player->is_waiting)
3000 move_dir = player->dir_waiting;
3002 InitPlayerGfxAnimation(player, action, move_dir);
3004 /* ----------------------------------------------------------------------- */
3005 /* draw things in the field the player is leaving, if needed */
3006 /* ----------------------------------------------------------------------- */
3008 if (player->is_moving)
3010 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3012 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3014 if (last_element == EL_DYNAMITE_ACTIVE ||
3015 last_element == EL_EM_DYNAMITE_ACTIVE ||
3016 last_element == EL_SP_DISK_RED_ACTIVE)
3017 DrawDynamite(last_jx, last_jy);
3019 DrawLevelFieldThruMask(last_jx, last_jy);
3021 else if (last_element == EL_DYNAMITE_ACTIVE ||
3022 last_element == EL_EM_DYNAMITE_ACTIVE ||
3023 last_element == EL_SP_DISK_RED_ACTIVE)
3024 DrawDynamite(last_jx, last_jy);
3026 /* !!! this is not enough to prevent flickering of players which are
3027 moving next to each others without a free tile between them -- this
3028 can only be solved by drawing all players layer by layer (first the
3029 background, then the foreground etc.) !!! => TODO */
3030 else if (!IS_PLAYER(last_jx, last_jy))
3031 DrawLevelField(last_jx, last_jy);
3034 DrawLevelField(last_jx, last_jy);
3037 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3038 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3041 if (!IN_SCR_FIELD(sx, sy))
3044 /* ----------------------------------------------------------------------- */
3045 /* draw things behind the player, if needed */
3046 /* ----------------------------------------------------------------------- */
3049 DrawLevelElement(jx, jy, Back[jx][jy]);
3050 else if (IS_ACTIVE_BOMB(element))
3051 DrawLevelElement(jx, jy, EL_EMPTY);
3054 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3056 int old_element = GfxElement[jx][jy];
3057 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3058 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3060 if (GFX_CRUMBLED(old_element))
3061 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3063 DrawGraphic(sx, sy, old_graphic, frame);
3065 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3066 player_is_opaque = TRUE;
3070 GfxElement[jx][jy] = EL_UNDEFINED;
3072 /* make sure that pushed elements are drawn with correct frame rate */
3073 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3075 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3076 GfxFrame[jx][jy] = player->StepFrame;
3078 DrawLevelField(jx, jy);
3082 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3083 /* ----------------------------------------------------------------------- */
3084 /* draw player himself */
3085 /* ----------------------------------------------------------------------- */
3087 graphic = getPlayerGraphic(player, move_dir);
3089 /* in the case of changed player action or direction, prevent the current
3090 animation frame from being restarted for identical animations */
3091 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3092 player->Frame = last_player_frame;
3094 frame = getGraphicAnimationFrame(graphic, player->Frame);
3098 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3099 sxx = player->GfxPos;
3101 syy = player->GfxPos;
3104 if (!setup.soft_scrolling && ScreenMovPos)
3107 if (player_is_opaque)
3108 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3110 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3112 if (SHIELD_ON(player))
3114 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3115 IMG_SHIELD_NORMAL_ACTIVE);
3116 int frame = getGraphicAnimationFrame(graphic, -1);
3118 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3122 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3125 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3126 sxx = player->GfxPos;
3128 syy = player->GfxPos;
3132 /* ----------------------------------------------------------------------- */
3133 /* draw things the player is pushing, if needed */
3134 /* ----------------------------------------------------------------------- */
3136 if (player->is_pushing && player->is_moving)
3138 int px = SCREENX(jx), py = SCREENY(jy);
3139 int pxx = (TILEX - ABS(sxx)) * dx;
3140 int pyy = (TILEY - ABS(syy)) * dy;
3141 int gfx_frame = GfxFrame[jx][jy];
3147 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3149 element = Feld[next_jx][next_jy];
3150 gfx_frame = GfxFrame[next_jx][next_jy];
3153 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3155 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3156 frame = getGraphicAnimationFrame(graphic, sync_frame);
3158 /* draw background element under pushed element (like the Sokoban field) */
3159 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3161 /* this allows transparent pushing animation over non-black background */
3164 DrawLevelElement(jx, jy, Back[jx][jy]);
3166 DrawLevelElement(jx, jy, EL_EMPTY);
3168 if (Back[next_jx][next_jy])
3169 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3171 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3173 else if (Back[next_jx][next_jy])
3174 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3177 /* do not draw (EM style) pushing animation when pushing is finished */
3178 /* (two-tile animations usually do not contain start and end frame) */
3179 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3180 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3182 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3184 /* masked drawing is needed for EMC style (double) movement graphics */
3185 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3186 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3190 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3191 /* ----------------------------------------------------------------------- */
3192 /* draw player himself */
3193 /* ----------------------------------------------------------------------- */
3195 graphic = getPlayerGraphic(player, move_dir);
3197 /* in the case of changed player action or direction, prevent the current
3198 animation frame from being restarted for identical animations */
3199 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3200 player->Frame = last_player_frame;
3202 frame = getGraphicAnimationFrame(graphic, player->Frame);
3206 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3207 sxx = player->GfxPos;
3209 syy = player->GfxPos;
3212 if (!setup.soft_scrolling && ScreenMovPos)
3215 if (player_is_opaque)
3216 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3218 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3220 if (SHIELD_ON(player))
3222 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3223 IMG_SHIELD_NORMAL_ACTIVE);
3224 int frame = getGraphicAnimationFrame(graphic, -1);
3226 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3230 /* ----------------------------------------------------------------------- */
3231 /* draw things in front of player (active dynamite or dynabombs) */
3232 /* ----------------------------------------------------------------------- */
3234 if (IS_ACTIVE_BOMB(element))
3236 graphic = el2img(element);
3237 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3239 if (game.emulation == EMU_SUPAPLEX)
3240 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3242 DrawGraphicThruMask(sx, sy, graphic, frame);
3245 if (player_is_moving && last_element == EL_EXPLOSION)
3247 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3248 GfxElement[last_jx][last_jy] : EL_EMPTY);
3249 int graphic = el_act2img(element, ACTION_EXPLODING);
3250 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3251 int phase = ExplodePhase[last_jx][last_jy] - 1;
3252 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3255 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3258 /* ----------------------------------------------------------------------- */
3259 /* draw elements the player is just walking/passing through/under */
3260 /* ----------------------------------------------------------------------- */
3262 if (player_is_moving)
3264 /* handle the field the player is leaving ... */
3265 if (IS_ACCESSIBLE_INSIDE(last_element))
3266 DrawLevelField(last_jx, last_jy);
3267 else if (IS_ACCESSIBLE_UNDER(last_element))
3268 DrawLevelFieldThruMask(last_jx, last_jy);
3271 /* do not redraw accessible elements if the player is just pushing them */
3272 if (!player_is_moving || !player->is_pushing)
3274 /* ... and the field the player is entering */
3275 if (IS_ACCESSIBLE_INSIDE(element))
3276 DrawLevelField(jx, jy);
3277 else if (IS_ACCESSIBLE_UNDER(element))
3278 DrawLevelFieldThruMask(jx, jy);
3281 MarkTileDirty(sx, sy);
3284 /* ------------------------------------------------------------------------- */
3286 void WaitForEventToContinue()
3288 boolean still_wait = TRUE;
3290 /* simulate releasing mouse button over last gadget, if still pressed */
3292 HandleGadgets(-1, -1, 0);
3294 button_status = MB_RELEASED;
3308 case EVENT_BUTTONPRESS:
3309 case EVENT_KEYPRESS:
3313 case EVENT_KEYRELEASE:
3314 ClearPlayerAction();
3318 HandleOtherEvents(&event);
3322 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3329 /* don't eat all CPU time */
3334 #define MAX_REQUEST_LINES 13
3335 #define MAX_REQUEST_LINE_FONT1_LEN 7
3336 #define MAX_REQUEST_LINE_FONT2_LEN 10
3338 static int RequestHandleEvents(unsigned int req_state)
3340 int last_game_status = game_status; /* save current game status */
3344 button_status = MB_RELEASED;
3346 request_gadget_id = -1;
3359 case EVENT_BUTTONPRESS:
3360 case EVENT_BUTTONRELEASE:
3361 case EVENT_MOTIONNOTIFY:
3363 if (event.type == EVENT_MOTIONNOTIFY)
3365 if (!PointerInWindow(window))
3366 continue; /* window and pointer are on different screens */
3371 motion_status = TRUE;
3372 mx = ((MotionEvent *) &event)->x;
3373 my = ((MotionEvent *) &event)->y;
3377 motion_status = FALSE;
3378 mx = ((ButtonEvent *) &event)->x;
3379 my = ((ButtonEvent *) &event)->y;
3380 if (event.type == EVENT_BUTTONPRESS)
3381 button_status = ((ButtonEvent *) &event)->button;
3383 button_status = MB_RELEASED;
3386 /* this sets 'request_gadget_id' */
3387 HandleGadgets(mx, my, button_status);
3389 switch (request_gadget_id)
3391 case TOOL_CTRL_ID_YES:
3394 case TOOL_CTRL_ID_NO:
3397 case TOOL_CTRL_ID_CONFIRM:
3398 result = TRUE | FALSE;
3401 case TOOL_CTRL_ID_PLAYER_1:
3404 case TOOL_CTRL_ID_PLAYER_2:
3407 case TOOL_CTRL_ID_PLAYER_3:
3410 case TOOL_CTRL_ID_PLAYER_4:
3421 case EVENT_KEYPRESS:
3422 switch (GetEventKey((KeyEvent *)&event, TRUE))
3425 if (req_state & REQ_CONFIRM)
3430 #if defined(TARGET_SDL2)
3437 #if defined(TARGET_SDL2)
3447 if (req_state & REQ_PLAYER)
3451 case EVENT_KEYRELEASE:
3452 ClearPlayerAction();
3456 HandleOtherEvents(&event);
3460 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3462 int joy = AnyJoystick();
3464 if (joy & JOY_BUTTON_1)
3466 else if (joy & JOY_BUTTON_2)
3470 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3472 HandleGameActions();
3478 if (!PendingEvent()) /* delay only if no pending events */
3482 game_status = GAME_MODE_PSEUDO_DOOR;
3486 game_status = last_game_status; /* restore current game status */
3492 static boolean RequestDoor(char *text, unsigned int req_state)
3494 unsigned int old_door_state;
3495 int last_game_status = game_status; /* save current game status */
3496 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3497 int font_nr = FONT_TEXT_2;
3502 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3504 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3505 font_nr = FONT_TEXT_1;
3508 if (game_status == GAME_MODE_PLAYING)
3509 BlitScreenToBitmap(backbuffer);
3511 /* disable deactivated drawing when quick-loading level tape recording */
3512 if (tape.playing && tape.deactivate_display)
3513 TapeDeactivateDisplayOff(TRUE);
3515 SetMouseCursor(CURSOR_DEFAULT);
3517 #if defined(NETWORK_AVALIABLE)
3518 /* pause network game while waiting for request to answer */
3519 if (options.network &&
3520 game_status == GAME_MODE_PLAYING &&
3521 req_state & REQUEST_WAIT_FOR_INPUT)
3522 SendToServer_PausePlaying();
3525 old_door_state = GetDoorState();
3527 /* simulate releasing mouse button over last gadget, if still pressed */
3529 HandleGadgets(-1, -1, 0);
3533 /* draw released gadget before proceeding */
3536 if (old_door_state & DOOR_OPEN_1)
3538 CloseDoor(DOOR_CLOSE_1);
3540 /* save old door content */
3541 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3542 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3545 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3546 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3548 /* clear door drawing field */
3549 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3551 /* force DOOR font inside door area */
3552 game_status = GAME_MODE_PSEUDO_DOOR;
3554 /* write text for request */
3555 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3557 char text_line[max_request_line_len + 1];
3563 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3565 tc = *(text_ptr + tx);
3566 // if (!tc || tc == ' ')
3567 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3571 if ((tc == '?' || tc == '!') && tl == 0)
3581 strncpy(text_line, text_ptr, tl);
3584 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3585 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3586 text_line, font_nr);
3588 text_ptr += tl + (tc == ' ' ? 1 : 0);
3589 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3592 game_status = last_game_status; /* restore current game status */
3594 if (req_state & REQ_ASK)
3596 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3597 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3599 else if (req_state & REQ_CONFIRM)
3601 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3603 else if (req_state & REQ_PLAYER)
3605 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3606 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3607 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3608 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3611 /* copy request gadgets to door backbuffer */
3612 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3614 OpenDoor(DOOR_OPEN_1);
3616 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3618 if (game_status == GAME_MODE_PLAYING)
3620 SetPanelBackground();
3621 SetDrawBackgroundMask(REDRAW_DOOR_1);
3625 SetDrawBackgroundMask(REDRAW_FIELD);
3631 if (game_status != GAME_MODE_MAIN)
3634 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3636 // ---------- handle request buttons ----------
3637 result = RequestHandleEvents(req_state);
3639 if (game_status != GAME_MODE_MAIN)
3644 if (!(req_state & REQ_STAY_OPEN))
3646 CloseDoor(DOOR_CLOSE_1);
3648 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3649 (req_state & REQ_REOPEN))
3650 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3655 if (game_status == GAME_MODE_PLAYING)
3657 SetPanelBackground();
3658 SetDrawBackgroundMask(REDRAW_DOOR_1);
3662 SetDrawBackgroundMask(REDRAW_FIELD);
3665 #if defined(NETWORK_AVALIABLE)
3666 /* continue network game after request */
3667 if (options.network &&
3668 game_status == GAME_MODE_PLAYING &&
3669 req_state & REQUEST_WAIT_FOR_INPUT)
3670 SendToServer_ContinuePlaying();
3673 /* restore deactivated drawing when quick-loading level tape recording */
3674 if (tape.playing && tape.deactivate_display)
3675 TapeDeactivateDisplayOn();
3680 static boolean RequestEnvelope(char *text, unsigned int req_state)
3684 if (game_status == GAME_MODE_PLAYING)
3685 BlitScreenToBitmap(backbuffer);
3687 /* disable deactivated drawing when quick-loading level tape recording */
3688 if (tape.playing && tape.deactivate_display)
3689 TapeDeactivateDisplayOff(TRUE);
3691 SetMouseCursor(CURSOR_DEFAULT);
3693 #if defined(NETWORK_AVALIABLE)
3694 /* pause network game while waiting for request to answer */
3695 if (options.network &&
3696 game_status == GAME_MODE_PLAYING &&
3697 req_state & REQUEST_WAIT_FOR_INPUT)
3698 SendToServer_PausePlaying();
3701 /* simulate releasing mouse button over last gadget, if still pressed */
3703 HandleGadgets(-1, -1, 0);
3707 // (replace with setting corresponding request background)
3708 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3709 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3711 /* clear door drawing field */
3712 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3714 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3716 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3718 if (game_status == GAME_MODE_PLAYING)
3720 SetPanelBackground();
3721 SetDrawBackgroundMask(REDRAW_DOOR_1);
3725 SetDrawBackgroundMask(REDRAW_FIELD);
3731 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3733 // ---------- handle request buttons ----------
3734 result = RequestHandleEvents(req_state);
3736 if (game_status != GAME_MODE_MAIN)
3741 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3745 if (game_status == GAME_MODE_PLAYING)
3747 SetPanelBackground();
3748 SetDrawBackgroundMask(REDRAW_DOOR_1);
3752 SetDrawBackgroundMask(REDRAW_FIELD);
3755 #if defined(NETWORK_AVALIABLE)
3756 /* continue network game after request */
3757 if (options.network &&
3758 game_status == GAME_MODE_PLAYING &&
3759 req_state & REQUEST_WAIT_FOR_INPUT)
3760 SendToServer_ContinuePlaying();
3763 /* restore deactivated drawing when quick-loading level tape recording */
3764 if (tape.playing && tape.deactivate_display)
3765 TapeDeactivateDisplayOn();
3770 boolean Request(char *text, unsigned int req_state)
3772 if (global.use_envelope_request)
3773 return RequestEnvelope(text, req_state);
3775 return RequestDoor(text, req_state);
3778 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3780 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3781 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3784 if (dpo1->sort_priority != dpo2->sort_priority)
3785 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3787 compare_result = dpo1->nr - dpo2->nr;
3789 return compare_result;
3792 void InitGraphicCompatibilityInfo_Doors()
3798 struct DoorInfo *door;
3802 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3803 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3805 { -1, -1, -1, NULL }
3807 struct Rect door_rect_list[] =
3809 { DX, DY, DXSIZE, DYSIZE },
3810 { VX, VY, VXSIZE, VYSIZE }
3814 for (i = 0; doors[i].door_token != -1; i++)
3816 int door_token = doors[i].door_token;
3817 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3818 int part_1 = doors[i].part_1;
3819 int part_8 = doors[i].part_8;
3820 int part_2 = part_1 + 1;
3821 int part_3 = part_1 + 2;
3822 struct DoorInfo *door = doors[i].door;
3823 struct Rect *door_rect = &door_rect_list[door_index];
3824 boolean door_gfx_redefined = FALSE;
3826 /* check if any door part graphic definitions have been redefined */
3828 for (j = 0; door_part_controls[j].door_token != -1; j++)
3830 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3831 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3833 if (dpc->door_token == door_token && fi->redefined)
3834 door_gfx_redefined = TRUE;
3837 /* check for old-style door graphic/animation modifications */
3839 if (!door_gfx_redefined)
3841 if (door->anim_mode & ANIM_STATIC_PANEL)
3843 door->panel.step_xoffset = 0;
3844 door->panel.step_yoffset = 0;
3847 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3849 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3850 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3851 int num_door_steps, num_panel_steps;
3853 /* remove door part graphics other than the two default wings */
3855 for (j = 0; door_part_controls[j].door_token != -1; j++)
3857 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3858 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3860 if (dpc->graphic >= part_3 &&
3861 dpc->graphic <= part_8)
3865 /* set graphics and screen positions of the default wings */
3867 g_part_1->width = door_rect->width;
3868 g_part_1->height = door_rect->height;
3869 g_part_2->width = door_rect->width;
3870 g_part_2->height = door_rect->height;
3871 g_part_2->src_x = door_rect->width;
3872 g_part_2->src_y = g_part_1->src_y;
3874 door->part_2.x = door->part_1.x;
3875 door->part_2.y = door->part_1.y;
3877 if (door->width != -1)
3879 g_part_1->width = door->width;
3880 g_part_2->width = door->width;
3882 // special treatment for graphics and screen position of right wing
3883 g_part_2->src_x += door_rect->width - door->width;
3884 door->part_2.x += door_rect->width - door->width;
3887 if (door->height != -1)
3889 g_part_1->height = door->height;
3890 g_part_2->height = door->height;
3892 // special treatment for graphics and screen position of bottom wing
3893 g_part_2->src_y += door_rect->height - door->height;
3894 door->part_2.y += door_rect->height - door->height;
3897 /* set animation delays for the default wings and panels */
3899 door->part_1.step_delay = door->step_delay;
3900 door->part_2.step_delay = door->step_delay;
3901 door->panel.step_delay = door->step_delay;
3903 /* set animation draw order for the default wings */
3905 door->part_1.sort_priority = 2; /* draw left wing over ... */
3906 door->part_2.sort_priority = 1; /* ... right wing */
3908 /* set animation draw offset for the default wings */
3910 if (door->anim_mode & ANIM_HORIZONTAL)
3912 door->part_1.step_xoffset = door->step_offset;
3913 door->part_1.step_yoffset = 0;
3914 door->part_2.step_xoffset = door->step_offset * -1;
3915 door->part_2.step_yoffset = 0;
3917 num_door_steps = g_part_1->width / door->step_offset;
3919 else // ANIM_VERTICAL
3921 door->part_1.step_xoffset = 0;
3922 door->part_1.step_yoffset = door->step_offset;
3923 door->part_2.step_xoffset = 0;
3924 door->part_2.step_yoffset = door->step_offset * -1;
3926 num_door_steps = g_part_1->height / door->step_offset;
3929 /* set animation draw offset for the default panels */
3931 if (door->step_offset > 1)
3933 num_panel_steps = 2 * door_rect->height / door->step_offset;
3934 door->panel.start_step = num_panel_steps - num_door_steps;
3938 num_panel_steps = door_rect->height / door->step_offset;
3939 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3940 door->panel.step_delay *= 2;
3951 for (i = 0; door_part_controls[i].door_token != -1; i++)
3953 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3954 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3956 /* initialize "start_step_opening" and "start_step_closing", if needed */
3957 if (dpc->pos->start_step_opening == 0 &&
3958 dpc->pos->start_step_closing == 0)
3960 // dpc->pos->start_step_opening = dpc->pos->start_step;
3961 dpc->pos->start_step_closing = dpc->pos->start_step;
3964 /* fill structure for door part draw order (sorted below) */
3966 dpo->sort_priority = dpc->pos->sort_priority;
3969 /* sort door part controls according to sort_priority and graphic number */
3970 qsort(door_part_order, MAX_DOOR_PARTS,
3971 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3974 unsigned int OpenDoor(unsigned int door_state)
3976 if (door_state & DOOR_COPY_BACK)
3978 if (door_state & DOOR_OPEN_1)
3979 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3980 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3982 if (door_state & DOOR_OPEN_2)
3983 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3984 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3986 door_state &= ~DOOR_COPY_BACK;
3989 return MoveDoor(door_state);
3992 unsigned int CloseDoor(unsigned int door_state)
3994 unsigned int old_door_state = GetDoorState();
3996 if (!(door_state & DOOR_NO_COPY_BACK))
3998 if (old_door_state & DOOR_OPEN_1)
3999 BlitBitmap(backbuffer, bitmap_db_door_1,
4000 DX, DY, DXSIZE, DYSIZE, 0, 0);
4002 if (old_door_state & DOOR_OPEN_2)
4003 BlitBitmap(backbuffer, bitmap_db_door_2,
4004 VX, VY, VXSIZE, VYSIZE, 0, 0);
4006 door_state &= ~DOOR_NO_COPY_BACK;
4009 return MoveDoor(door_state);
4012 unsigned int GetDoorState()
4014 return MoveDoor(DOOR_GET_STATE);
4017 unsigned int SetDoorState(unsigned int door_state)
4019 return MoveDoor(door_state | DOOR_SET_STATE);
4022 int euclid(int a, int b)
4024 return (b ? euclid(b, a % b) : a);
4027 unsigned int MoveDoor(unsigned int door_state)
4029 struct Rect door_rect_list[] =
4031 { DX, DY, DXSIZE, DYSIZE },
4032 { VX, VY, VXSIZE, VYSIZE }
4034 static int door1 = DOOR_OPEN_1;
4035 static int door2 = DOOR_CLOSE_2;
4036 unsigned int door_delay = 0;
4037 unsigned int door_delay_value;
4040 if (door_1.width < 0 || door_1.width > DXSIZE)
4041 door_1.width = DXSIZE;
4042 if (door_1.height < 0 || door_1.height > DYSIZE)
4043 door_1.height = DYSIZE;
4044 if (door_2.width < 0 || door_2.width > VXSIZE)
4045 door_2.width = VXSIZE;
4046 if (door_2.height < 0 || door_2.height > VYSIZE)
4047 door_2.height = VYSIZE;
4049 if (door_state == DOOR_GET_STATE)
4050 return (door1 | door2);
4052 if (door_state & DOOR_SET_STATE)
4054 if (door_state & DOOR_ACTION_1)
4055 door1 = door_state & DOOR_ACTION_1;
4056 if (door_state & DOOR_ACTION_2)
4057 door2 = door_state & DOOR_ACTION_2;
4059 return (door1 | door2);
4062 if (!(door_state & DOOR_FORCE_REDRAW))
4064 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4065 door_state &= ~DOOR_OPEN_1;
4066 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4067 door_state &= ~DOOR_CLOSE_1;
4068 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4069 door_state &= ~DOOR_OPEN_2;
4070 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4071 door_state &= ~DOOR_CLOSE_2;
4074 if (global.autoplay_leveldir)
4076 door_state |= DOOR_NO_DELAY;
4077 door_state &= ~DOOR_CLOSE_ALL;
4080 if (game_status == GAME_MODE_EDITOR)
4081 door_state |= DOOR_NO_DELAY;
4083 if (door_state & DOOR_ACTION)
4085 boolean door_panel_drawn[NUM_DOORS];
4086 boolean panel_has_doors[NUM_DOORS];
4087 boolean door_part_skip[MAX_DOOR_PARTS];
4088 boolean door_part_done[MAX_DOOR_PARTS];
4089 boolean door_part_done_all;
4090 int num_steps[MAX_DOOR_PARTS];
4091 int max_move_delay = 0; // delay for complete animations of all doors
4092 int max_step_delay = 0; // delay (ms) between two animation frames
4093 int num_move_steps = 0; // number of animation steps for all doors
4094 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4095 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4096 int current_move_delay = 0;
4100 for (i = 0; i < NUM_DOORS; i++)
4101 panel_has_doors[i] = FALSE;
4103 for (i = 0; i < MAX_DOOR_PARTS; i++)
4105 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4106 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4107 int door_token = dpc->door_token;
4109 door_part_done[i] = FALSE;
4110 door_part_skip[i] = (!(door_state & door_token) ||
4114 for (i = 0; i < MAX_DOOR_PARTS; i++)
4116 int nr = door_part_order[i].nr;
4117 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4118 struct DoorPartPosInfo *pos = dpc->pos;
4119 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4120 int door_token = dpc->door_token;
4121 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4122 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4123 int step_xoffset = ABS(pos->step_xoffset);
4124 int step_yoffset = ABS(pos->step_yoffset);
4125 int step_delay = pos->step_delay;
4126 int current_door_state = door_state & door_token;
4127 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4128 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4129 boolean part_opening = (is_panel ? door_closing : door_opening);
4130 int start_step = (part_opening ? pos->start_step_opening :
4131 pos->start_step_closing);
4132 float move_xsize = (step_xoffset ? g->width : 0);
4133 float move_ysize = (step_yoffset ? g->height : 0);
4134 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4135 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4136 int move_steps = (move_xsteps && move_ysteps ?
4137 MIN(move_xsteps, move_ysteps) :
4138 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4139 int move_delay = move_steps * step_delay;
4141 if (door_part_skip[nr])
4144 max_move_delay = MAX(max_move_delay, move_delay);
4145 max_step_delay = (max_step_delay == 0 ? step_delay :
4146 euclid(max_step_delay, step_delay));
4147 num_steps[nr] = move_steps;
4151 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4153 panel_has_doors[door_index] = TRUE;
4157 num_move_steps = max_move_delay / max_step_delay;
4158 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4160 door_delay_value = max_step_delay;
4162 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4164 start = num_move_steps - 1;
4168 /* opening door sound has priority over simultaneously closing door */
4169 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4170 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4171 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4172 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4175 for (k = start; k < num_move_steps; k++)
4177 door_part_done_all = TRUE;
4179 for (i = 0; i < NUM_DOORS; i++)
4180 door_panel_drawn[i] = FALSE;
4182 for (i = 0; i < MAX_DOOR_PARTS; i++)
4184 int nr = door_part_order[i].nr;
4185 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4186 struct DoorPartPosInfo *pos = dpc->pos;
4187 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4188 int door_token = dpc->door_token;
4189 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4190 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4191 boolean is_panel_and_door_has_closed = FALSE;
4192 struct Rect *door_rect = &door_rect_list[door_index];
4193 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4195 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4196 int current_door_state = door_state & door_token;
4197 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4198 boolean door_closing = !door_opening;
4199 boolean part_opening = (is_panel ? door_closing : door_opening);
4200 boolean part_closing = !part_opening;
4201 int start_step = (part_opening ? pos->start_step_opening :
4202 pos->start_step_closing);
4203 int step_delay = pos->step_delay;
4204 int step_factor = step_delay / max_step_delay;
4205 int k1 = (step_factor ? k / step_factor + 1 : k);
4206 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4207 int kk = MAX(0, k2);
4210 int src_x, src_y, src_xx, src_yy;
4211 int dst_x, dst_y, dst_xx, dst_yy;
4214 if (door_part_skip[nr])
4217 if (!(door_state & door_token))
4225 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4226 int kk_door = MAX(0, k2_door);
4227 int sync_frame = kk_door * door_delay_value;
4228 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4230 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4235 if (!door_panel_drawn[door_index])
4237 ClearRectangle(drawto, door_rect->x, door_rect->y,
4238 door_rect->width, door_rect->height);
4240 door_panel_drawn[door_index] = TRUE;
4243 // draw opening or closing door parts
4245 if (pos->step_xoffset < 0) // door part on right side
4248 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4251 if (dst_xx + width > door_rect->width)
4252 width = door_rect->width - dst_xx;
4254 else // door part on left side
4257 dst_xx = pos->x - kk * pos->step_xoffset;
4261 src_xx = ABS(dst_xx);
4265 width = g->width - src_xx;
4267 // printf("::: k == %d [%d] \n", k, start_step);
4270 if (pos->step_yoffset < 0) // door part on bottom side
4273 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4276 if (dst_yy + height > door_rect->height)
4277 height = door_rect->height - dst_yy;
4279 else // door part on top side
4282 dst_yy = pos->y - kk * pos->step_yoffset;
4286 src_yy = ABS(dst_yy);
4290 height = g->height - src_yy;
4293 src_x = g_src_x + src_xx;
4294 src_y = g_src_y + src_yy;
4296 dst_x = door_rect->x + dst_xx;
4297 dst_y = door_rect->y + dst_yy;
4299 is_panel_and_door_has_closed =
4302 panel_has_doors[door_index] &&
4303 k >= num_move_steps_doors_only - 1);
4305 if (width >= 0 && width <= g->width &&
4306 height >= 0 && height <= g->height &&
4307 !is_panel_and_door_has_closed)
4309 if (is_panel || !pos->draw_masked)
4310 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4313 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4317 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4319 if ((part_opening && (width < 0 || height < 0)) ||
4320 (part_closing && (width >= g->width && height >= g->height)))
4321 door_part_done[nr] = TRUE;
4323 // continue door part animations, but not panel after door has closed
4324 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4325 door_part_done_all = FALSE;
4328 if (!(door_state & DOOR_NO_DELAY))
4332 if (game_status == GAME_MODE_MAIN)
4335 WaitUntilDelayReached(&door_delay, door_delay_value);
4337 current_move_delay += max_step_delay;
4340 if (door_part_done_all)
4345 if (door_state & DOOR_ACTION_1)
4346 door1 = door_state & DOOR_ACTION_1;
4347 if (door_state & DOOR_ACTION_2)
4348 door2 = door_state & DOOR_ACTION_2;
4350 return (door1 | door2);
4353 void DrawSpecialEditorDoor()
4355 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4356 int top_border_width = gfx1->width;
4357 int top_border_height = gfx1->height;
4358 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4359 int ex = EX - outer_border;
4360 int ey = EY - outer_border;
4361 int vy = VY - outer_border;
4362 int exsize = EXSIZE + 2 * outer_border;
4364 CloseDoor(DOOR_CLOSE_2);
4366 /* draw bigger level editor toolbox window */
4367 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4368 top_border_width, top_border_height, ex, ey - top_border_height);
4369 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4370 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4372 redraw_mask |= REDRAW_ALL;
4375 void UndrawSpecialEditorDoor()
4377 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4378 int top_border_width = gfx1->width;
4379 int top_border_height = gfx1->height;
4380 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4381 int ex = EX - outer_border;
4382 int ey = EY - outer_border;
4383 int ey_top = ey - top_border_height;
4384 int exsize = EXSIZE + 2 * outer_border;
4385 int eysize = EYSIZE + 2 * outer_border;
4387 /* draw normal tape recorder window */
4388 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4390 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4391 ex, ey_top, top_border_width, top_border_height,
4393 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4394 ex, ey, exsize, eysize, ex, ey);
4398 // if screen background is set to "[NONE]", clear editor toolbox window
4399 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4400 ClearRectangle(drawto, ex, ey, exsize, eysize);
4403 redraw_mask |= REDRAW_ALL;
4407 /* ---------- new tool button stuff ---------------------------------------- */
4412 struct TextPosInfo *pos;
4415 } toolbutton_info[NUM_TOOL_BUTTONS] =
4418 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4419 TOOL_CTRL_ID_YES, "yes"
4422 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4423 TOOL_CTRL_ID_NO, "no"
4426 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4427 TOOL_CTRL_ID_CONFIRM, "confirm"
4430 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4431 TOOL_CTRL_ID_PLAYER_1, "player 1"
4434 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4435 TOOL_CTRL_ID_PLAYER_2, "player 2"
4438 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4439 TOOL_CTRL_ID_PLAYER_3, "player 3"
4442 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4443 TOOL_CTRL_ID_PLAYER_4, "player 4"
4447 void CreateToolButtons()
4451 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4453 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4454 struct TextPosInfo *pos = toolbutton_info[i].pos;
4455 struct GadgetInfo *gi;
4456 Bitmap *deco_bitmap = None;
4457 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4458 unsigned int event_mask = GD_EVENT_RELEASED;
4461 int gd_x = gfx->src_x;
4462 int gd_y = gfx->src_y;
4463 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4464 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4467 if (global.use_envelope_request)
4468 setRequestPosition(&dx, &dy, TRUE);
4470 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4472 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4474 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4475 pos->size, &deco_bitmap, &deco_x, &deco_y);
4476 deco_xpos = (gfx->width - pos->size) / 2;
4477 deco_ypos = (gfx->height - pos->size) / 2;
4480 gi = CreateGadget(GDI_CUSTOM_ID, id,
4481 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4482 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4483 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4484 GDI_WIDTH, gfx->width,
4485 GDI_HEIGHT, gfx->height,
4486 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4487 GDI_STATE, GD_BUTTON_UNPRESSED,
4488 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4489 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4490 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4491 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4492 GDI_DECORATION_SIZE, pos->size, pos->size,
4493 GDI_DECORATION_SHIFTING, 1, 1,
4494 GDI_DIRECT_DRAW, FALSE,
4495 GDI_EVENT_MASK, event_mask,
4496 GDI_CALLBACK_ACTION, HandleToolButtons,
4500 Error(ERR_EXIT, "cannot create gadget");
4502 tool_gadget[id] = gi;
4506 void FreeToolButtons()
4510 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4511 FreeGadget(tool_gadget[i]);
4514 static void UnmapToolButtons()
4518 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4519 UnmapGadget(tool_gadget[i]);
4522 static void HandleToolButtons(struct GadgetInfo *gi)
4524 request_gadget_id = gi->custom_id;
4527 static struct Mapping_EM_to_RND_object
4530 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4531 boolean is_backside; /* backside of moving element */
4537 em_object_mapping_list[] =
4540 Xblank, TRUE, FALSE,
4544 Yacid_splash_eB, FALSE, FALSE,
4545 EL_ACID_SPLASH_RIGHT, -1, -1
4548 Yacid_splash_wB, FALSE, FALSE,
4549 EL_ACID_SPLASH_LEFT, -1, -1
4552 #ifdef EM_ENGINE_BAD_ROLL
4554 Xstone_force_e, FALSE, FALSE,
4555 EL_ROCK, -1, MV_BIT_RIGHT
4558 Xstone_force_w, FALSE, FALSE,
4559 EL_ROCK, -1, MV_BIT_LEFT
4562 Xnut_force_e, FALSE, FALSE,
4563 EL_NUT, -1, MV_BIT_RIGHT
4566 Xnut_force_w, FALSE, FALSE,
4567 EL_NUT, -1, MV_BIT_LEFT
4570 Xspring_force_e, FALSE, FALSE,
4571 EL_SPRING, -1, MV_BIT_RIGHT
4574 Xspring_force_w, FALSE, FALSE,
4575 EL_SPRING, -1, MV_BIT_LEFT
4578 Xemerald_force_e, FALSE, FALSE,
4579 EL_EMERALD, -1, MV_BIT_RIGHT
4582 Xemerald_force_w, FALSE, FALSE,
4583 EL_EMERALD, -1, MV_BIT_LEFT
4586 Xdiamond_force_e, FALSE, FALSE,
4587 EL_DIAMOND, -1, MV_BIT_RIGHT
4590 Xdiamond_force_w, FALSE, FALSE,
4591 EL_DIAMOND, -1, MV_BIT_LEFT
4594 Xbomb_force_e, FALSE, FALSE,
4595 EL_BOMB, -1, MV_BIT_RIGHT
4598 Xbomb_force_w, FALSE, FALSE,
4599 EL_BOMB, -1, MV_BIT_LEFT
4601 #endif /* EM_ENGINE_BAD_ROLL */
4604 Xstone, TRUE, FALSE,
4608 Xstone_pause, FALSE, FALSE,
4612 Xstone_fall, FALSE, FALSE,
4616 Ystone_s, FALSE, FALSE,
4617 EL_ROCK, ACTION_FALLING, -1
4620 Ystone_sB, FALSE, TRUE,
4621 EL_ROCK, ACTION_FALLING, -1
4624 Ystone_e, FALSE, FALSE,
4625 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4628 Ystone_eB, FALSE, TRUE,
4629 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4632 Ystone_w, FALSE, FALSE,
4633 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4636 Ystone_wB, FALSE, TRUE,
4637 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4644 Xnut_pause, FALSE, FALSE,
4648 Xnut_fall, FALSE, FALSE,
4652 Ynut_s, FALSE, FALSE,
4653 EL_NUT, ACTION_FALLING, -1
4656 Ynut_sB, FALSE, TRUE,
4657 EL_NUT, ACTION_FALLING, -1
4660 Ynut_e, FALSE, FALSE,
4661 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4664 Ynut_eB, FALSE, TRUE,
4665 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4668 Ynut_w, FALSE, FALSE,
4669 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4672 Ynut_wB, FALSE, TRUE,
4673 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4676 Xbug_n, TRUE, FALSE,
4680 Xbug_e, TRUE, FALSE,
4681 EL_BUG_RIGHT, -1, -1
4684 Xbug_s, TRUE, FALSE,
4688 Xbug_w, TRUE, FALSE,
4692 Xbug_gon, FALSE, FALSE,
4696 Xbug_goe, FALSE, FALSE,
4697 EL_BUG_RIGHT, -1, -1
4700 Xbug_gos, FALSE, FALSE,
4704 Xbug_gow, FALSE, FALSE,
4708 Ybug_n, FALSE, FALSE,
4709 EL_BUG, ACTION_MOVING, MV_BIT_UP
4712 Ybug_nB, FALSE, TRUE,
4713 EL_BUG, ACTION_MOVING, MV_BIT_UP
4716 Ybug_e, FALSE, FALSE,
4717 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4720 Ybug_eB, FALSE, TRUE,
4721 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4724 Ybug_s, FALSE, FALSE,
4725 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4728 Ybug_sB, FALSE, TRUE,
4729 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4732 Ybug_w, FALSE, FALSE,
4733 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4736 Ybug_wB, FALSE, TRUE,
4737 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4740 Ybug_w_n, FALSE, FALSE,
4741 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4744 Ybug_n_e, FALSE, FALSE,
4745 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4748 Ybug_e_s, FALSE, FALSE,
4749 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4752 Ybug_s_w, FALSE, FALSE,
4753 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4756 Ybug_e_n, FALSE, FALSE,
4757 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4760 Ybug_s_e, FALSE, FALSE,
4761 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4764 Ybug_w_s, FALSE, FALSE,
4765 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4768 Ybug_n_w, FALSE, FALSE,
4769 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4772 Ybug_stone, FALSE, FALSE,
4773 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4776 Ybug_spring, FALSE, FALSE,
4777 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4780 Xtank_n, TRUE, FALSE,
4781 EL_SPACESHIP_UP, -1, -1
4784 Xtank_e, TRUE, FALSE,
4785 EL_SPACESHIP_RIGHT, -1, -1
4788 Xtank_s, TRUE, FALSE,
4789 EL_SPACESHIP_DOWN, -1, -1
4792 Xtank_w, TRUE, FALSE,
4793 EL_SPACESHIP_LEFT, -1, -1
4796 Xtank_gon, FALSE, FALSE,
4797 EL_SPACESHIP_UP, -1, -1
4800 Xtank_goe, FALSE, FALSE,
4801 EL_SPACESHIP_RIGHT, -1, -1
4804 Xtank_gos, FALSE, FALSE,
4805 EL_SPACESHIP_DOWN, -1, -1
4808 Xtank_gow, FALSE, FALSE,
4809 EL_SPACESHIP_LEFT, -1, -1
4812 Ytank_n, FALSE, FALSE,
4813 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4816 Ytank_nB, FALSE, TRUE,
4817 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4820 Ytank_e, FALSE, FALSE,
4821 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4824 Ytank_eB, FALSE, TRUE,
4825 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4828 Ytank_s, FALSE, FALSE,
4829 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4832 Ytank_sB, FALSE, TRUE,
4833 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4836 Ytank_w, FALSE, FALSE,
4837 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4840 Ytank_wB, FALSE, TRUE,
4841 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4844 Ytank_w_n, FALSE, FALSE,
4845 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4848 Ytank_n_e, FALSE, FALSE,
4849 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4852 Ytank_e_s, FALSE, FALSE,
4853 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4856 Ytank_s_w, FALSE, FALSE,
4857 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4860 Ytank_e_n, FALSE, FALSE,
4861 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4864 Ytank_s_e, FALSE, FALSE,
4865 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4868 Ytank_w_s, FALSE, FALSE,
4869 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4872 Ytank_n_w, FALSE, FALSE,
4873 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4876 Ytank_stone, FALSE, FALSE,
4877 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4880 Ytank_spring, FALSE, FALSE,
4881 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4884 Xandroid, TRUE, FALSE,
4885 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4888 Xandroid_1_n, FALSE, FALSE,
4889 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4892 Xandroid_2_n, FALSE, FALSE,
4893 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4896 Xandroid_1_e, FALSE, FALSE,
4897 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4900 Xandroid_2_e, FALSE, FALSE,
4901 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4904 Xandroid_1_w, FALSE, FALSE,
4905 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4908 Xandroid_2_w, FALSE, FALSE,
4909 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4912 Xandroid_1_s, FALSE, FALSE,
4913 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4916 Xandroid_2_s, FALSE, FALSE,
4917 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4920 Yandroid_n, FALSE, FALSE,
4921 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4924 Yandroid_nB, FALSE, TRUE,
4925 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4928 Yandroid_ne, FALSE, FALSE,
4929 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4932 Yandroid_neB, FALSE, TRUE,
4933 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4936 Yandroid_e, FALSE, FALSE,
4937 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4940 Yandroid_eB, FALSE, TRUE,
4941 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4944 Yandroid_se, FALSE, FALSE,
4945 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4948 Yandroid_seB, FALSE, TRUE,
4949 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4952 Yandroid_s, FALSE, FALSE,
4953 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4956 Yandroid_sB, FALSE, TRUE,
4957 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4960 Yandroid_sw, FALSE, FALSE,
4961 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4964 Yandroid_swB, FALSE, TRUE,
4965 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4968 Yandroid_w, FALSE, FALSE,
4969 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4972 Yandroid_wB, FALSE, TRUE,
4973 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4976 Yandroid_nw, FALSE, FALSE,
4977 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4980 Yandroid_nwB, FALSE, TRUE,
4981 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4984 Xspring, TRUE, FALSE,
4988 Xspring_pause, FALSE, FALSE,
4992 Xspring_e, FALSE, FALSE,
4996 Xspring_w, FALSE, FALSE,
5000 Xspring_fall, FALSE, FALSE,
5004 Yspring_s, FALSE, FALSE,
5005 EL_SPRING, ACTION_FALLING, -1
5008 Yspring_sB, FALSE, TRUE,
5009 EL_SPRING, ACTION_FALLING, -1
5012 Yspring_e, FALSE, FALSE,
5013 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5016 Yspring_eB, FALSE, TRUE,
5017 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5020 Yspring_w, FALSE, FALSE,
5021 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5024 Yspring_wB, FALSE, TRUE,
5025 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5028 Yspring_kill_e, FALSE, FALSE,
5029 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5032 Yspring_kill_eB, FALSE, TRUE,
5033 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5036 Yspring_kill_w, FALSE, FALSE,
5037 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5040 Yspring_kill_wB, FALSE, TRUE,
5041 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5044 Xeater_n, TRUE, FALSE,
5045 EL_YAMYAM_UP, -1, -1
5048 Xeater_e, TRUE, FALSE,
5049 EL_YAMYAM_RIGHT, -1, -1
5052 Xeater_w, TRUE, FALSE,
5053 EL_YAMYAM_LEFT, -1, -1
5056 Xeater_s, TRUE, FALSE,
5057 EL_YAMYAM_DOWN, -1, -1
5060 Yeater_n, FALSE, FALSE,
5061 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5064 Yeater_nB, FALSE, TRUE,
5065 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5068 Yeater_e, FALSE, FALSE,
5069 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5072 Yeater_eB, FALSE, TRUE,
5073 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5076 Yeater_s, FALSE, FALSE,
5077 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5080 Yeater_sB, FALSE, TRUE,
5081 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5084 Yeater_w, FALSE, FALSE,
5085 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5088 Yeater_wB, FALSE, TRUE,
5089 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5092 Yeater_stone, FALSE, FALSE,
5093 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5096 Yeater_spring, FALSE, FALSE,
5097 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5100 Xalien, TRUE, FALSE,
5104 Xalien_pause, FALSE, FALSE,
5108 Yalien_n, FALSE, FALSE,
5109 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5112 Yalien_nB, FALSE, TRUE,
5113 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5116 Yalien_e, FALSE, FALSE,
5117 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5120 Yalien_eB, FALSE, TRUE,
5121 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5124 Yalien_s, FALSE, FALSE,
5125 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5128 Yalien_sB, FALSE, TRUE,
5129 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5132 Yalien_w, FALSE, FALSE,
5133 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5136 Yalien_wB, FALSE, TRUE,
5137 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5140 Yalien_stone, FALSE, FALSE,
5141 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5144 Yalien_spring, FALSE, FALSE,
5145 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5148 Xemerald, TRUE, FALSE,
5152 Xemerald_pause, FALSE, FALSE,
5156 Xemerald_fall, FALSE, FALSE,
5160 Xemerald_shine, FALSE, FALSE,
5161 EL_EMERALD, ACTION_TWINKLING, -1
5164 Yemerald_s, FALSE, FALSE,
5165 EL_EMERALD, ACTION_FALLING, -1
5168 Yemerald_sB, FALSE, TRUE,
5169 EL_EMERALD, ACTION_FALLING, -1
5172 Yemerald_e, FALSE, FALSE,
5173 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5176 Yemerald_eB, FALSE, TRUE,
5177 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5180 Yemerald_w, FALSE, FALSE,
5181 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5184 Yemerald_wB, FALSE, TRUE,
5185 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5188 Yemerald_eat, FALSE, FALSE,
5189 EL_EMERALD, ACTION_COLLECTING, -1
5192 Yemerald_stone, FALSE, FALSE,
5193 EL_NUT, ACTION_BREAKING, -1
5196 Xdiamond, TRUE, FALSE,
5200 Xdiamond_pause, FALSE, FALSE,
5204 Xdiamond_fall, FALSE, FALSE,
5208 Xdiamond_shine, FALSE, FALSE,
5209 EL_DIAMOND, ACTION_TWINKLING, -1
5212 Ydiamond_s, FALSE, FALSE,
5213 EL_DIAMOND, ACTION_FALLING, -1
5216 Ydiamond_sB, FALSE, TRUE,
5217 EL_DIAMOND, ACTION_FALLING, -1
5220 Ydiamond_e, FALSE, FALSE,
5221 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5224 Ydiamond_eB, FALSE, TRUE,
5225 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5228 Ydiamond_w, FALSE, FALSE,
5229 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5232 Ydiamond_wB, FALSE, TRUE,
5233 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5236 Ydiamond_eat, FALSE, FALSE,
5237 EL_DIAMOND, ACTION_COLLECTING, -1
5240 Ydiamond_stone, FALSE, FALSE,
5241 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5244 Xdrip_fall, TRUE, FALSE,
5245 EL_AMOEBA_DROP, -1, -1
5248 Xdrip_stretch, FALSE, FALSE,
5249 EL_AMOEBA_DROP, ACTION_FALLING, -1
5252 Xdrip_stretchB, FALSE, TRUE,
5253 EL_AMOEBA_DROP, ACTION_FALLING, -1
5256 Xdrip_eat, FALSE, FALSE,
5257 EL_AMOEBA_DROP, ACTION_GROWING, -1
5260 Ydrip_s1, FALSE, FALSE,
5261 EL_AMOEBA_DROP, ACTION_FALLING, -1
5264 Ydrip_s1B, FALSE, TRUE,
5265 EL_AMOEBA_DROP, ACTION_FALLING, -1
5268 Ydrip_s2, FALSE, FALSE,
5269 EL_AMOEBA_DROP, ACTION_FALLING, -1
5272 Ydrip_s2B, FALSE, TRUE,
5273 EL_AMOEBA_DROP, ACTION_FALLING, -1
5280 Xbomb_pause, FALSE, FALSE,
5284 Xbomb_fall, FALSE, FALSE,
5288 Ybomb_s, FALSE, FALSE,
5289 EL_BOMB, ACTION_FALLING, -1
5292 Ybomb_sB, FALSE, TRUE,
5293 EL_BOMB, ACTION_FALLING, -1
5296 Ybomb_e, FALSE, FALSE,
5297 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5300 Ybomb_eB, FALSE, TRUE,
5301 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5304 Ybomb_w, FALSE, FALSE,
5305 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5308 Ybomb_wB, FALSE, TRUE,
5309 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5312 Ybomb_eat, FALSE, FALSE,
5313 EL_BOMB, ACTION_ACTIVATING, -1
5316 Xballoon, TRUE, FALSE,
5320 Yballoon_n, FALSE, FALSE,
5321 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5324 Yballoon_nB, FALSE, TRUE,
5325 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5328 Yballoon_e, FALSE, FALSE,
5329 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5332 Yballoon_eB, FALSE, TRUE,
5333 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5336 Yballoon_s, FALSE, FALSE,
5337 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5340 Yballoon_sB, FALSE, TRUE,
5341 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5344 Yballoon_w, FALSE, FALSE,
5345 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5348 Yballoon_wB, FALSE, TRUE,
5349 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5352 Xgrass, TRUE, FALSE,
5353 EL_EMC_GRASS, -1, -1
5356 Ygrass_nB, FALSE, FALSE,
5357 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5360 Ygrass_eB, FALSE, FALSE,
5361 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5364 Ygrass_sB, FALSE, FALSE,
5365 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5368 Ygrass_wB, FALSE, FALSE,
5369 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5376 Ydirt_nB, FALSE, FALSE,
5377 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5380 Ydirt_eB, FALSE, FALSE,
5381 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5384 Ydirt_sB, FALSE, FALSE,
5385 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5388 Ydirt_wB, FALSE, FALSE,
5389 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5392 Xacid_ne, TRUE, FALSE,
5393 EL_ACID_POOL_TOPRIGHT, -1, -1
5396 Xacid_se, TRUE, FALSE,
5397 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5400 Xacid_s, TRUE, FALSE,
5401 EL_ACID_POOL_BOTTOM, -1, -1
5404 Xacid_sw, TRUE, FALSE,
5405 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5408 Xacid_nw, TRUE, FALSE,
5409 EL_ACID_POOL_TOPLEFT, -1, -1
5412 Xacid_1, TRUE, FALSE,
5416 Xacid_2, FALSE, FALSE,
5420 Xacid_3, FALSE, FALSE,
5424 Xacid_4, FALSE, FALSE,
5428 Xacid_5, FALSE, FALSE,
5432 Xacid_6, FALSE, FALSE,
5436 Xacid_7, FALSE, FALSE,
5440 Xacid_8, FALSE, FALSE,
5444 Xball_1, TRUE, FALSE,
5445 EL_EMC_MAGIC_BALL, -1, -1
5448 Xball_1B, FALSE, FALSE,
5449 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5452 Xball_2, FALSE, FALSE,
5453 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5456 Xball_2B, FALSE, FALSE,
5457 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5460 Yball_eat, FALSE, FALSE,
5461 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5464 Ykey_1_eat, FALSE, FALSE,
5465 EL_EM_KEY_1, ACTION_COLLECTING, -1
5468 Ykey_2_eat, FALSE, FALSE,
5469 EL_EM_KEY_2, ACTION_COLLECTING, -1
5472 Ykey_3_eat, FALSE, FALSE,
5473 EL_EM_KEY_3, ACTION_COLLECTING, -1
5476 Ykey_4_eat, FALSE, FALSE,
5477 EL_EM_KEY_4, ACTION_COLLECTING, -1
5480 Ykey_5_eat, FALSE, FALSE,
5481 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5484 Ykey_6_eat, FALSE, FALSE,
5485 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5488 Ykey_7_eat, FALSE, FALSE,
5489 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5492 Ykey_8_eat, FALSE, FALSE,
5493 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5496 Ylenses_eat, FALSE, FALSE,
5497 EL_EMC_LENSES, ACTION_COLLECTING, -1
5500 Ymagnify_eat, FALSE, FALSE,
5501 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5504 Ygrass_eat, FALSE, FALSE,
5505 EL_EMC_GRASS, ACTION_SNAPPING, -1
5508 Ydirt_eat, FALSE, FALSE,
5509 EL_SAND, ACTION_SNAPPING, -1
5512 Xgrow_ns, TRUE, FALSE,
5513 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5516 Ygrow_ns_eat, FALSE, FALSE,
5517 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5520 Xgrow_ew, TRUE, FALSE,
5521 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5524 Ygrow_ew_eat, FALSE, FALSE,
5525 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5528 Xwonderwall, TRUE, FALSE,
5529 EL_MAGIC_WALL, -1, -1
5532 XwonderwallB, FALSE, FALSE,
5533 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5536 Xamoeba_1, TRUE, FALSE,
5537 EL_AMOEBA_DRY, ACTION_OTHER, -1
5540 Xamoeba_2, FALSE, FALSE,
5541 EL_AMOEBA_DRY, ACTION_OTHER, -1
5544 Xamoeba_3, FALSE, FALSE,
5545 EL_AMOEBA_DRY, ACTION_OTHER, -1
5548 Xamoeba_4, FALSE, FALSE,
5549 EL_AMOEBA_DRY, ACTION_OTHER, -1
5552 Xamoeba_5, TRUE, FALSE,
5553 EL_AMOEBA_WET, ACTION_OTHER, -1
5556 Xamoeba_6, FALSE, FALSE,
5557 EL_AMOEBA_WET, ACTION_OTHER, -1
5560 Xamoeba_7, FALSE, FALSE,
5561 EL_AMOEBA_WET, ACTION_OTHER, -1
5564 Xamoeba_8, FALSE, FALSE,
5565 EL_AMOEBA_WET, ACTION_OTHER, -1
5568 Xdoor_1, TRUE, FALSE,
5569 EL_EM_GATE_1, -1, -1
5572 Xdoor_2, TRUE, FALSE,
5573 EL_EM_GATE_2, -1, -1
5576 Xdoor_3, TRUE, FALSE,
5577 EL_EM_GATE_3, -1, -1
5580 Xdoor_4, TRUE, FALSE,
5581 EL_EM_GATE_4, -1, -1
5584 Xdoor_5, TRUE, FALSE,
5585 EL_EMC_GATE_5, -1, -1
5588 Xdoor_6, TRUE, FALSE,
5589 EL_EMC_GATE_6, -1, -1
5592 Xdoor_7, TRUE, FALSE,
5593 EL_EMC_GATE_7, -1, -1
5596 Xdoor_8, TRUE, FALSE,
5597 EL_EMC_GATE_8, -1, -1
5600 Xkey_1, TRUE, FALSE,
5604 Xkey_2, TRUE, FALSE,
5608 Xkey_3, TRUE, FALSE,
5612 Xkey_4, TRUE, FALSE,
5616 Xkey_5, TRUE, FALSE,
5617 EL_EMC_KEY_5, -1, -1
5620 Xkey_6, TRUE, FALSE,
5621 EL_EMC_KEY_6, -1, -1
5624 Xkey_7, TRUE, FALSE,
5625 EL_EMC_KEY_7, -1, -1
5628 Xkey_8, TRUE, FALSE,
5629 EL_EMC_KEY_8, -1, -1
5632 Xwind_n, TRUE, FALSE,
5633 EL_BALLOON_SWITCH_UP, -1, -1
5636 Xwind_e, TRUE, FALSE,
5637 EL_BALLOON_SWITCH_RIGHT, -1, -1
5640 Xwind_s, TRUE, FALSE,
5641 EL_BALLOON_SWITCH_DOWN, -1, -1
5644 Xwind_w, TRUE, FALSE,
5645 EL_BALLOON_SWITCH_LEFT, -1, -1
5648 Xwind_nesw, TRUE, FALSE,
5649 EL_BALLOON_SWITCH_ANY, -1, -1
5652 Xwind_stop, TRUE, FALSE,
5653 EL_BALLOON_SWITCH_NONE, -1, -1
5657 EL_EM_EXIT_CLOSED, -1, -1
5660 Xexit_1, TRUE, FALSE,
5661 EL_EM_EXIT_OPEN, -1, -1
5664 Xexit_2, FALSE, FALSE,
5665 EL_EM_EXIT_OPEN, -1, -1
5668 Xexit_3, FALSE, FALSE,
5669 EL_EM_EXIT_OPEN, -1, -1
5672 Xdynamite, TRUE, FALSE,
5673 EL_EM_DYNAMITE, -1, -1
5676 Ydynamite_eat, FALSE, FALSE,
5677 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5680 Xdynamite_1, TRUE, FALSE,
5681 EL_EM_DYNAMITE_ACTIVE, -1, -1
5684 Xdynamite_2, FALSE, FALSE,
5685 EL_EM_DYNAMITE_ACTIVE, -1, -1
5688 Xdynamite_3, FALSE, FALSE,
5689 EL_EM_DYNAMITE_ACTIVE, -1, -1
5692 Xdynamite_4, FALSE, FALSE,
5693 EL_EM_DYNAMITE_ACTIVE, -1, -1
5696 Xbumper, TRUE, FALSE,
5697 EL_EMC_SPRING_BUMPER, -1, -1
5700 XbumperB, FALSE, FALSE,
5701 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5704 Xwheel, TRUE, FALSE,
5705 EL_ROBOT_WHEEL, -1, -1
5708 XwheelB, FALSE, FALSE,
5709 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5712 Xswitch, TRUE, FALSE,
5713 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5716 XswitchB, FALSE, FALSE,
5717 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5721 EL_QUICKSAND_EMPTY, -1, -1
5724 Xsand_stone, TRUE, FALSE,
5725 EL_QUICKSAND_FULL, -1, -1
5728 Xsand_stonein_1, FALSE, TRUE,
5729 EL_ROCK, ACTION_FILLING, -1
5732 Xsand_stonein_2, FALSE, TRUE,
5733 EL_ROCK, ACTION_FILLING, -1
5736 Xsand_stonein_3, FALSE, TRUE,
5737 EL_ROCK, ACTION_FILLING, -1
5740 Xsand_stonein_4, FALSE, TRUE,
5741 EL_ROCK, ACTION_FILLING, -1
5744 Xsand_stonesand_1, FALSE, FALSE,
5745 EL_QUICKSAND_EMPTYING, -1, -1
5748 Xsand_stonesand_2, FALSE, FALSE,
5749 EL_QUICKSAND_EMPTYING, -1, -1
5752 Xsand_stonesand_3, FALSE, FALSE,
5753 EL_QUICKSAND_EMPTYING, -1, -1
5756 Xsand_stonesand_4, FALSE, FALSE,
5757 EL_QUICKSAND_EMPTYING, -1, -1
5760 Xsand_stonesand_quickout_1, FALSE, FALSE,
5761 EL_QUICKSAND_EMPTYING, -1, -1
5764 Xsand_stonesand_quickout_2, FALSE, FALSE,
5765 EL_QUICKSAND_EMPTYING, -1, -1
5768 Xsand_stoneout_1, FALSE, FALSE,
5769 EL_ROCK, ACTION_EMPTYING, -1
5772 Xsand_stoneout_2, FALSE, FALSE,
5773 EL_ROCK, ACTION_EMPTYING, -1
5776 Xsand_sandstone_1, FALSE, FALSE,
5777 EL_QUICKSAND_FILLING, -1, -1
5780 Xsand_sandstone_2, FALSE, FALSE,
5781 EL_QUICKSAND_FILLING, -1, -1
5784 Xsand_sandstone_3, FALSE, FALSE,
5785 EL_QUICKSAND_FILLING, -1, -1
5788 Xsand_sandstone_4, FALSE, FALSE,
5789 EL_QUICKSAND_FILLING, -1, -1
5792 Xplant, TRUE, FALSE,
5793 EL_EMC_PLANT, -1, -1
5796 Yplant, FALSE, FALSE,
5797 EL_EMC_PLANT, -1, -1
5800 Xlenses, TRUE, FALSE,
5801 EL_EMC_LENSES, -1, -1
5804 Xmagnify, TRUE, FALSE,
5805 EL_EMC_MAGNIFIER, -1, -1
5808 Xdripper, TRUE, FALSE,
5809 EL_EMC_DRIPPER, -1, -1
5812 XdripperB, FALSE, FALSE,
5813 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5816 Xfake_blank, TRUE, FALSE,
5817 EL_INVISIBLE_WALL, -1, -1
5820 Xfake_blankB, FALSE, FALSE,
5821 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5824 Xfake_grass, TRUE, FALSE,
5825 EL_EMC_FAKE_GRASS, -1, -1
5828 Xfake_grassB, FALSE, FALSE,
5829 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5832 Xfake_door_1, TRUE, FALSE,
5833 EL_EM_GATE_1_GRAY, -1, -1
5836 Xfake_door_2, TRUE, FALSE,
5837 EL_EM_GATE_2_GRAY, -1, -1
5840 Xfake_door_3, TRUE, FALSE,
5841 EL_EM_GATE_3_GRAY, -1, -1
5844 Xfake_door_4, TRUE, FALSE,
5845 EL_EM_GATE_4_GRAY, -1, -1
5848 Xfake_door_5, TRUE, FALSE,
5849 EL_EMC_GATE_5_GRAY, -1, -1
5852 Xfake_door_6, TRUE, FALSE,
5853 EL_EMC_GATE_6_GRAY, -1, -1
5856 Xfake_door_7, TRUE, FALSE,
5857 EL_EMC_GATE_7_GRAY, -1, -1
5860 Xfake_door_8, TRUE, FALSE,
5861 EL_EMC_GATE_8_GRAY, -1, -1
5864 Xfake_acid_1, TRUE, FALSE,
5865 EL_EMC_FAKE_ACID, -1, -1
5868 Xfake_acid_2, FALSE, FALSE,
5869 EL_EMC_FAKE_ACID, -1, -1
5872 Xfake_acid_3, FALSE, FALSE,
5873 EL_EMC_FAKE_ACID, -1, -1
5876 Xfake_acid_4, FALSE, FALSE,
5877 EL_EMC_FAKE_ACID, -1, -1
5880 Xfake_acid_5, FALSE, FALSE,
5881 EL_EMC_FAKE_ACID, -1, -1
5884 Xfake_acid_6, FALSE, FALSE,
5885 EL_EMC_FAKE_ACID, -1, -1
5888 Xfake_acid_7, FALSE, FALSE,
5889 EL_EMC_FAKE_ACID, -1, -1
5892 Xfake_acid_8, FALSE, FALSE,
5893 EL_EMC_FAKE_ACID, -1, -1
5896 Xsteel_1, TRUE, FALSE,
5897 EL_STEELWALL, -1, -1
5900 Xsteel_2, TRUE, FALSE,
5901 EL_EMC_STEELWALL_2, -1, -1
5904 Xsteel_3, TRUE, FALSE,
5905 EL_EMC_STEELWALL_3, -1, -1
5908 Xsteel_4, TRUE, FALSE,
5909 EL_EMC_STEELWALL_4, -1, -1
5912 Xwall_1, TRUE, FALSE,
5916 Xwall_2, TRUE, FALSE,
5917 EL_EMC_WALL_14, -1, -1
5920 Xwall_3, TRUE, FALSE,
5921 EL_EMC_WALL_15, -1, -1
5924 Xwall_4, TRUE, FALSE,
5925 EL_EMC_WALL_16, -1, -1
5928 Xround_wall_1, TRUE, FALSE,
5929 EL_WALL_SLIPPERY, -1, -1
5932 Xround_wall_2, TRUE, FALSE,
5933 EL_EMC_WALL_SLIPPERY_2, -1, -1
5936 Xround_wall_3, TRUE, FALSE,
5937 EL_EMC_WALL_SLIPPERY_3, -1, -1
5940 Xround_wall_4, TRUE, FALSE,
5941 EL_EMC_WALL_SLIPPERY_4, -1, -1
5944 Xdecor_1, TRUE, FALSE,
5945 EL_EMC_WALL_8, -1, -1
5948 Xdecor_2, TRUE, FALSE,
5949 EL_EMC_WALL_6, -1, -1
5952 Xdecor_3, TRUE, FALSE,
5953 EL_EMC_WALL_4, -1, -1
5956 Xdecor_4, TRUE, FALSE,
5957 EL_EMC_WALL_7, -1, -1
5960 Xdecor_5, TRUE, FALSE,
5961 EL_EMC_WALL_5, -1, -1
5964 Xdecor_6, TRUE, FALSE,
5965 EL_EMC_WALL_9, -1, -1
5968 Xdecor_7, TRUE, FALSE,
5969 EL_EMC_WALL_10, -1, -1
5972 Xdecor_8, TRUE, FALSE,
5973 EL_EMC_WALL_1, -1, -1
5976 Xdecor_9, TRUE, FALSE,
5977 EL_EMC_WALL_2, -1, -1
5980 Xdecor_10, TRUE, FALSE,
5981 EL_EMC_WALL_3, -1, -1
5984 Xdecor_11, TRUE, FALSE,
5985 EL_EMC_WALL_11, -1, -1
5988 Xdecor_12, TRUE, FALSE,
5989 EL_EMC_WALL_12, -1, -1
5992 Xalpha_0, TRUE, FALSE,
5993 EL_CHAR('0'), -1, -1
5996 Xalpha_1, TRUE, FALSE,
5997 EL_CHAR('1'), -1, -1
6000 Xalpha_2, TRUE, FALSE,
6001 EL_CHAR('2'), -1, -1
6004 Xalpha_3, TRUE, FALSE,
6005 EL_CHAR('3'), -1, -1
6008 Xalpha_4, TRUE, FALSE,
6009 EL_CHAR('4'), -1, -1
6012 Xalpha_5, TRUE, FALSE,
6013 EL_CHAR('5'), -1, -1
6016 Xalpha_6, TRUE, FALSE,
6017 EL_CHAR('6'), -1, -1
6020 Xalpha_7, TRUE, FALSE,
6021 EL_CHAR('7'), -1, -1
6024 Xalpha_8, TRUE, FALSE,
6025 EL_CHAR('8'), -1, -1
6028 Xalpha_9, TRUE, FALSE,
6029 EL_CHAR('9'), -1, -1
6032 Xalpha_excla, TRUE, FALSE,
6033 EL_CHAR('!'), -1, -1
6036 Xalpha_quote, TRUE, FALSE,
6037 EL_CHAR('"'), -1, -1
6040 Xalpha_comma, TRUE, FALSE,
6041 EL_CHAR(','), -1, -1
6044 Xalpha_minus, TRUE, FALSE,
6045 EL_CHAR('-'), -1, -1
6048 Xalpha_perio, TRUE, FALSE,
6049 EL_CHAR('.'), -1, -1
6052 Xalpha_colon, TRUE, FALSE,
6053 EL_CHAR(':'), -1, -1
6056 Xalpha_quest, TRUE, FALSE,
6057 EL_CHAR('?'), -1, -1
6060 Xalpha_a, TRUE, FALSE,
6061 EL_CHAR('A'), -1, -1
6064 Xalpha_b, TRUE, FALSE,
6065 EL_CHAR('B'), -1, -1
6068 Xalpha_c, TRUE, FALSE,
6069 EL_CHAR('C'), -1, -1
6072 Xalpha_d, TRUE, FALSE,
6073 EL_CHAR('D'), -1, -1
6076 Xalpha_e, TRUE, FALSE,
6077 EL_CHAR('E'), -1, -1
6080 Xalpha_f, TRUE, FALSE,
6081 EL_CHAR('F'), -1, -1
6084 Xalpha_g, TRUE, FALSE,
6085 EL_CHAR('G'), -1, -1
6088 Xalpha_h, TRUE, FALSE,
6089 EL_CHAR('H'), -1, -1
6092 Xalpha_i, TRUE, FALSE,
6093 EL_CHAR('I'), -1, -1
6096 Xalpha_j, TRUE, FALSE,
6097 EL_CHAR('J'), -1, -1
6100 Xalpha_k, TRUE, FALSE,
6101 EL_CHAR('K'), -1, -1
6104 Xalpha_l, TRUE, FALSE,
6105 EL_CHAR('L'), -1, -1
6108 Xalpha_m, TRUE, FALSE,
6109 EL_CHAR('M'), -1, -1
6112 Xalpha_n, TRUE, FALSE,
6113 EL_CHAR('N'), -1, -1
6116 Xalpha_o, TRUE, FALSE,
6117 EL_CHAR('O'), -1, -1
6120 Xalpha_p, TRUE, FALSE,
6121 EL_CHAR('P'), -1, -1
6124 Xalpha_q, TRUE, FALSE,
6125 EL_CHAR('Q'), -1, -1
6128 Xalpha_r, TRUE, FALSE,
6129 EL_CHAR('R'), -1, -1
6132 Xalpha_s, TRUE, FALSE,
6133 EL_CHAR('S'), -1, -1
6136 Xalpha_t, TRUE, FALSE,
6137 EL_CHAR('T'), -1, -1
6140 Xalpha_u, TRUE, FALSE,
6141 EL_CHAR('U'), -1, -1
6144 Xalpha_v, TRUE, FALSE,
6145 EL_CHAR('V'), -1, -1
6148 Xalpha_w, TRUE, FALSE,
6149 EL_CHAR('W'), -1, -1
6152 Xalpha_x, TRUE, FALSE,
6153 EL_CHAR('X'), -1, -1
6156 Xalpha_y, TRUE, FALSE,
6157 EL_CHAR('Y'), -1, -1
6160 Xalpha_z, TRUE, FALSE,
6161 EL_CHAR('Z'), -1, -1
6164 Xalpha_arrow_e, TRUE, FALSE,
6165 EL_CHAR('>'), -1, -1
6168 Xalpha_arrow_w, TRUE, FALSE,
6169 EL_CHAR('<'), -1, -1
6172 Xalpha_copyr, TRUE, FALSE,
6173 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6177 Xboom_bug, FALSE, FALSE,
6178 EL_BUG, ACTION_EXPLODING, -1
6181 Xboom_bomb, FALSE, FALSE,
6182 EL_BOMB, ACTION_EXPLODING, -1
6185 Xboom_android, FALSE, FALSE,
6186 EL_EMC_ANDROID, ACTION_OTHER, -1
6189 Xboom_1, FALSE, FALSE,
6190 EL_DEFAULT, ACTION_EXPLODING, -1
6193 Xboom_2, FALSE, FALSE,
6194 EL_DEFAULT, ACTION_EXPLODING, -1
6197 Znormal, FALSE, FALSE,
6201 Zdynamite, FALSE, FALSE,
6205 Zplayer, FALSE, FALSE,
6209 ZBORDER, FALSE, FALSE,
6219 static struct Mapping_EM_to_RND_player
6228 em_player_mapping_list[] =
6232 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6236 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6240 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6244 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6248 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6252 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6256 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6260 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6264 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6268 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6272 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6276 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6280 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6284 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6288 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6292 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6296 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6300 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6304 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6308 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6312 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6316 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6320 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6324 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6328 EL_PLAYER_1, ACTION_DEFAULT, -1,
6332 EL_PLAYER_2, ACTION_DEFAULT, -1,
6336 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6340 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6344 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6348 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6352 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6356 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6360 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6364 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6368 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6372 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6376 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6380 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6384 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6388 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6392 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6396 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6400 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6404 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6408 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6412 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6416 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6420 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6424 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6428 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6432 EL_PLAYER_3, ACTION_DEFAULT, -1,
6436 EL_PLAYER_4, ACTION_DEFAULT, -1,
6445 int map_element_RND_to_EM(int element_rnd)
6447 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6448 static boolean mapping_initialized = FALSE;
6450 if (!mapping_initialized)
6454 /* return "Xalpha_quest" for all undefined elements in mapping array */
6455 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6456 mapping_RND_to_EM[i] = Xalpha_quest;
6458 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6459 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6460 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6461 em_object_mapping_list[i].element_em;
6463 mapping_initialized = TRUE;
6466 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6467 return mapping_RND_to_EM[element_rnd];
6469 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6474 int map_element_EM_to_RND(int element_em)
6476 static unsigned short mapping_EM_to_RND[TILE_MAX];
6477 static boolean mapping_initialized = FALSE;
6479 if (!mapping_initialized)
6483 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6484 for (i = 0; i < TILE_MAX; i++)
6485 mapping_EM_to_RND[i] = EL_UNKNOWN;
6487 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6488 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6489 em_object_mapping_list[i].element_rnd;
6491 mapping_initialized = TRUE;
6494 if (element_em >= 0 && element_em < TILE_MAX)
6495 return mapping_EM_to_RND[element_em];
6497 Error(ERR_WARN, "invalid EM level element %d", element_em);
6502 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6504 struct LevelInfo_EM *level_em = level->native_em_level;
6505 struct LEVEL *lev = level_em->lev;
6508 for (i = 0; i < TILE_MAX; i++)
6509 lev->android_array[i] = Xblank;
6511 for (i = 0; i < level->num_android_clone_elements; i++)
6513 int element_rnd = level->android_clone_element[i];
6514 int element_em = map_element_RND_to_EM(element_rnd);
6516 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6517 if (em_object_mapping_list[j].element_rnd == element_rnd)
6518 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6522 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6524 struct LevelInfo_EM *level_em = level->native_em_level;
6525 struct LEVEL *lev = level_em->lev;
6528 level->num_android_clone_elements = 0;
6530 for (i = 0; i < TILE_MAX; i++)
6532 int element_em = lev->android_array[i];
6534 boolean element_found = FALSE;
6536 if (element_em == Xblank)
6539 element_rnd = map_element_EM_to_RND(element_em);
6541 for (j = 0; j < level->num_android_clone_elements; j++)
6542 if (level->android_clone_element[j] == element_rnd)
6543 element_found = TRUE;
6547 level->android_clone_element[level->num_android_clone_elements++] =
6550 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6555 if (level->num_android_clone_elements == 0)
6557 level->num_android_clone_elements = 1;
6558 level->android_clone_element[0] = EL_EMPTY;
6562 int map_direction_RND_to_EM(int direction)
6564 return (direction == MV_UP ? 0 :
6565 direction == MV_RIGHT ? 1 :
6566 direction == MV_DOWN ? 2 :
6567 direction == MV_LEFT ? 3 :
6571 int map_direction_EM_to_RND(int direction)
6573 return (direction == 0 ? MV_UP :
6574 direction == 1 ? MV_RIGHT :
6575 direction == 2 ? MV_DOWN :
6576 direction == 3 ? MV_LEFT :
6580 int map_element_RND_to_SP(int element_rnd)
6582 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6584 if (element_rnd >= EL_SP_START &&
6585 element_rnd <= EL_SP_END)
6586 element_sp = element_rnd - EL_SP_START;
6587 else if (element_rnd == EL_EMPTY_SPACE)
6589 else if (element_rnd == EL_INVISIBLE_WALL)
6595 int map_element_SP_to_RND(int element_sp)
6597 int element_rnd = EL_UNKNOWN;
6599 if (element_sp >= 0x00 &&
6601 element_rnd = EL_SP_START + element_sp;
6602 else if (element_sp == 0x28)
6603 element_rnd = EL_INVISIBLE_WALL;
6608 int map_action_SP_to_RND(int action_sp)
6612 case actActive: return ACTION_ACTIVE;
6613 case actImpact: return ACTION_IMPACT;
6614 case actExploding: return ACTION_EXPLODING;
6615 case actDigging: return ACTION_DIGGING;
6616 case actSnapping: return ACTION_SNAPPING;
6617 case actCollecting: return ACTION_COLLECTING;
6618 case actPassing: return ACTION_PASSING;
6619 case actPushing: return ACTION_PUSHING;
6620 case actDropping: return ACTION_DROPPING;
6622 default: return ACTION_DEFAULT;
6626 int get_next_element(int element)
6630 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6631 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6632 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6633 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6634 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6635 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6636 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6637 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6638 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6639 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6640 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6642 default: return element;
6646 int el_act_dir2img(int element, int action, int direction)
6648 element = GFX_ELEMENT(element);
6649 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6651 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6652 return element_info[element].direction_graphic[action][direction];
6655 static int el_act_dir2crm(int element, int action, int direction)
6657 element = GFX_ELEMENT(element);
6658 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6660 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6661 return element_info[element].direction_crumbled[action][direction];
6664 int el_act2img(int element, int action)
6666 element = GFX_ELEMENT(element);
6668 return element_info[element].graphic[action];
6671 int el_act2crm(int element, int action)
6673 element = GFX_ELEMENT(element);
6675 return element_info[element].crumbled[action];
6678 int el_dir2img(int element, int direction)
6680 element = GFX_ELEMENT(element);
6682 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6685 int el2baseimg(int element)
6687 return element_info[element].graphic[ACTION_DEFAULT];
6690 int el2img(int element)
6692 element = GFX_ELEMENT(element);
6694 return element_info[element].graphic[ACTION_DEFAULT];
6697 int el2edimg(int element)
6699 element = GFX_ELEMENT(element);
6701 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6704 int el2preimg(int element)
6706 element = GFX_ELEMENT(element);
6708 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6711 int el2panelimg(int element)
6713 element = GFX_ELEMENT(element);
6715 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6718 int font2baseimg(int font_nr)
6720 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6723 int getBeltNrFromBeltElement(int element)
6725 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6726 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6727 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6730 int getBeltNrFromBeltActiveElement(int element)
6732 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6733 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6734 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6737 int getBeltNrFromBeltSwitchElement(int element)
6739 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6740 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6741 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6744 int getBeltDirNrFromBeltElement(int element)
6746 static int belt_base_element[4] =
6748 EL_CONVEYOR_BELT_1_LEFT,
6749 EL_CONVEYOR_BELT_2_LEFT,
6750 EL_CONVEYOR_BELT_3_LEFT,
6751 EL_CONVEYOR_BELT_4_LEFT
6754 int belt_nr = getBeltNrFromBeltElement(element);
6755 int belt_dir_nr = element - belt_base_element[belt_nr];
6757 return (belt_dir_nr % 3);
6760 int getBeltDirNrFromBeltSwitchElement(int element)
6762 static int belt_base_element[4] =
6764 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6765 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6766 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6767 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6770 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6771 int belt_dir_nr = element - belt_base_element[belt_nr];
6773 return (belt_dir_nr % 3);
6776 int getBeltDirFromBeltElement(int element)
6778 static int belt_move_dir[3] =
6785 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6787 return belt_move_dir[belt_dir_nr];
6790 int getBeltDirFromBeltSwitchElement(int element)
6792 static int belt_move_dir[3] =
6799 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6801 return belt_move_dir[belt_dir_nr];
6804 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6806 static int belt_base_element[4] =
6808 EL_CONVEYOR_BELT_1_LEFT,
6809 EL_CONVEYOR_BELT_2_LEFT,
6810 EL_CONVEYOR_BELT_3_LEFT,
6811 EL_CONVEYOR_BELT_4_LEFT
6814 return belt_base_element[belt_nr] + belt_dir_nr;
6817 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6819 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6821 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6824 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6826 static int belt_base_element[4] =
6828 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6829 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6830 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6831 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6834 return belt_base_element[belt_nr] + belt_dir_nr;
6837 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6839 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6841 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6844 boolean getTeamMode_EM()
6846 return game.team_mode;
6849 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6851 int game_frame_delay_value;
6853 game_frame_delay_value =
6854 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6855 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6858 if (tape.playing && tape.warp_forward && !tape.pausing)
6859 game_frame_delay_value = 0;
6861 return game_frame_delay_value;
6864 unsigned int InitRND(int seed)
6866 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6867 return InitEngineRandom_EM(seed);
6868 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6869 return InitEngineRandom_SP(seed);
6871 return InitEngineRandom_RND(seed);
6874 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6875 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6877 inline static int get_effective_element_EM(int tile, int frame_em)
6879 int element = object_mapping[tile].element_rnd;
6880 int action = object_mapping[tile].action;
6881 boolean is_backside = object_mapping[tile].is_backside;
6882 boolean action_removing = (action == ACTION_DIGGING ||
6883 action == ACTION_SNAPPING ||
6884 action == ACTION_COLLECTING);
6890 case Yacid_splash_eB:
6891 case Yacid_splash_wB:
6892 return (frame_em > 5 ? EL_EMPTY : element);
6898 else /* frame_em == 7 */
6902 case Yacid_splash_eB:
6903 case Yacid_splash_wB:
6906 case Yemerald_stone:
6909 case Ydiamond_stone:
6913 case Xdrip_stretchB:
6932 case Xsand_stonein_1:
6933 case Xsand_stonein_2:
6934 case Xsand_stonein_3:
6935 case Xsand_stonein_4:
6939 return (is_backside || action_removing ? EL_EMPTY : element);
6944 inline static boolean check_linear_animation_EM(int tile)
6948 case Xsand_stonesand_1:
6949 case Xsand_stonesand_quickout_1:
6950 case Xsand_sandstone_1:
6951 case Xsand_stonein_1:
6952 case Xsand_stoneout_1:
6971 case Yacid_splash_eB:
6972 case Yacid_splash_wB:
6973 case Yemerald_stone:
6980 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6981 boolean has_crumbled_graphics,
6982 int crumbled, int sync_frame)
6984 /* if element can be crumbled, but certain action graphics are just empty
6985 space (like instantly snapping sand to empty space in 1 frame), do not
6986 treat these empty space graphics as crumbled graphics in EMC engine */
6987 if (crumbled == IMG_EMPTY_SPACE)
6988 has_crumbled_graphics = FALSE;
6990 if (has_crumbled_graphics)
6992 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6993 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6994 g_crumbled->anim_delay,
6995 g_crumbled->anim_mode,
6996 g_crumbled->anim_start_frame,
6999 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7000 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7002 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7004 g_em->has_crumbled_graphics = TRUE;
7008 g_em->crumbled_bitmap = NULL;
7009 g_em->crumbled_src_x = 0;
7010 g_em->crumbled_src_y = 0;
7011 g_em->crumbled_border_size = 0;
7013 g_em->has_crumbled_graphics = FALSE;
7017 void ResetGfxAnimation_EM(int x, int y, int tile)
7022 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7023 int tile, int frame_em, int x, int y)
7025 int action = object_mapping[tile].action;
7026 int direction = object_mapping[tile].direction;
7027 int effective_element = get_effective_element_EM(tile, frame_em);
7028 int graphic = (direction == MV_NONE ?
7029 el_act2img(effective_element, action) :
7030 el_act_dir2img(effective_element, action, direction));
7031 struct GraphicInfo *g = &graphic_info[graphic];
7033 boolean action_removing = (action == ACTION_DIGGING ||
7034 action == ACTION_SNAPPING ||
7035 action == ACTION_COLLECTING);
7036 boolean action_moving = (action == ACTION_FALLING ||
7037 action == ACTION_MOVING ||
7038 action == ACTION_PUSHING ||
7039 action == ACTION_EATING ||
7040 action == ACTION_FILLING ||
7041 action == ACTION_EMPTYING);
7042 boolean action_falling = (action == ACTION_FALLING ||
7043 action == ACTION_FILLING ||
7044 action == ACTION_EMPTYING);
7046 /* special case: graphic uses "2nd movement tile" and has defined
7047 7 frames for movement animation (or less) => use default graphic
7048 for last (8th) frame which ends the movement animation */
7049 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7051 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7052 graphic = (direction == MV_NONE ?
7053 el_act2img(effective_element, action) :
7054 el_act_dir2img(effective_element, action, direction));
7056 g = &graphic_info[graphic];
7059 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7063 else if (action_moving)
7065 boolean is_backside = object_mapping[tile].is_backside;
7069 int direction = object_mapping[tile].direction;
7070 int move_dir = (action_falling ? MV_DOWN : direction);
7075 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7076 if (g->double_movement && frame_em == 0)
7080 if (move_dir == MV_LEFT)
7081 GfxFrame[x - 1][y] = GfxFrame[x][y];
7082 else if (move_dir == MV_RIGHT)
7083 GfxFrame[x + 1][y] = GfxFrame[x][y];
7084 else if (move_dir == MV_UP)
7085 GfxFrame[x][y - 1] = GfxFrame[x][y];
7086 else if (move_dir == MV_DOWN)
7087 GfxFrame[x][y + 1] = GfxFrame[x][y];
7094 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7095 if (tile == Xsand_stonesand_quickout_1 ||
7096 tile == Xsand_stonesand_quickout_2)
7100 if (graphic_info[graphic].anim_global_sync)
7101 sync_frame = FrameCounter;
7102 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7103 sync_frame = GfxFrame[x][y];
7105 sync_frame = 0; /* playfield border (pseudo steel) */
7107 SetRandomAnimationValue(x, y);
7109 int frame = getAnimationFrame(g->anim_frames,
7112 g->anim_start_frame,
7115 g_em->unique_identifier =
7116 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7119 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7120 int tile, int frame_em, int x, int y)
7122 int action = object_mapping[tile].action;
7123 int direction = object_mapping[tile].direction;
7124 boolean is_backside = object_mapping[tile].is_backside;
7125 int effective_element = get_effective_element_EM(tile, frame_em);
7126 int effective_action = action;
7127 int graphic = (direction == MV_NONE ?
7128 el_act2img(effective_element, effective_action) :
7129 el_act_dir2img(effective_element, effective_action,
7131 int crumbled = (direction == MV_NONE ?
7132 el_act2crm(effective_element, effective_action) :
7133 el_act_dir2crm(effective_element, effective_action,
7135 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7136 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7137 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7138 struct GraphicInfo *g = &graphic_info[graphic];
7141 /* special case: graphic uses "2nd movement tile" and has defined
7142 7 frames for movement animation (or less) => use default graphic
7143 for last (8th) frame which ends the movement animation */
7144 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7146 effective_action = ACTION_DEFAULT;
7147 graphic = (direction == MV_NONE ?
7148 el_act2img(effective_element, effective_action) :
7149 el_act_dir2img(effective_element, effective_action,
7151 crumbled = (direction == MV_NONE ?
7152 el_act2crm(effective_element, effective_action) :
7153 el_act_dir2crm(effective_element, effective_action,
7156 g = &graphic_info[graphic];
7159 if (graphic_info[graphic].anim_global_sync)
7160 sync_frame = FrameCounter;
7161 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7162 sync_frame = GfxFrame[x][y];
7164 sync_frame = 0; /* playfield border (pseudo steel) */
7166 SetRandomAnimationValue(x, y);
7168 int frame = getAnimationFrame(g->anim_frames,
7171 g->anim_start_frame,
7174 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7175 g->double_movement && is_backside);
7177 /* (updating the "crumbled" graphic definitions is probably not really needed,
7178 as animations for crumbled graphics can't be longer than one EMC cycle) */
7179 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7183 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7184 int player_nr, int anim, int frame_em)
7186 int element = player_mapping[player_nr][anim].element_rnd;
7187 int action = player_mapping[player_nr][anim].action;
7188 int direction = player_mapping[player_nr][anim].direction;
7189 int graphic = (direction == MV_NONE ?
7190 el_act2img(element, action) :
7191 el_act_dir2img(element, action, direction));
7192 struct GraphicInfo *g = &graphic_info[graphic];
7195 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7197 stored_player[player_nr].StepFrame = frame_em;
7199 sync_frame = stored_player[player_nr].Frame;
7201 int frame = getAnimationFrame(g->anim_frames,
7204 g->anim_start_frame,
7207 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7208 &g_em->src_x, &g_em->src_y, FALSE);
7211 void InitGraphicInfo_EM(void)
7216 int num_em_gfx_errors = 0;
7218 if (graphic_info_em_object[0][0].bitmap == NULL)
7220 /* EM graphics not yet initialized in em_open_all() */
7225 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7228 /* always start with reliable default values */
7229 for (i = 0; i < TILE_MAX; i++)
7231 object_mapping[i].element_rnd = EL_UNKNOWN;
7232 object_mapping[i].is_backside = FALSE;
7233 object_mapping[i].action = ACTION_DEFAULT;
7234 object_mapping[i].direction = MV_NONE;
7237 /* always start with reliable default values */
7238 for (p = 0; p < MAX_PLAYERS; p++)
7240 for (i = 0; i < SPR_MAX; i++)
7242 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7243 player_mapping[p][i].action = ACTION_DEFAULT;
7244 player_mapping[p][i].direction = MV_NONE;
7248 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7250 int e = em_object_mapping_list[i].element_em;
7252 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7253 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7255 if (em_object_mapping_list[i].action != -1)
7256 object_mapping[e].action = em_object_mapping_list[i].action;
7258 if (em_object_mapping_list[i].direction != -1)
7259 object_mapping[e].direction =
7260 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7263 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7265 int a = em_player_mapping_list[i].action_em;
7266 int p = em_player_mapping_list[i].player_nr;
7268 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7270 if (em_player_mapping_list[i].action != -1)
7271 player_mapping[p][a].action = em_player_mapping_list[i].action;
7273 if (em_player_mapping_list[i].direction != -1)
7274 player_mapping[p][a].direction =
7275 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7278 for (i = 0; i < TILE_MAX; i++)
7280 int element = object_mapping[i].element_rnd;
7281 int action = object_mapping[i].action;
7282 int direction = object_mapping[i].direction;
7283 boolean is_backside = object_mapping[i].is_backside;
7284 boolean action_exploding = ((action == ACTION_EXPLODING ||
7285 action == ACTION_SMASHED_BY_ROCK ||
7286 action == ACTION_SMASHED_BY_SPRING) &&
7287 element != EL_DIAMOND);
7288 boolean action_active = (action == ACTION_ACTIVE);
7289 boolean action_other = (action == ACTION_OTHER);
7291 for (j = 0; j < 8; j++)
7293 int effective_element = get_effective_element_EM(i, j);
7294 int effective_action = (j < 7 ? action :
7295 i == Xdrip_stretch ? action :
7296 i == Xdrip_stretchB ? action :
7297 i == Ydrip_s1 ? action :
7298 i == Ydrip_s1B ? action :
7299 i == Xball_1B ? action :
7300 i == Xball_2 ? action :
7301 i == Xball_2B ? action :
7302 i == Yball_eat ? action :
7303 i == Ykey_1_eat ? action :
7304 i == Ykey_2_eat ? action :
7305 i == Ykey_3_eat ? action :
7306 i == Ykey_4_eat ? action :
7307 i == Ykey_5_eat ? action :
7308 i == Ykey_6_eat ? action :
7309 i == Ykey_7_eat ? action :
7310 i == Ykey_8_eat ? action :
7311 i == Ylenses_eat ? action :
7312 i == Ymagnify_eat ? action :
7313 i == Ygrass_eat ? action :
7314 i == Ydirt_eat ? action :
7315 i == Xsand_stonein_1 ? action :
7316 i == Xsand_stonein_2 ? action :
7317 i == Xsand_stonein_3 ? action :
7318 i == Xsand_stonein_4 ? action :
7319 i == Xsand_stoneout_1 ? action :
7320 i == Xsand_stoneout_2 ? action :
7321 i == Xboom_android ? ACTION_EXPLODING :
7322 action_exploding ? ACTION_EXPLODING :
7323 action_active ? action :
7324 action_other ? action :
7326 int graphic = (el_act_dir2img(effective_element, effective_action,
7328 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7330 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7331 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7332 boolean has_action_graphics = (graphic != base_graphic);
7333 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7334 struct GraphicInfo *g = &graphic_info[graphic];
7335 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7338 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7339 boolean special_animation = (action != ACTION_DEFAULT &&
7340 g->anim_frames == 3 &&
7341 g->anim_delay == 2 &&
7342 g->anim_mode & ANIM_LINEAR);
7343 int sync_frame = (i == Xdrip_stretch ? 7 :
7344 i == Xdrip_stretchB ? 7 :
7345 i == Ydrip_s2 ? j + 8 :
7346 i == Ydrip_s2B ? j + 8 :
7355 i == Xfake_acid_1 ? 0 :
7356 i == Xfake_acid_2 ? 10 :
7357 i == Xfake_acid_3 ? 20 :
7358 i == Xfake_acid_4 ? 30 :
7359 i == Xfake_acid_5 ? 40 :
7360 i == Xfake_acid_6 ? 50 :
7361 i == Xfake_acid_7 ? 60 :
7362 i == Xfake_acid_8 ? 70 :
7364 i == Xball_2B ? j + 8 :
7365 i == Yball_eat ? j + 1 :
7366 i == Ykey_1_eat ? j + 1 :
7367 i == Ykey_2_eat ? j + 1 :
7368 i == Ykey_3_eat ? j + 1 :
7369 i == Ykey_4_eat ? j + 1 :
7370 i == Ykey_5_eat ? j + 1 :
7371 i == Ykey_6_eat ? j + 1 :
7372 i == Ykey_7_eat ? j + 1 :
7373 i == Ykey_8_eat ? j + 1 :
7374 i == Ylenses_eat ? j + 1 :
7375 i == Ymagnify_eat ? j + 1 :
7376 i == Ygrass_eat ? j + 1 :
7377 i == Ydirt_eat ? j + 1 :
7378 i == Xamoeba_1 ? 0 :
7379 i == Xamoeba_2 ? 1 :
7380 i == Xamoeba_3 ? 2 :
7381 i == Xamoeba_4 ? 3 :
7382 i == Xamoeba_5 ? 0 :
7383 i == Xamoeba_6 ? 1 :
7384 i == Xamoeba_7 ? 2 :
7385 i == Xamoeba_8 ? 3 :
7386 i == Xexit_2 ? j + 8 :
7387 i == Xexit_3 ? j + 16 :
7388 i == Xdynamite_1 ? 0 :
7389 i == Xdynamite_2 ? 8 :
7390 i == Xdynamite_3 ? 16 :
7391 i == Xdynamite_4 ? 24 :
7392 i == Xsand_stonein_1 ? j + 1 :
7393 i == Xsand_stonein_2 ? j + 9 :
7394 i == Xsand_stonein_3 ? j + 17 :
7395 i == Xsand_stonein_4 ? j + 25 :
7396 i == Xsand_stoneout_1 && j == 0 ? 0 :
7397 i == Xsand_stoneout_1 && j == 1 ? 0 :
7398 i == Xsand_stoneout_1 && j == 2 ? 1 :
7399 i == Xsand_stoneout_1 && j == 3 ? 2 :
7400 i == Xsand_stoneout_1 && j == 4 ? 2 :
7401 i == Xsand_stoneout_1 && j == 5 ? 3 :
7402 i == Xsand_stoneout_1 && j == 6 ? 4 :
7403 i == Xsand_stoneout_1 && j == 7 ? 4 :
7404 i == Xsand_stoneout_2 && j == 0 ? 5 :
7405 i == Xsand_stoneout_2 && j == 1 ? 6 :
7406 i == Xsand_stoneout_2 && j == 2 ? 7 :
7407 i == Xsand_stoneout_2 && j == 3 ? 8 :
7408 i == Xsand_stoneout_2 && j == 4 ? 9 :
7409 i == Xsand_stoneout_2 && j == 5 ? 11 :
7410 i == Xsand_stoneout_2 && j == 6 ? 13 :
7411 i == Xsand_stoneout_2 && j == 7 ? 15 :
7412 i == Xboom_bug && j == 1 ? 2 :
7413 i == Xboom_bug && j == 2 ? 2 :
7414 i == Xboom_bug && j == 3 ? 4 :
7415 i == Xboom_bug && j == 4 ? 4 :
7416 i == Xboom_bug && j == 5 ? 2 :
7417 i == Xboom_bug && j == 6 ? 2 :
7418 i == Xboom_bug && j == 7 ? 0 :
7419 i == Xboom_bomb && j == 1 ? 2 :
7420 i == Xboom_bomb && j == 2 ? 2 :
7421 i == Xboom_bomb && j == 3 ? 4 :
7422 i == Xboom_bomb && j == 4 ? 4 :
7423 i == Xboom_bomb && j == 5 ? 2 :
7424 i == Xboom_bomb && j == 6 ? 2 :
7425 i == Xboom_bomb && j == 7 ? 0 :
7426 i == Xboom_android && j == 7 ? 6 :
7427 i == Xboom_1 && j == 1 ? 2 :
7428 i == Xboom_1 && j == 2 ? 2 :
7429 i == Xboom_1 && j == 3 ? 4 :
7430 i == Xboom_1 && j == 4 ? 4 :
7431 i == Xboom_1 && j == 5 ? 6 :
7432 i == Xboom_1 && j == 6 ? 6 :
7433 i == Xboom_1 && j == 7 ? 8 :
7434 i == Xboom_2 && j == 0 ? 8 :
7435 i == Xboom_2 && j == 1 ? 8 :
7436 i == Xboom_2 && j == 2 ? 10 :
7437 i == Xboom_2 && j == 3 ? 10 :
7438 i == Xboom_2 && j == 4 ? 10 :
7439 i == Xboom_2 && j == 5 ? 12 :
7440 i == Xboom_2 && j == 6 ? 12 :
7441 i == Xboom_2 && j == 7 ? 12 :
7442 special_animation && j == 4 ? 3 :
7443 effective_action != action ? 0 :
7447 Bitmap *debug_bitmap = g_em->bitmap;
7448 int debug_src_x = g_em->src_x;
7449 int debug_src_y = g_em->src_y;
7452 int frame = getAnimationFrame(g->anim_frames,
7455 g->anim_start_frame,
7458 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7459 g->double_movement && is_backside);
7461 g_em->bitmap = src_bitmap;
7462 g_em->src_x = src_x;
7463 g_em->src_y = src_y;
7464 g_em->src_offset_x = 0;
7465 g_em->src_offset_y = 0;
7466 g_em->dst_offset_x = 0;
7467 g_em->dst_offset_y = 0;
7468 g_em->width = TILEX;
7469 g_em->height = TILEY;
7471 g_em->preserve_background = FALSE;
7473 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7476 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7477 effective_action == ACTION_MOVING ||
7478 effective_action == ACTION_PUSHING ||
7479 effective_action == ACTION_EATING)) ||
7480 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7481 effective_action == ACTION_EMPTYING)))
7484 (effective_action == ACTION_FALLING ||
7485 effective_action == ACTION_FILLING ||
7486 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7487 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7488 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7489 int num_steps = (i == Ydrip_s1 ? 16 :
7490 i == Ydrip_s1B ? 16 :
7491 i == Ydrip_s2 ? 16 :
7492 i == Ydrip_s2B ? 16 :
7493 i == Xsand_stonein_1 ? 32 :
7494 i == Xsand_stonein_2 ? 32 :
7495 i == Xsand_stonein_3 ? 32 :
7496 i == Xsand_stonein_4 ? 32 :
7497 i == Xsand_stoneout_1 ? 16 :
7498 i == Xsand_stoneout_2 ? 16 : 8);
7499 int cx = ABS(dx) * (TILEX / num_steps);
7500 int cy = ABS(dy) * (TILEY / num_steps);
7501 int step_frame = (i == Ydrip_s2 ? j + 8 :
7502 i == Ydrip_s2B ? j + 8 :
7503 i == Xsand_stonein_2 ? j + 8 :
7504 i == Xsand_stonein_3 ? j + 16 :
7505 i == Xsand_stonein_4 ? j + 24 :
7506 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7507 int step = (is_backside ? step_frame : num_steps - step_frame);
7509 if (is_backside) /* tile where movement starts */
7511 if (dx < 0 || dy < 0)
7513 g_em->src_offset_x = cx * step;
7514 g_em->src_offset_y = cy * step;
7518 g_em->dst_offset_x = cx * step;
7519 g_em->dst_offset_y = cy * step;
7522 else /* tile where movement ends */
7524 if (dx < 0 || dy < 0)
7526 g_em->dst_offset_x = cx * step;
7527 g_em->dst_offset_y = cy * step;
7531 g_em->src_offset_x = cx * step;
7532 g_em->src_offset_y = cy * step;
7536 g_em->width = TILEX - cx * step;
7537 g_em->height = TILEY - cy * step;
7540 /* create unique graphic identifier to decide if tile must be redrawn */
7541 /* bit 31 - 16 (16 bit): EM style graphic
7542 bit 15 - 12 ( 4 bit): EM style frame
7543 bit 11 - 6 ( 6 bit): graphic width
7544 bit 5 - 0 ( 6 bit): graphic height */
7545 g_em->unique_identifier =
7546 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7550 /* skip check for EMC elements not contained in original EMC artwork */
7551 if (element == EL_EMC_FAKE_ACID)
7554 if (g_em->bitmap != debug_bitmap ||
7555 g_em->src_x != debug_src_x ||
7556 g_em->src_y != debug_src_y ||
7557 g_em->src_offset_x != 0 ||
7558 g_em->src_offset_y != 0 ||
7559 g_em->dst_offset_x != 0 ||
7560 g_em->dst_offset_y != 0 ||
7561 g_em->width != TILEX ||
7562 g_em->height != TILEY)
7564 static int last_i = -1;
7572 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7573 i, element, element_info[element].token_name,
7574 element_action_info[effective_action].suffix, direction);
7576 if (element != effective_element)
7577 printf(" [%d ('%s')]",
7579 element_info[effective_element].token_name);
7583 if (g_em->bitmap != debug_bitmap)
7584 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7585 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7587 if (g_em->src_x != debug_src_x ||
7588 g_em->src_y != debug_src_y)
7589 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7590 j, (is_backside ? 'B' : 'F'),
7591 g_em->src_x, g_em->src_y,
7592 g_em->src_x / 32, g_em->src_y / 32,
7593 debug_src_x, debug_src_y,
7594 debug_src_x / 32, debug_src_y / 32);
7596 if (g_em->src_offset_x != 0 ||
7597 g_em->src_offset_y != 0 ||
7598 g_em->dst_offset_x != 0 ||
7599 g_em->dst_offset_y != 0)
7600 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7602 g_em->src_offset_x, g_em->src_offset_y,
7603 g_em->dst_offset_x, g_em->dst_offset_y);
7605 if (g_em->width != TILEX ||
7606 g_em->height != TILEY)
7607 printf(" %d (%d): size %d,%d should be %d,%d\n",
7609 g_em->width, g_em->height, TILEX, TILEY);
7611 num_em_gfx_errors++;
7618 for (i = 0; i < TILE_MAX; i++)
7620 for (j = 0; j < 8; j++)
7622 int element = object_mapping[i].element_rnd;
7623 int action = object_mapping[i].action;
7624 int direction = object_mapping[i].direction;
7625 boolean is_backside = object_mapping[i].is_backside;
7626 int graphic_action = el_act_dir2img(element, action, direction);
7627 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7629 if ((action == ACTION_SMASHED_BY_ROCK ||
7630 action == ACTION_SMASHED_BY_SPRING ||
7631 action == ACTION_EATING) &&
7632 graphic_action == graphic_default)
7634 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7635 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7636 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7637 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7640 /* no separate animation for "smashed by rock" -- use rock instead */
7641 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7642 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7644 g_em->bitmap = g_xx->bitmap;
7645 g_em->src_x = g_xx->src_x;
7646 g_em->src_y = g_xx->src_y;
7647 g_em->src_offset_x = g_xx->src_offset_x;
7648 g_em->src_offset_y = g_xx->src_offset_y;
7649 g_em->dst_offset_x = g_xx->dst_offset_x;
7650 g_em->dst_offset_y = g_xx->dst_offset_y;
7651 g_em->width = g_xx->width;
7652 g_em->height = g_xx->height;
7653 g_em->unique_identifier = g_xx->unique_identifier;
7656 g_em->preserve_background = TRUE;
7661 for (p = 0; p < MAX_PLAYERS; p++)
7663 for (i = 0; i < SPR_MAX; i++)
7665 int element = player_mapping[p][i].element_rnd;
7666 int action = player_mapping[p][i].action;
7667 int direction = player_mapping[p][i].direction;
7669 for (j = 0; j < 8; j++)
7671 int effective_element = element;
7672 int effective_action = action;
7673 int graphic = (direction == MV_NONE ?
7674 el_act2img(effective_element, effective_action) :
7675 el_act_dir2img(effective_element, effective_action,
7677 struct GraphicInfo *g = &graphic_info[graphic];
7678 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7684 Bitmap *debug_bitmap = g_em->bitmap;
7685 int debug_src_x = g_em->src_x;
7686 int debug_src_y = g_em->src_y;
7689 int frame = getAnimationFrame(g->anim_frames,
7692 g->anim_start_frame,
7695 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7697 g_em->bitmap = src_bitmap;
7698 g_em->src_x = src_x;
7699 g_em->src_y = src_y;
7700 g_em->src_offset_x = 0;
7701 g_em->src_offset_y = 0;
7702 g_em->dst_offset_x = 0;
7703 g_em->dst_offset_y = 0;
7704 g_em->width = TILEX;
7705 g_em->height = TILEY;
7709 /* skip check for EMC elements not contained in original EMC artwork */
7710 if (element == EL_PLAYER_3 ||
7711 element == EL_PLAYER_4)
7714 if (g_em->bitmap != debug_bitmap ||
7715 g_em->src_x != debug_src_x ||
7716 g_em->src_y != debug_src_y)
7718 static int last_i = -1;
7726 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7727 p, i, element, element_info[element].token_name,
7728 element_action_info[effective_action].suffix, direction);
7730 if (element != effective_element)
7731 printf(" [%d ('%s')]",
7733 element_info[effective_element].token_name);
7737 if (g_em->bitmap != debug_bitmap)
7738 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7739 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7741 if (g_em->src_x != debug_src_x ||
7742 g_em->src_y != debug_src_y)
7743 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7745 g_em->src_x, g_em->src_y,
7746 g_em->src_x / 32, g_em->src_y / 32,
7747 debug_src_x, debug_src_y,
7748 debug_src_x / 32, debug_src_y / 32);
7750 num_em_gfx_errors++;
7760 printf("::: [%d errors found]\n", num_em_gfx_errors);
7766 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7767 boolean any_player_moving,
7768 boolean player_is_dropping)
7770 if (tape.single_step && tape.recording && !tape.pausing)
7771 if (frame == 0 && !player_is_dropping)
7772 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7775 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7776 boolean murphy_is_dropping)
7778 if (tape.single_step && tape.recording && !tape.pausing)
7779 if (murphy_is_waiting)
7780 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7783 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7784 int graphic, int sync_frame, int x, int y)
7786 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7788 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7791 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7793 return (IS_NEXT_FRAME(sync_frame, graphic));
7796 int getGraphicInfo_Delay(int graphic)
7798 return graphic_info[graphic].anim_delay;
7801 void PlayMenuSoundExt(int sound)
7803 if (sound == SND_UNDEFINED)
7806 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7807 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7810 if (IS_LOOP_SOUND(sound))
7811 PlaySoundLoop(sound);
7816 void PlayMenuSound()
7818 PlayMenuSoundExt(menu.sound[game_status]);
7821 void PlayMenuSoundStereo(int sound, int stereo_position)
7823 if (sound == SND_UNDEFINED)
7826 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7827 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7830 if (IS_LOOP_SOUND(sound))
7831 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7833 PlaySoundStereo(sound, stereo_position);
7836 void PlayMenuSoundIfLoopExt(int sound)
7838 if (sound == SND_UNDEFINED)
7841 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7842 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7845 if (IS_LOOP_SOUND(sound))
7846 PlaySoundLoop(sound);
7849 void PlayMenuSoundIfLoop()
7851 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7854 void PlayMenuMusicExt(int music)
7856 if (music == MUS_UNDEFINED)
7859 if (!setup.sound_music)
7865 void PlayMenuMusic()
7867 PlayMenuMusicExt(menu.music[game_status]);
7870 void PlaySoundActivating()
7873 PlaySound(SND_MENU_ITEM_ACTIVATING);
7877 void PlaySoundSelecting()
7880 PlaySound(SND_MENU_ITEM_SELECTING);
7884 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7886 boolean change_fullscreen = (setup.fullscreen !=
7887 video.fullscreen_enabled);
7888 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7889 !strEqual(setup.fullscreen_mode,
7890 video.fullscreen_mode_current));
7891 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7892 setup.window_scaling_percent !=
7893 video.window_scaling_percent);
7895 if (change_window_scaling_percent && video.fullscreen_enabled)
7898 if (!change_window_scaling_percent && !video.fullscreen_available)
7901 #if defined(TARGET_SDL2)
7902 if (change_window_scaling_percent)
7904 SDLSetWindowScaling(setup.window_scaling_percent);
7908 else if (change_fullscreen)
7910 SDLSetWindowFullscreen(setup.fullscreen);
7912 /* set setup value according to successfully changed fullscreen mode */
7913 setup.fullscreen = video.fullscreen_enabled;
7919 if (change_fullscreen ||
7920 change_fullscreen_mode ||
7921 change_window_scaling_percent)
7923 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7925 /* save backbuffer content which gets lost when toggling fullscreen mode */
7926 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7928 if (change_fullscreen_mode)
7930 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7931 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7934 if (change_window_scaling_percent)
7936 /* keep window mode, but change window scaling */
7937 video.fullscreen_enabled = TRUE; /* force new window scaling */
7940 /* toggle fullscreen */
7941 ChangeVideoModeIfNeeded(setup.fullscreen);
7943 /* set setup value according to successfully changed fullscreen mode */
7944 setup.fullscreen = video.fullscreen_enabled;
7946 /* restore backbuffer content from temporary backbuffer backup bitmap */
7947 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7949 FreeBitmap(tmp_backbuffer);
7951 /* update visible window/screen */
7952 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7956 void ChangeViewportPropertiesIfNeeded()
7958 int gfx_game_mode = game_status;
7959 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7961 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7962 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7963 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7964 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7965 int border_size = vp_playfield->border_size;
7966 int new_sx = vp_playfield->x + border_size;
7967 int new_sy = vp_playfield->y + border_size;
7968 int new_sxsize = vp_playfield->width - 2 * border_size;
7969 int new_sysize = vp_playfield->height - 2 * border_size;
7970 int new_real_sx = vp_playfield->x;
7971 int new_real_sy = vp_playfield->y;
7972 int new_full_sxsize = vp_playfield->width;
7973 int new_full_sysize = vp_playfield->height;
7974 int new_dx = vp_door_1->x;
7975 int new_dy = vp_door_1->y;
7976 int new_dxsize = vp_door_1->width;
7977 int new_dysize = vp_door_1->height;
7978 int new_vx = vp_door_2->x;
7979 int new_vy = vp_door_2->y;
7980 int new_vxsize = vp_door_2->width;
7981 int new_vysize = vp_door_2->height;
7982 int new_ex = vp_door_3->x;
7983 int new_ey = vp_door_3->y;
7984 int new_exsize = vp_door_3->width;
7985 int new_eysize = vp_door_3->height;
7986 int new_tilesize_var =
7987 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
7989 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
7990 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
7991 int new_scr_fieldx = new_sxsize / tilesize;
7992 int new_scr_fieldy = new_sysize / tilesize;
7993 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
7994 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
7995 boolean init_gfx_buffers = FALSE;
7996 boolean init_video_buffer = FALSE;
7997 boolean init_gadgets_and_toons = FALSE;
7998 boolean init_em_graphics = FALSE;
8000 if (viewport.window.width != WIN_XSIZE ||
8001 viewport.window.height != WIN_YSIZE)
8003 WIN_XSIZE = viewport.window.width;
8004 WIN_YSIZE = viewport.window.height;
8006 init_video_buffer = TRUE;
8007 init_gfx_buffers = TRUE;
8009 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8012 if (new_scr_fieldx != SCR_FIELDX ||
8013 new_scr_fieldy != SCR_FIELDY)
8015 /* this always toggles between MAIN and GAME when using small tile size */
8017 SCR_FIELDX = new_scr_fieldx;
8018 SCR_FIELDY = new_scr_fieldy;
8020 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8031 new_sxsize != SXSIZE ||
8032 new_sysize != SYSIZE ||
8033 new_dxsize != DXSIZE ||
8034 new_dysize != DYSIZE ||
8035 new_vxsize != VXSIZE ||
8036 new_vysize != VYSIZE ||
8037 new_exsize != EXSIZE ||
8038 new_eysize != EYSIZE ||
8039 new_real_sx != REAL_SX ||
8040 new_real_sy != REAL_SY ||
8041 new_full_sxsize != FULL_SXSIZE ||
8042 new_full_sysize != FULL_SYSIZE ||
8043 new_tilesize_var != TILESIZE_VAR
8046 if (new_tilesize_var != TILESIZE_VAR)
8048 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8050 // changing tile size invalidates scroll values of engine snapshots
8051 FreeEngineSnapshot();
8053 // changing tile size requires update of graphic mapping for EM engine
8054 init_em_graphics = TRUE;
8065 SXSIZE = new_sxsize;
8066 SYSIZE = new_sysize;
8067 DXSIZE = new_dxsize;
8068 DYSIZE = new_dysize;
8069 VXSIZE = new_vxsize;
8070 VYSIZE = new_vysize;
8071 EXSIZE = new_exsize;
8072 EYSIZE = new_eysize;
8073 REAL_SX = new_real_sx;
8074 REAL_SY = new_real_sy;
8075 FULL_SXSIZE = new_full_sxsize;
8076 FULL_SYSIZE = new_full_sysize;
8077 TILESIZE_VAR = new_tilesize_var;
8079 init_gfx_buffers = TRUE;
8080 init_gadgets_and_toons = TRUE;
8082 // printf("::: viewports: init_gfx_buffers\n");
8083 // printf("::: viewports: init_gadgets_and_toons\n");
8086 if (init_gfx_buffers)
8088 // printf("::: init_gfx_buffers\n");
8090 SCR_FIELDX = new_scr_fieldx_buffers;
8091 SCR_FIELDY = new_scr_fieldy_buffers;
8095 SCR_FIELDX = new_scr_fieldx;
8096 SCR_FIELDY = new_scr_fieldy;
8099 if (init_video_buffer)
8101 // printf("::: init_video_buffer\n");
8103 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8105 SetDrawDeactivationMask(REDRAW_NONE);
8106 SetDrawBackgroundMask(REDRAW_FIELD);
8109 if (init_gadgets_and_toons)
8111 // printf("::: init_gadgets_and_toons\n");
8117 if (init_em_graphics)
8119 InitGraphicInfo_EM();