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 no in-game graphics defined, always use standard graphic size
1056 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
1057 tilesize = TILESIZE;
1059 if (tilesize == gfx.standard_tile_size)
1060 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
1061 else if (tilesize == game.tile_size)
1062 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
1064 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
1066 if (g->offset_y == 0) /* frames are ordered horizontally */
1068 int max_width = g->anim_frames_per_line * g->width;
1069 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1071 src_x = pos % max_width;
1072 src_y = src_y % g->height + pos / max_width * g->height;
1074 else if (g->offset_x == 0) /* frames are ordered vertically */
1076 int max_height = g->anim_frames_per_line * g->height;
1077 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1079 src_x = src_x % g->width + pos / max_height * g->width;
1080 src_y = pos % max_height;
1082 else /* frames are ordered diagonally */
1084 src_x = src_x + frame * g->offset_x;
1085 src_y = src_y + frame * g->offset_y;
1088 *bitmap = src_bitmap;
1089 *x = src_x * tilesize / TILESIZE;
1090 *y = src_y * tilesize / TILESIZE;
1093 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1094 int *x, int *y, boolean get_backside)
1096 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1100 void getSizedGraphicSource(int graphic, int frame, int tilesize,
1101 Bitmap **bitmap, int *x, int *y)
1103 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1106 void getFixedGraphicSource(int graphic, int frame,
1107 Bitmap **bitmap, int *x, int *y)
1109 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1112 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1114 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1117 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1118 int *x, int *y, boolean get_backside)
1120 struct GraphicInfo *g = &graphic_info[graphic];
1121 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1122 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1124 if (TILESIZE_VAR != TILESIZE)
1125 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1128 *bitmap = g->bitmap;
1130 if (g->offset_y == 0) /* frames are ordered horizontally */
1132 int max_width = g->anim_frames_per_line * g->width;
1133 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1135 *x = pos % max_width;
1136 *y = src_y % g->height + pos / max_width * g->height;
1138 else if (g->offset_x == 0) /* frames are ordered vertically */
1140 int max_height = g->anim_frames_per_line * g->height;
1141 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1143 *x = src_x % g->width + pos / max_height * g->width;
1144 *y = pos % max_height;
1146 else /* frames are ordered diagonally */
1148 *x = src_x + frame * g->offset_x;
1149 *y = src_y + frame * g->offset_y;
1153 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1155 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1158 void DrawGraphic(int x, int y, int graphic, int frame)
1161 if (!IN_SCR_FIELD(x, y))
1163 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1164 printf("DrawGraphic(): This should never happen!\n");
1169 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1172 MarkTileDirty(x, y);
1175 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1178 if (!IN_SCR_FIELD(x, y))
1180 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1181 printf("DrawGraphic(): This should never happen!\n");
1186 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1188 MarkTileDirty(x, y);
1191 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1197 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1199 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1202 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1208 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1209 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1212 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1215 if (!IN_SCR_FIELD(x, y))
1217 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1218 printf("DrawGraphicThruMask(): This should never happen!\n");
1223 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1226 MarkTileDirty(x, y);
1229 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1232 if (!IN_SCR_FIELD(x, y))
1234 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1235 printf("DrawGraphicThruMask(): This should never happen!\n");
1240 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1242 MarkTileDirty(x, y);
1245 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1251 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1253 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1257 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1258 int graphic, int frame)
1260 struct GraphicInfo *g = &graphic_info[graphic];
1264 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1266 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1270 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1272 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1274 MarkTileDirty(x / tilesize, y / tilesize);
1277 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1283 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1284 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1287 void DrawMiniGraphic(int x, int y, int graphic)
1289 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1290 MarkTileDirty(x / 2, y / 2);
1293 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1298 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1299 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1302 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1303 int graphic, int frame,
1304 int cut_mode, int mask_mode)
1309 int width = TILEX, height = TILEY;
1312 if (dx || dy) /* shifted graphic */
1314 if (x < BX1) /* object enters playfield from the left */
1321 else if (x > BX2) /* object enters playfield from the right */
1327 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1333 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1335 else if (dx) /* general horizontal movement */
1336 MarkTileDirty(x + SIGN(dx), y);
1338 if (y < BY1) /* object enters playfield from the top */
1340 if (cut_mode==CUT_BELOW) /* object completely above top border */
1348 else if (y > BY2) /* object enters playfield from the bottom */
1354 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1360 else if (dy > 0 && cut_mode == CUT_ABOVE)
1362 if (y == BY2) /* object completely above bottom border */
1368 MarkTileDirty(x, y + 1);
1369 } /* object leaves playfield to the bottom */
1370 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1372 else if (dy) /* general vertical movement */
1373 MarkTileDirty(x, y + SIGN(dy));
1377 if (!IN_SCR_FIELD(x, y))
1379 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1380 printf("DrawGraphicShifted(): This should never happen!\n");
1385 width = width * TILESIZE_VAR / TILESIZE;
1386 height = height * TILESIZE_VAR / TILESIZE;
1387 cx = cx * TILESIZE_VAR / TILESIZE;
1388 cy = cy * TILESIZE_VAR / TILESIZE;
1389 dx = dx * TILESIZE_VAR / TILESIZE;
1390 dy = dy * TILESIZE_VAR / TILESIZE;
1392 if (width > 0 && height > 0)
1394 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1399 dst_x = FX + x * TILEX_VAR + dx;
1400 dst_y = FY + y * TILEY_VAR + dy;
1402 if (mask_mode == USE_MASKING)
1403 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1406 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1409 MarkTileDirty(x, y);
1413 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1414 int graphic, int frame,
1415 int cut_mode, int mask_mode)
1420 int width = TILEX_VAR, height = TILEY_VAR;
1423 int x2 = x + SIGN(dx);
1424 int y2 = y + SIGN(dy);
1426 /* movement with two-tile animations must be sync'ed with movement position,
1427 not with current GfxFrame (which can be higher when using slow movement) */
1428 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1429 int anim_frames = graphic_info[graphic].anim_frames;
1431 /* (we also need anim_delay here for movement animations with less frames) */
1432 int anim_delay = graphic_info[graphic].anim_delay;
1433 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1435 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1436 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1438 /* re-calculate animation frame for two-tile movement animation */
1439 frame = getGraphicAnimationFrame(graphic, sync_frame);
1441 /* check if movement start graphic inside screen area and should be drawn */
1442 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1444 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1446 dst_x = FX + x1 * TILEX_VAR;
1447 dst_y = FY + y1 * TILEY_VAR;
1449 if (mask_mode == USE_MASKING)
1450 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1453 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1456 MarkTileDirty(x1, y1);
1459 /* check if movement end graphic inside screen area and should be drawn */
1460 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1462 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1464 dst_x = FX + x2 * TILEX_VAR;
1465 dst_y = FY + y2 * TILEY_VAR;
1467 if (mask_mode == USE_MASKING)
1468 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1471 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1474 MarkTileDirty(x2, y2);
1478 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1479 int graphic, int frame,
1480 int cut_mode, int mask_mode)
1484 DrawGraphic(x, y, graphic, frame);
1489 if (graphic_info[graphic].double_movement) /* EM style movement images */
1490 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1492 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1495 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1496 int frame, int cut_mode)
1498 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1501 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1502 int cut_mode, int mask_mode)
1504 int lx = LEVELX(x), ly = LEVELY(y);
1508 if (IN_LEV_FIELD(lx, ly))
1510 SetRandomAnimationValue(lx, ly);
1512 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1513 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1515 /* do not use double (EM style) movement graphic when not moving */
1516 if (graphic_info[graphic].double_movement && !dx && !dy)
1518 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1519 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1522 else /* border element */
1524 graphic = el2img(element);
1525 frame = getGraphicAnimationFrame(graphic, -1);
1528 if (element == EL_EXPANDABLE_WALL)
1530 boolean left_stopped = FALSE, right_stopped = FALSE;
1532 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1533 left_stopped = TRUE;
1534 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1535 right_stopped = TRUE;
1537 if (left_stopped && right_stopped)
1539 else if (left_stopped)
1541 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1542 frame = graphic_info[graphic].anim_frames - 1;
1544 else if (right_stopped)
1546 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1547 frame = graphic_info[graphic].anim_frames - 1;
1552 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1553 else if (mask_mode == USE_MASKING)
1554 DrawGraphicThruMask(x, y, graphic, frame);
1556 DrawGraphic(x, y, graphic, frame);
1559 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1560 int cut_mode, int mask_mode)
1562 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1563 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1564 cut_mode, mask_mode);
1567 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1570 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1573 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1576 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1579 void DrawLevelElementThruMask(int x, int y, int element)
1581 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1584 void DrawLevelFieldThruMask(int x, int y)
1586 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1589 /* !!! implementation of quicksand is totally broken !!! */
1590 #define IS_CRUMBLED_TILE(x, y, e) \
1591 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1592 !IS_MOVING(x, y) || \
1593 (e) == EL_QUICKSAND_EMPTYING || \
1594 (e) == EL_QUICKSAND_FAST_EMPTYING))
1596 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1601 int width, height, cx, cy;
1602 int sx = SCREENX(x), sy = SCREENY(y);
1603 int crumbled_border_size = graphic_info[graphic].border_size;
1606 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1608 for (i = 1; i < 4; i++)
1610 int dxx = (i & 1 ? dx : 0);
1611 int dyy = (i & 2 ? dy : 0);
1614 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1617 /* check if neighbour field is of same crumble type */
1618 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1619 graphic_info[graphic].class ==
1620 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1622 /* return if check prevents inner corner */
1623 if (same == (dxx == dx && dyy == dy))
1627 /* if we reach this point, we have an inner corner */
1629 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1631 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1632 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1633 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1634 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1636 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1637 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1640 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1645 int width, height, bx, by, cx, cy;
1646 int sx = SCREENX(x), sy = SCREENY(y);
1647 int crumbled_border_size = graphic_info[graphic].border_size;
1648 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1649 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1652 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1654 /* draw simple, sloppy, non-corner-accurate crumbled border */
1656 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1657 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1658 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1659 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1661 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1662 FX + sx * TILEX_VAR + cx,
1663 FY + sy * TILEY_VAR + cy);
1665 /* (remaining middle border part must be at least as big as corner part) */
1666 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1667 crumbled_border_size >= TILESIZE / 3)
1670 /* correct corners of crumbled border, if needed */
1672 for (i = -1; i <= 1; i += 2)
1674 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1675 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1676 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1679 /* check if neighbour field is of same crumble type */
1680 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1681 graphic_info[graphic].class ==
1682 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1684 /* no crumbled corner, but continued crumbled border */
1686 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1687 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1688 int b1 = (i == 1 ? crumbled_border_size_var :
1689 TILESIZE_VAR - 2 * crumbled_border_size_var);
1691 width = crumbled_border_size_var;
1692 height = crumbled_border_size_var;
1694 if (dir == 1 || dir == 2)
1709 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1711 FX + sx * TILEX_VAR + cx,
1712 FY + sy * TILEY_VAR + cy);
1717 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1719 int sx = SCREENX(x), sy = SCREENY(y);
1722 static int xy[4][2] =
1730 if (!IN_LEV_FIELD(x, y))
1733 element = TILE_GFX_ELEMENT(x, y);
1735 /* crumble field itself */
1736 if (IS_CRUMBLED_TILE(x, y, element))
1738 if (!IN_SCR_FIELD(sx, sy))
1741 for (i = 0; i < 4; i++)
1743 int xx = x + xy[i][0];
1744 int yy = y + xy[i][1];
1746 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1749 /* check if neighbour field is of same crumble type */
1750 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1751 graphic_info[graphic].class ==
1752 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1755 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1758 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1759 graphic_info[graphic].anim_frames == 2)
1761 for (i = 0; i < 4; i++)
1763 int dx = (i & 1 ? +1 : -1);
1764 int dy = (i & 2 ? +1 : -1);
1766 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1770 MarkTileDirty(sx, sy);
1772 else /* center field not crumbled -- crumble neighbour fields */
1774 for (i = 0; i < 4; i++)
1776 int xx = x + xy[i][0];
1777 int yy = y + xy[i][1];
1778 int sxx = sx + xy[i][0];
1779 int syy = sy + xy[i][1];
1781 if (!IN_LEV_FIELD(xx, yy) ||
1782 !IN_SCR_FIELD(sxx, syy))
1785 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1788 element = TILE_GFX_ELEMENT(xx, yy);
1790 if (!IS_CRUMBLED_TILE(xx, yy, element))
1793 graphic = el_act2crm(element, ACTION_DEFAULT);
1795 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1797 MarkTileDirty(sxx, syy);
1802 void DrawLevelFieldCrumbled(int x, int y)
1806 if (!IN_LEV_FIELD(x, y))
1809 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1810 GfxElement[x][y] != EL_UNDEFINED &&
1811 GFX_CRUMBLED(GfxElement[x][y]))
1813 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1818 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1820 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1823 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1826 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1827 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1828 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1829 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1830 int sx = SCREENX(x), sy = SCREENY(y);
1832 DrawGraphic(sx, sy, graphic1, frame1);
1833 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1836 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1838 int sx = SCREENX(x), sy = SCREENY(y);
1839 static int xy[4][2] =
1848 for (i = 0; i < 4; i++)
1850 int xx = x + xy[i][0];
1851 int yy = y + xy[i][1];
1852 int sxx = sx + xy[i][0];
1853 int syy = sy + xy[i][1];
1855 if (!IN_LEV_FIELD(xx, yy) ||
1856 !IN_SCR_FIELD(sxx, syy) ||
1857 !GFX_CRUMBLED(Feld[xx][yy]) ||
1861 DrawLevelField(xx, yy);
1865 static int getBorderElement(int x, int y)
1869 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1870 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1871 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1872 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1873 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1874 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1875 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1877 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1878 int steel_position = (x == -1 && y == -1 ? 0 :
1879 x == lev_fieldx && y == -1 ? 1 :
1880 x == -1 && y == lev_fieldy ? 2 :
1881 x == lev_fieldx && y == lev_fieldy ? 3 :
1882 x == -1 || x == lev_fieldx ? 4 :
1883 y == -1 || y == lev_fieldy ? 5 : 6);
1885 return border[steel_position][steel_type];
1888 void DrawScreenElement(int x, int y, int element)
1890 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1891 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1894 void DrawLevelElement(int x, int y, int element)
1896 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1897 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1900 void DrawScreenField(int x, int y)
1902 int lx = LEVELX(x), ly = LEVELY(y);
1903 int element, content;
1905 if (!IN_LEV_FIELD(lx, ly))
1907 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1910 element = getBorderElement(lx, ly);
1912 DrawScreenElement(x, y, element);
1917 element = Feld[lx][ly];
1918 content = Store[lx][ly];
1920 if (IS_MOVING(lx, ly))
1922 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1923 boolean cut_mode = NO_CUTTING;
1925 if (element == EL_QUICKSAND_EMPTYING ||
1926 element == EL_QUICKSAND_FAST_EMPTYING ||
1927 element == EL_MAGIC_WALL_EMPTYING ||
1928 element == EL_BD_MAGIC_WALL_EMPTYING ||
1929 element == EL_DC_MAGIC_WALL_EMPTYING ||
1930 element == EL_AMOEBA_DROPPING)
1931 cut_mode = CUT_ABOVE;
1932 else if (element == EL_QUICKSAND_FILLING ||
1933 element == EL_QUICKSAND_FAST_FILLING ||
1934 element == EL_MAGIC_WALL_FILLING ||
1935 element == EL_BD_MAGIC_WALL_FILLING ||
1936 element == EL_DC_MAGIC_WALL_FILLING)
1937 cut_mode = CUT_BELOW;
1939 if (cut_mode == CUT_ABOVE)
1940 DrawScreenElement(x, y, element);
1942 DrawScreenElement(x, y, EL_EMPTY);
1945 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1946 else if (cut_mode == NO_CUTTING)
1947 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1950 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1952 if (cut_mode == CUT_BELOW &&
1953 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1954 DrawLevelElement(lx, ly + 1, element);
1957 if (content == EL_ACID)
1959 int dir = MovDir[lx][ly];
1960 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1961 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1963 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1966 else if (IS_BLOCKED(lx, ly))
1971 boolean cut_mode = NO_CUTTING;
1972 int element_old, content_old;
1974 Blocked2Moving(lx, ly, &oldx, &oldy);
1977 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1978 MovDir[oldx][oldy] == MV_RIGHT);
1980 element_old = Feld[oldx][oldy];
1981 content_old = Store[oldx][oldy];
1983 if (element_old == EL_QUICKSAND_EMPTYING ||
1984 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1985 element_old == EL_MAGIC_WALL_EMPTYING ||
1986 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1987 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1988 element_old == EL_AMOEBA_DROPPING)
1989 cut_mode = CUT_ABOVE;
1991 DrawScreenElement(x, y, EL_EMPTY);
1994 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1996 else if (cut_mode == NO_CUTTING)
1997 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2000 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2003 else if (IS_DRAWABLE(element))
2004 DrawScreenElement(x, y, element);
2006 DrawScreenElement(x, y, EL_EMPTY);
2009 void DrawLevelField(int x, int y)
2011 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2012 DrawScreenField(SCREENX(x), SCREENY(y));
2013 else if (IS_MOVING(x, y))
2017 Moving2Blocked(x, y, &newx, &newy);
2018 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2019 DrawScreenField(SCREENX(newx), SCREENY(newy));
2021 else if (IS_BLOCKED(x, y))
2025 Blocked2Moving(x, y, &oldx, &oldy);
2026 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2027 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2031 void DrawMiniElement(int x, int y, int element)
2035 graphic = el2edimg(element);
2036 DrawMiniGraphic(x, y, graphic);
2039 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2041 int x = sx + scroll_x, y = sy + scroll_y;
2043 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2044 DrawMiniElement(sx, sy, EL_EMPTY);
2045 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2046 DrawMiniElement(sx, sy, Feld[x][y]);
2048 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2051 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2052 int x, int y, int xsize, int ysize,
2053 int tile_width, int tile_height)
2057 int dst_x = startx + x * tile_width;
2058 int dst_y = starty + y * tile_height;
2059 int width = graphic_info[graphic].width;
2060 int height = graphic_info[graphic].height;
2061 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2062 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2063 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2064 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2065 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2066 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2067 boolean draw_masked = graphic_info[graphic].draw_masked;
2069 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2071 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2073 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2077 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2078 inner_sx + (x - 1) * tile_width % inner_width);
2079 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2080 inner_sy + (y - 1) * tile_height % inner_height);
2083 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2086 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2090 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2091 int x, int y, int xsize, int ysize, int font_nr)
2093 int font_width = getFontWidth(font_nr);
2094 int font_height = getFontHeight(font_nr);
2096 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2097 font_width, font_height);
2100 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2102 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2103 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2104 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2105 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2106 boolean no_delay = (tape.warp_forward);
2107 unsigned int anim_delay = 0;
2108 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2109 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2110 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2111 int font_width = getFontWidth(font_nr);
2112 int font_height = getFontHeight(font_nr);
2113 int max_xsize = level.envelope[envelope_nr].xsize;
2114 int max_ysize = level.envelope[envelope_nr].ysize;
2115 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2116 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2117 int xend = max_xsize;
2118 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2119 int xstep = (xstart < xend ? 1 : 0);
2120 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2123 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2125 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2126 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2127 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2128 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2131 SetDrawtoField(DRAW_BUFFERED);
2133 BlitScreenToBitmap(backbuffer);
2135 SetDrawtoField(DRAW_BACKBUFFER);
2137 for (yy = 0; yy < ysize; yy++)
2138 for (xx = 0; xx < xsize; xx++)
2139 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2141 DrawTextBuffer(sx + font_width, sy + font_height,
2142 level.envelope[envelope_nr].text, font_nr, max_xsize,
2143 xsize - 2, ysize - 2, 0, mask_mode,
2144 level.envelope[envelope_nr].autowrap,
2145 level.envelope[envelope_nr].centered, FALSE);
2147 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2150 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2154 void ShowEnvelope(int envelope_nr)
2156 int element = EL_ENVELOPE_1 + envelope_nr;
2157 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2158 int sound_opening = element_info[element].sound[ACTION_OPENING];
2159 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2160 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2161 boolean no_delay = (tape.warp_forward);
2162 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2163 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2164 int anim_mode = graphic_info[graphic].anim_mode;
2165 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2166 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2168 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2170 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2172 if (anim_mode == ANIM_DEFAULT)
2173 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2175 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2178 Delay(wait_delay_value);
2180 WaitForEventToContinue();
2182 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2184 if (anim_mode != ANIM_NONE)
2185 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2187 if (anim_mode == ANIM_DEFAULT)
2188 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2190 game.envelope_active = FALSE;
2192 SetDrawtoField(DRAW_BUFFERED);
2194 redraw_mask |= REDRAW_FIELD;
2198 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2200 int border_size = request.border_size;
2201 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2202 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2203 int sx = sx_center - request.width / 2;
2204 int sy = sy_center - request.height / 2;
2206 if (add_border_size)
2216 void DrawEnvelopeRequest(char *text)
2218 char *text_final = text;
2219 char *text_door_style = NULL;
2220 int graphic = IMG_BACKGROUND_REQUEST;
2221 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2222 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2223 int font_nr = FONT_REQUEST;
2224 int font_width = getFontWidth(font_nr);
2225 int font_height = getFontHeight(font_nr);
2226 int border_size = request.border_size;
2227 int line_spacing = request.line_spacing;
2228 int line_height = font_height + line_spacing;
2229 int text_width = request.width - 2 * border_size;
2230 int text_height = request.height - 2 * border_size;
2231 int line_length = text_width / font_width;
2232 int max_lines = text_height / line_height;
2233 int width = request.width;
2234 int height = request.height;
2235 int tile_size = request.step_offset;
2236 int x_steps = width / tile_size;
2237 int y_steps = height / tile_size;
2241 if (request.wrap_single_words)
2243 char *src_text_ptr, *dst_text_ptr;
2245 text_door_style = checked_malloc(2 * strlen(text) + 1);
2247 src_text_ptr = text;
2248 dst_text_ptr = text_door_style;
2250 while (*src_text_ptr)
2252 if (*src_text_ptr == ' ' ||
2253 *src_text_ptr == '?' ||
2254 *src_text_ptr == '!')
2255 *dst_text_ptr++ = '\n';
2257 if (*src_text_ptr != ' ')
2258 *dst_text_ptr++ = *src_text_ptr;
2263 *dst_text_ptr = '\0';
2265 text_final = text_door_style;
2268 setRequestPosition(&sx, &sy, FALSE);
2270 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2272 for (y = 0; y < y_steps; y++)
2273 for (x = 0; x < x_steps; x++)
2274 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2275 x, y, x_steps, y_steps,
2276 tile_size, tile_size);
2278 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2279 line_length, -1, max_lines, line_spacing, mask_mode,
2280 request.autowrap, request.centered, FALSE);
2282 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2283 RedrawGadget(tool_gadget[i]);
2285 // store readily prepared envelope request for later use when animating
2286 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2288 if (text_door_style)
2289 free(text_door_style);
2292 void AnimateEnvelopeRequest(int anim_mode, int action)
2294 int graphic = IMG_BACKGROUND_REQUEST;
2295 boolean draw_masked = graphic_info[graphic].draw_masked;
2296 int delay_value_normal = request.step_delay;
2297 int delay_value_fast = delay_value_normal / 2;
2298 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2299 boolean no_delay = (tape.warp_forward);
2300 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2301 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
2302 unsigned int anim_delay = 0;
2304 int width = request.width;
2305 int height = request.height;
2306 int tile_size = request.step_offset;
2307 int max_xsize = width / tile_size;
2308 int max_ysize = height / tile_size;
2309 int max_xsize_inner = max_xsize - 2;
2310 int max_ysize_inner = max_ysize - 2;
2312 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2313 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2314 int xend = max_xsize_inner;
2315 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2316 int xstep = (xstart < xend ? 1 : 0);
2317 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2320 if (setup.quick_doors)
2327 if (action == ACTION_OPENING)
2328 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2329 else if (action == ACTION_CLOSING)
2330 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2333 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2335 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2336 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2337 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2338 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2339 int src_x = sx_center - width / 2;
2340 int src_y = sy_center - height / 2;
2341 int dst_x = sx_center - xsize * tile_size / 2;
2342 int dst_y = sy_center - ysize * tile_size / 2;
2343 int xsize_size_left = (xsize - 1) * tile_size;
2344 int ysize_size_top = (ysize - 1) * tile_size;
2345 int max_xsize_pos = (max_xsize - 1) * tile_size;
2346 int max_ysize_pos = (max_ysize - 1) * tile_size;
2349 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2351 for (yy = 0; yy < 2; yy++)
2353 for (xx = 0; xx < 2; xx++)
2355 int src_xx = src_x + xx * max_xsize_pos;
2356 int src_yy = src_y + yy * max_ysize_pos;
2357 int dst_xx = dst_x + xx * xsize_size_left;
2358 int dst_yy = dst_y + yy * ysize_size_top;
2359 int xx_size = (xx ? tile_size : xsize_size_left);
2360 int yy_size = (yy ? tile_size : ysize_size_top);
2363 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2364 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2366 BlitBitmap(bitmap_db_cross, backbuffer,
2367 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2371 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2376 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2381 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2383 int last_game_status = game_status; /* save current game status */
2384 int graphic = IMG_BACKGROUND_REQUEST;
2385 int sound_opening = SND_REQUEST_OPENING;
2386 int sound_closing = SND_REQUEST_CLOSING;
2387 int anim_mode = graphic_info[graphic].anim_mode;
2388 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2389 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2391 if (game_status == GAME_MODE_PLAYING)
2392 BlitScreenToBitmap(backbuffer);
2394 SetDrawtoField(DRAW_BACKBUFFER);
2396 // SetDrawBackgroundMask(REDRAW_NONE);
2398 if (action == ACTION_OPENING)
2400 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2402 if (req_state & REQ_ASK)
2404 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2405 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2407 else if (req_state & REQ_CONFIRM)
2409 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2411 else if (req_state & REQ_PLAYER)
2413 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2414 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2415 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2416 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2419 DrawEnvelopeRequest(text);
2421 if (game_status != GAME_MODE_MAIN)
2425 /* force DOOR font inside door area */
2426 game_status = GAME_MODE_PSEUDO_DOOR;
2428 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2430 if (action == ACTION_OPENING)
2432 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2434 if (anim_mode == ANIM_DEFAULT)
2435 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2437 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2442 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2444 if (anim_mode != ANIM_NONE)
2445 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2447 if (anim_mode == ANIM_DEFAULT)
2448 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2451 game.envelope_active = FALSE;
2453 game_status = last_game_status; /* restore current game status */
2455 if (action == ACTION_CLOSING)
2457 if (game_status != GAME_MODE_MAIN)
2460 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2463 // SetDrawBackgroundMask(last_draw_background_mask);
2465 redraw_mask |= REDRAW_FIELD;
2467 if (game_status == GAME_MODE_MAIN)
2472 if (action == ACTION_CLOSING &&
2473 game_status == GAME_MODE_PLAYING &&
2474 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2475 SetDrawtoField(DRAW_BUFFERED);
2478 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2482 int graphic = el2preimg(element);
2484 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2485 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2488 void DrawLevel(int draw_background_mask)
2492 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2493 SetDrawBackgroundMask(draw_background_mask);
2497 for (x = BX1; x <= BX2; x++)
2498 for (y = BY1; y <= BY2; y++)
2499 DrawScreenField(x, y);
2501 redraw_mask |= REDRAW_FIELD;
2504 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2508 for (x = 0; x < size_x; x++)
2509 for (y = 0; y < size_y; y++)
2510 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2512 redraw_mask |= REDRAW_FIELD;
2515 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2517 boolean show_level_border = (BorderElement != EL_EMPTY);
2518 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2519 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2520 int tile_size = preview.tile_size;
2521 int preview_width = preview.xsize * tile_size;
2522 int preview_height = preview.ysize * tile_size;
2523 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2524 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2525 int real_preview_width = real_preview_xsize * tile_size;
2526 int real_preview_height = real_preview_ysize * tile_size;
2527 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2528 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2531 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2534 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2536 dst_x += (preview_width - real_preview_width) / 2;
2537 dst_y += (preview_height - real_preview_height) / 2;
2539 for (x = 0; x < real_preview_xsize; x++)
2541 for (y = 0; y < real_preview_ysize; y++)
2543 int lx = from_x + x + (show_level_border ? -1 : 0);
2544 int ly = from_y + y + (show_level_border ? -1 : 0);
2545 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2546 getBorderElement(lx, ly));
2548 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2549 element, tile_size);
2553 redraw_mask |= REDRAW_MICROLEVEL;
2556 #define MICROLABEL_EMPTY 0
2557 #define MICROLABEL_LEVEL_NAME 1
2558 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2559 #define MICROLABEL_LEVEL_AUTHOR 3
2560 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2561 #define MICROLABEL_IMPORTED_FROM 5
2562 #define MICROLABEL_IMPORTED_BY_HEAD 6
2563 #define MICROLABEL_IMPORTED_BY 7
2565 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2567 int max_text_width = SXSIZE;
2568 int font_width = getFontWidth(font_nr);
2570 if (pos->align == ALIGN_CENTER)
2571 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2572 else if (pos->align == ALIGN_RIGHT)
2573 max_text_width = pos->x;
2575 max_text_width = SXSIZE - pos->x;
2577 return max_text_width / font_width;
2580 static void DrawPreviewLevelLabelExt(int mode)
2582 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2583 char label_text[MAX_OUTPUT_LINESIZE + 1];
2584 int max_len_label_text;
2585 int font_nr = pos->font;
2588 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2591 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2592 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2593 mode == MICROLABEL_IMPORTED_BY_HEAD)
2594 font_nr = pos->font_alt;
2596 max_len_label_text = getMaxTextLength(pos, font_nr);
2598 if (pos->size != -1)
2599 max_len_label_text = pos->size;
2601 for (i = 0; i < max_len_label_text; i++)
2602 label_text[i] = ' ';
2603 label_text[max_len_label_text] = '\0';
2605 if (strlen(label_text) > 0)
2606 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2609 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2610 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2611 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2612 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2613 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2614 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2615 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2616 max_len_label_text);
2617 label_text[max_len_label_text] = '\0';
2619 if (strlen(label_text) > 0)
2620 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2622 redraw_mask |= REDRAW_MICROLEVEL;
2625 static void DrawPreviewLevelExt(boolean restart)
2627 static unsigned int scroll_delay = 0;
2628 static unsigned int label_delay = 0;
2629 static int from_x, from_y, scroll_direction;
2630 static int label_state, label_counter;
2631 unsigned int scroll_delay_value = preview.step_delay;
2632 boolean show_level_border = (BorderElement != EL_EMPTY);
2633 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2634 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2635 int last_game_status = game_status; /* save current game status */
2642 if (preview.anim_mode == ANIM_CENTERED)
2644 if (level_xsize > preview.xsize)
2645 from_x = (level_xsize - preview.xsize) / 2;
2646 if (level_ysize > preview.ysize)
2647 from_y = (level_ysize - preview.ysize) / 2;
2650 from_x += preview.xoffset;
2651 from_y += preview.yoffset;
2653 scroll_direction = MV_RIGHT;
2657 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2658 DrawPreviewLevelLabelExt(label_state);
2660 /* initialize delay counters */
2661 DelayReached(&scroll_delay, 0);
2662 DelayReached(&label_delay, 0);
2664 if (leveldir_current->name)
2666 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2667 char label_text[MAX_OUTPUT_LINESIZE + 1];
2668 int font_nr = pos->font;
2669 int max_len_label_text = getMaxTextLength(pos, font_nr);
2671 if (pos->size != -1)
2672 max_len_label_text = pos->size;
2674 strncpy(label_text, leveldir_current->name, max_len_label_text);
2675 label_text[max_len_label_text] = '\0';
2677 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2678 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2681 game_status = last_game_status; /* restore current game status */
2686 /* scroll preview level, if needed */
2687 if (preview.anim_mode != ANIM_NONE &&
2688 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2689 DelayReached(&scroll_delay, scroll_delay_value))
2691 switch (scroll_direction)
2696 from_x -= preview.step_offset;
2697 from_x = (from_x < 0 ? 0 : from_x);
2700 scroll_direction = MV_UP;
2704 if (from_x < level_xsize - preview.xsize)
2706 from_x += preview.step_offset;
2707 from_x = (from_x > level_xsize - preview.xsize ?
2708 level_xsize - preview.xsize : from_x);
2711 scroll_direction = MV_DOWN;
2717 from_y -= preview.step_offset;
2718 from_y = (from_y < 0 ? 0 : from_y);
2721 scroll_direction = MV_RIGHT;
2725 if (from_y < level_ysize - preview.ysize)
2727 from_y += preview.step_offset;
2728 from_y = (from_y > level_ysize - preview.ysize ?
2729 level_ysize - preview.ysize : from_y);
2732 scroll_direction = MV_LEFT;
2739 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2742 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2743 /* redraw micro level label, if needed */
2744 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2745 !strEqual(level.author, ANONYMOUS_NAME) &&
2746 !strEqual(level.author, leveldir_current->name) &&
2747 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2749 int max_label_counter = 23;
2751 if (leveldir_current->imported_from != NULL &&
2752 strlen(leveldir_current->imported_from) > 0)
2753 max_label_counter += 14;
2754 if (leveldir_current->imported_by != NULL &&
2755 strlen(leveldir_current->imported_by) > 0)
2756 max_label_counter += 14;
2758 label_counter = (label_counter + 1) % max_label_counter;
2759 label_state = (label_counter >= 0 && label_counter <= 7 ?
2760 MICROLABEL_LEVEL_NAME :
2761 label_counter >= 9 && label_counter <= 12 ?
2762 MICROLABEL_LEVEL_AUTHOR_HEAD :
2763 label_counter >= 14 && label_counter <= 21 ?
2764 MICROLABEL_LEVEL_AUTHOR :
2765 label_counter >= 23 && label_counter <= 26 ?
2766 MICROLABEL_IMPORTED_FROM_HEAD :
2767 label_counter >= 28 && label_counter <= 35 ?
2768 MICROLABEL_IMPORTED_FROM :
2769 label_counter >= 37 && label_counter <= 40 ?
2770 MICROLABEL_IMPORTED_BY_HEAD :
2771 label_counter >= 42 && label_counter <= 49 ?
2772 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2774 if (leveldir_current->imported_from == NULL &&
2775 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2776 label_state == MICROLABEL_IMPORTED_FROM))
2777 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2778 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2780 DrawPreviewLevelLabelExt(label_state);
2783 game_status = last_game_status; /* restore current game status */
2786 void DrawPreviewLevelInitial()
2788 DrawPreviewLevelExt(TRUE);
2791 void DrawPreviewLevelAnimation()
2793 DrawPreviewLevelExt(FALSE);
2796 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2797 int graphic, int sync_frame, int mask_mode)
2799 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2801 if (mask_mode == USE_MASKING)
2802 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2804 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2807 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2808 int graphic, int sync_frame,
2811 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2813 if (mask_mode == USE_MASKING)
2814 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2816 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2819 inline void DrawGraphicAnimation(int x, int y, int graphic)
2821 int lx = LEVELX(x), ly = LEVELY(y);
2823 if (!IN_SCR_FIELD(x, y))
2826 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2827 graphic, GfxFrame[lx][ly], NO_MASKING);
2829 MarkTileDirty(x, y);
2832 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2834 int lx = LEVELX(x), ly = LEVELY(y);
2836 if (!IN_SCR_FIELD(x, y))
2839 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2840 graphic, GfxFrame[lx][ly], NO_MASKING);
2841 MarkTileDirty(x, y);
2844 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2846 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2849 void DrawLevelElementAnimation(int x, int y, int element)
2851 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2853 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2856 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2858 int sx = SCREENX(x), sy = SCREENY(y);
2860 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2863 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2866 DrawGraphicAnimation(sx, sy, graphic);
2869 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2870 DrawLevelFieldCrumbled(x, y);
2872 if (GFX_CRUMBLED(Feld[x][y]))
2873 DrawLevelFieldCrumbled(x, y);
2877 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2879 int sx = SCREENX(x), sy = SCREENY(y);
2882 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2885 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2887 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2890 DrawGraphicAnimation(sx, sy, graphic);
2892 if (GFX_CRUMBLED(element))
2893 DrawLevelFieldCrumbled(x, y);
2896 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2898 if (player->use_murphy)
2900 /* this works only because currently only one player can be "murphy" ... */
2901 static int last_horizontal_dir = MV_LEFT;
2902 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2904 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2905 last_horizontal_dir = move_dir;
2907 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2909 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2911 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2917 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2920 static boolean equalGraphics(int graphic1, int graphic2)
2922 struct GraphicInfo *g1 = &graphic_info[graphic1];
2923 struct GraphicInfo *g2 = &graphic_info[graphic2];
2925 return (g1->bitmap == g2->bitmap &&
2926 g1->src_x == g2->src_x &&
2927 g1->src_y == g2->src_y &&
2928 g1->anim_frames == g2->anim_frames &&
2929 g1->anim_delay == g2->anim_delay &&
2930 g1->anim_mode == g2->anim_mode);
2933 void DrawAllPlayers()
2937 for (i = 0; i < MAX_PLAYERS; i++)
2938 if (stored_player[i].active)
2939 DrawPlayer(&stored_player[i]);
2942 void DrawPlayerField(int x, int y)
2944 if (!IS_PLAYER(x, y))
2947 DrawPlayer(PLAYERINFO(x, y));
2950 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2952 void DrawPlayer(struct PlayerInfo *player)
2954 int jx = player->jx;
2955 int jy = player->jy;
2956 int move_dir = player->MovDir;
2957 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2958 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2959 int last_jx = (player->is_moving ? jx - dx : jx);
2960 int last_jy = (player->is_moving ? jy - dy : jy);
2961 int next_jx = jx + dx;
2962 int next_jy = jy + dy;
2963 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2964 boolean player_is_opaque = FALSE;
2965 int sx = SCREENX(jx), sy = SCREENY(jy);
2966 int sxx = 0, syy = 0;
2967 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2969 int action = ACTION_DEFAULT;
2970 int last_player_graphic = getPlayerGraphic(player, move_dir);
2971 int last_player_frame = player->Frame;
2974 /* GfxElement[][] is set to the element the player is digging or collecting;
2975 remove also for off-screen player if the player is not moving anymore */
2976 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2977 GfxElement[jx][jy] = EL_UNDEFINED;
2979 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2983 if (!IN_LEV_FIELD(jx, jy))
2985 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2986 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2987 printf("DrawPlayerField(): This should never happen!\n");
2992 if (element == EL_EXPLOSION)
2995 action = (player->is_pushing ? ACTION_PUSHING :
2996 player->is_digging ? ACTION_DIGGING :
2997 player->is_collecting ? ACTION_COLLECTING :
2998 player->is_moving ? ACTION_MOVING :
2999 player->is_snapping ? ACTION_SNAPPING :
3000 player->is_dropping ? ACTION_DROPPING :
3001 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3003 if (player->is_waiting)
3004 move_dir = player->dir_waiting;
3006 InitPlayerGfxAnimation(player, action, move_dir);
3008 /* ----------------------------------------------------------------------- */
3009 /* draw things in the field the player is leaving, if needed */
3010 /* ----------------------------------------------------------------------- */
3012 if (player->is_moving)
3014 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3016 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3018 if (last_element == EL_DYNAMITE_ACTIVE ||
3019 last_element == EL_EM_DYNAMITE_ACTIVE ||
3020 last_element == EL_SP_DISK_RED_ACTIVE)
3021 DrawDynamite(last_jx, last_jy);
3023 DrawLevelFieldThruMask(last_jx, last_jy);
3025 else if (last_element == EL_DYNAMITE_ACTIVE ||
3026 last_element == EL_EM_DYNAMITE_ACTIVE ||
3027 last_element == EL_SP_DISK_RED_ACTIVE)
3028 DrawDynamite(last_jx, last_jy);
3030 /* !!! this is not enough to prevent flickering of players which are
3031 moving next to each others without a free tile between them -- this
3032 can only be solved by drawing all players layer by layer (first the
3033 background, then the foreground etc.) !!! => TODO */
3034 else if (!IS_PLAYER(last_jx, last_jy))
3035 DrawLevelField(last_jx, last_jy);
3038 DrawLevelField(last_jx, last_jy);
3041 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3042 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3045 if (!IN_SCR_FIELD(sx, sy))
3048 /* ----------------------------------------------------------------------- */
3049 /* draw things behind the player, if needed */
3050 /* ----------------------------------------------------------------------- */
3053 DrawLevelElement(jx, jy, Back[jx][jy]);
3054 else if (IS_ACTIVE_BOMB(element))
3055 DrawLevelElement(jx, jy, EL_EMPTY);
3058 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3060 int old_element = GfxElement[jx][jy];
3061 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3062 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3064 if (GFX_CRUMBLED(old_element))
3065 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3067 DrawGraphic(sx, sy, old_graphic, frame);
3069 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3070 player_is_opaque = TRUE;
3074 GfxElement[jx][jy] = EL_UNDEFINED;
3076 /* make sure that pushed elements are drawn with correct frame rate */
3077 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3079 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3080 GfxFrame[jx][jy] = player->StepFrame;
3082 DrawLevelField(jx, jy);
3086 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3087 /* ----------------------------------------------------------------------- */
3088 /* draw player himself */
3089 /* ----------------------------------------------------------------------- */
3091 graphic = getPlayerGraphic(player, move_dir);
3093 /* in the case of changed player action or direction, prevent the current
3094 animation frame from being restarted for identical animations */
3095 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3096 player->Frame = last_player_frame;
3098 frame = getGraphicAnimationFrame(graphic, player->Frame);
3102 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3103 sxx = player->GfxPos;
3105 syy = player->GfxPos;
3108 if (!setup.soft_scrolling && ScreenMovPos)
3111 if (player_is_opaque)
3112 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3114 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3116 if (SHIELD_ON(player))
3118 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3119 IMG_SHIELD_NORMAL_ACTIVE);
3120 int frame = getGraphicAnimationFrame(graphic, -1);
3122 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3126 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3129 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3130 sxx = player->GfxPos;
3132 syy = player->GfxPos;
3136 /* ----------------------------------------------------------------------- */
3137 /* draw things the player is pushing, if needed */
3138 /* ----------------------------------------------------------------------- */
3140 if (player->is_pushing && player->is_moving)
3142 int px = SCREENX(jx), py = SCREENY(jy);
3143 int pxx = (TILEX - ABS(sxx)) * dx;
3144 int pyy = (TILEY - ABS(syy)) * dy;
3145 int gfx_frame = GfxFrame[jx][jy];
3151 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3153 element = Feld[next_jx][next_jy];
3154 gfx_frame = GfxFrame[next_jx][next_jy];
3157 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3159 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3160 frame = getGraphicAnimationFrame(graphic, sync_frame);
3162 /* draw background element under pushed element (like the Sokoban field) */
3163 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3165 /* this allows transparent pushing animation over non-black background */
3168 DrawLevelElement(jx, jy, Back[jx][jy]);
3170 DrawLevelElement(jx, jy, EL_EMPTY);
3172 if (Back[next_jx][next_jy])
3173 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3175 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3177 else if (Back[next_jx][next_jy])
3178 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3181 /* do not draw (EM style) pushing animation when pushing is finished */
3182 /* (two-tile animations usually do not contain start and end frame) */
3183 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3184 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3186 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3188 /* masked drawing is needed for EMC style (double) movement graphics */
3189 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3190 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3194 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3195 /* ----------------------------------------------------------------------- */
3196 /* draw player himself */
3197 /* ----------------------------------------------------------------------- */
3199 graphic = getPlayerGraphic(player, move_dir);
3201 /* in the case of changed player action or direction, prevent the current
3202 animation frame from being restarted for identical animations */
3203 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3204 player->Frame = last_player_frame;
3206 frame = getGraphicAnimationFrame(graphic, player->Frame);
3210 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3211 sxx = player->GfxPos;
3213 syy = player->GfxPos;
3216 if (!setup.soft_scrolling && ScreenMovPos)
3219 if (player_is_opaque)
3220 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3222 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3224 if (SHIELD_ON(player))
3226 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3227 IMG_SHIELD_NORMAL_ACTIVE);
3228 int frame = getGraphicAnimationFrame(graphic, -1);
3230 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3234 /* ----------------------------------------------------------------------- */
3235 /* draw things in front of player (active dynamite or dynabombs) */
3236 /* ----------------------------------------------------------------------- */
3238 if (IS_ACTIVE_BOMB(element))
3240 graphic = el2img(element);
3241 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3243 if (game.emulation == EMU_SUPAPLEX)
3244 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3246 DrawGraphicThruMask(sx, sy, graphic, frame);
3249 if (player_is_moving && last_element == EL_EXPLOSION)
3251 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3252 GfxElement[last_jx][last_jy] : EL_EMPTY);
3253 int graphic = el_act2img(element, ACTION_EXPLODING);
3254 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3255 int phase = ExplodePhase[last_jx][last_jy] - 1;
3256 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3259 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3262 /* ----------------------------------------------------------------------- */
3263 /* draw elements the player is just walking/passing through/under */
3264 /* ----------------------------------------------------------------------- */
3266 if (player_is_moving)
3268 /* handle the field the player is leaving ... */
3269 if (IS_ACCESSIBLE_INSIDE(last_element))
3270 DrawLevelField(last_jx, last_jy);
3271 else if (IS_ACCESSIBLE_UNDER(last_element))
3272 DrawLevelFieldThruMask(last_jx, last_jy);
3275 /* do not redraw accessible elements if the player is just pushing them */
3276 if (!player_is_moving || !player->is_pushing)
3278 /* ... and the field the player is entering */
3279 if (IS_ACCESSIBLE_INSIDE(element))
3280 DrawLevelField(jx, jy);
3281 else if (IS_ACCESSIBLE_UNDER(element))
3282 DrawLevelFieldThruMask(jx, jy);
3285 MarkTileDirty(sx, sy);
3288 /* ------------------------------------------------------------------------- */
3290 void WaitForEventToContinue()
3292 boolean still_wait = TRUE;
3294 /* simulate releasing mouse button over last gadget, if still pressed */
3296 HandleGadgets(-1, -1, 0);
3298 button_status = MB_RELEASED;
3312 case EVENT_BUTTONPRESS:
3313 case EVENT_KEYPRESS:
3317 case EVENT_KEYRELEASE:
3318 ClearPlayerAction();
3322 HandleOtherEvents(&event);
3326 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3333 /* don't eat all CPU time */
3338 #define MAX_REQUEST_LINES 13
3339 #define MAX_REQUEST_LINE_FONT1_LEN 7
3340 #define MAX_REQUEST_LINE_FONT2_LEN 10
3342 static int RequestHandleEvents(unsigned int req_state)
3344 int last_game_status = game_status; /* save current game status */
3348 button_status = MB_RELEASED;
3350 request_gadget_id = -1;
3363 case EVENT_BUTTONPRESS:
3364 case EVENT_BUTTONRELEASE:
3365 case EVENT_MOTIONNOTIFY:
3367 if (event.type == EVENT_MOTIONNOTIFY)
3369 if (!PointerInWindow(window))
3370 continue; /* window and pointer are on different screens */
3375 motion_status = TRUE;
3376 mx = ((MotionEvent *) &event)->x;
3377 my = ((MotionEvent *) &event)->y;
3381 motion_status = FALSE;
3382 mx = ((ButtonEvent *) &event)->x;
3383 my = ((ButtonEvent *) &event)->y;
3384 if (event.type == EVENT_BUTTONPRESS)
3385 button_status = ((ButtonEvent *) &event)->button;
3387 button_status = MB_RELEASED;
3390 /* this sets 'request_gadget_id' */
3391 HandleGadgets(mx, my, button_status);
3393 switch (request_gadget_id)
3395 case TOOL_CTRL_ID_YES:
3398 case TOOL_CTRL_ID_NO:
3401 case TOOL_CTRL_ID_CONFIRM:
3402 result = TRUE | FALSE;
3405 case TOOL_CTRL_ID_PLAYER_1:
3408 case TOOL_CTRL_ID_PLAYER_2:
3411 case TOOL_CTRL_ID_PLAYER_3:
3414 case TOOL_CTRL_ID_PLAYER_4:
3425 case EVENT_KEYPRESS:
3426 switch (GetEventKey((KeyEvent *)&event, TRUE))
3429 if (req_state & REQ_CONFIRM)
3434 #if defined(TARGET_SDL2)
3441 #if defined(TARGET_SDL2)
3451 if (req_state & REQ_PLAYER)
3455 case EVENT_KEYRELEASE:
3456 ClearPlayerAction();
3460 HandleOtherEvents(&event);
3464 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3466 int joy = AnyJoystick();
3468 if (joy & JOY_BUTTON_1)
3470 else if (joy & JOY_BUTTON_2)
3474 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3476 HandleGameActions();
3482 if (!PendingEvent()) /* delay only if no pending events */
3486 game_status = GAME_MODE_PSEUDO_DOOR;
3490 game_status = last_game_status; /* restore current game status */
3496 static boolean RequestDoor(char *text, unsigned int req_state)
3498 unsigned int old_door_state;
3499 int last_game_status = game_status; /* save current game status */
3500 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3501 int font_nr = FONT_TEXT_2;
3506 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3508 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3509 font_nr = FONT_TEXT_1;
3512 if (game_status == GAME_MODE_PLAYING)
3513 BlitScreenToBitmap(backbuffer);
3515 /* disable deactivated drawing when quick-loading level tape recording */
3516 if (tape.playing && tape.deactivate_display)
3517 TapeDeactivateDisplayOff(TRUE);
3519 SetMouseCursor(CURSOR_DEFAULT);
3521 #if defined(NETWORK_AVALIABLE)
3522 /* pause network game while waiting for request to answer */
3523 if (options.network &&
3524 game_status == GAME_MODE_PLAYING &&
3525 req_state & REQUEST_WAIT_FOR_INPUT)
3526 SendToServer_PausePlaying();
3529 old_door_state = GetDoorState();
3531 /* simulate releasing mouse button over last gadget, if still pressed */
3533 HandleGadgets(-1, -1, 0);
3537 /* draw released gadget before proceeding */
3540 if (old_door_state & DOOR_OPEN_1)
3542 CloseDoor(DOOR_CLOSE_1);
3544 /* save old door content */
3545 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3546 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3549 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3550 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3552 /* clear door drawing field */
3553 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3555 /* force DOOR font inside door area */
3556 game_status = GAME_MODE_PSEUDO_DOOR;
3558 /* write text for request */
3559 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3561 char text_line[max_request_line_len + 1];
3567 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3569 tc = *(text_ptr + tx);
3570 // if (!tc || tc == ' ')
3571 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3575 if ((tc == '?' || tc == '!') && tl == 0)
3585 strncpy(text_line, text_ptr, tl);
3588 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3589 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3590 text_line, font_nr);
3592 text_ptr += tl + (tc == ' ' ? 1 : 0);
3593 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3596 game_status = last_game_status; /* restore current game status */
3598 if (req_state & REQ_ASK)
3600 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3601 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3603 else if (req_state & REQ_CONFIRM)
3605 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3607 else if (req_state & REQ_PLAYER)
3609 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3610 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3611 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3612 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3615 /* copy request gadgets to door backbuffer */
3616 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3618 OpenDoor(DOOR_OPEN_1);
3620 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3622 if (game_status == GAME_MODE_PLAYING)
3624 SetPanelBackground();
3625 SetDrawBackgroundMask(REDRAW_DOOR_1);
3629 SetDrawBackgroundMask(REDRAW_FIELD);
3635 if (game_status != GAME_MODE_MAIN)
3638 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3640 // ---------- handle request buttons ----------
3641 result = RequestHandleEvents(req_state);
3643 if (game_status != GAME_MODE_MAIN)
3648 if (!(req_state & REQ_STAY_OPEN))
3650 CloseDoor(DOOR_CLOSE_1);
3652 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3653 (req_state & REQ_REOPEN))
3654 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3659 if (game_status == GAME_MODE_PLAYING)
3661 SetPanelBackground();
3662 SetDrawBackgroundMask(REDRAW_DOOR_1);
3666 SetDrawBackgroundMask(REDRAW_FIELD);
3669 #if defined(NETWORK_AVALIABLE)
3670 /* continue network game after request */
3671 if (options.network &&
3672 game_status == GAME_MODE_PLAYING &&
3673 req_state & REQUEST_WAIT_FOR_INPUT)
3674 SendToServer_ContinuePlaying();
3677 /* restore deactivated drawing when quick-loading level tape recording */
3678 if (tape.playing && tape.deactivate_display)
3679 TapeDeactivateDisplayOn();
3684 static boolean RequestEnvelope(char *text, unsigned int req_state)
3688 if (game_status == GAME_MODE_PLAYING)
3689 BlitScreenToBitmap(backbuffer);
3691 /* disable deactivated drawing when quick-loading level tape recording */
3692 if (tape.playing && tape.deactivate_display)
3693 TapeDeactivateDisplayOff(TRUE);
3695 SetMouseCursor(CURSOR_DEFAULT);
3697 #if defined(NETWORK_AVALIABLE)
3698 /* pause network game while waiting for request to answer */
3699 if (options.network &&
3700 game_status == GAME_MODE_PLAYING &&
3701 req_state & REQUEST_WAIT_FOR_INPUT)
3702 SendToServer_PausePlaying();
3705 /* simulate releasing mouse button over last gadget, if still pressed */
3707 HandleGadgets(-1, -1, 0);
3711 // (replace with setting corresponding request background)
3712 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3713 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3715 /* clear door drawing field */
3716 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3718 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3720 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3722 if (game_status == GAME_MODE_PLAYING)
3724 SetPanelBackground();
3725 SetDrawBackgroundMask(REDRAW_DOOR_1);
3729 SetDrawBackgroundMask(REDRAW_FIELD);
3735 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3737 // ---------- handle request buttons ----------
3738 result = RequestHandleEvents(req_state);
3740 if (game_status != GAME_MODE_MAIN)
3745 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3749 if (game_status == GAME_MODE_PLAYING)
3751 SetPanelBackground();
3752 SetDrawBackgroundMask(REDRAW_DOOR_1);
3756 SetDrawBackgroundMask(REDRAW_FIELD);
3759 #if defined(NETWORK_AVALIABLE)
3760 /* continue network game after request */
3761 if (options.network &&
3762 game_status == GAME_MODE_PLAYING &&
3763 req_state & REQUEST_WAIT_FOR_INPUT)
3764 SendToServer_ContinuePlaying();
3767 /* restore deactivated drawing when quick-loading level tape recording */
3768 if (tape.playing && tape.deactivate_display)
3769 TapeDeactivateDisplayOn();
3774 boolean Request(char *text, unsigned int req_state)
3776 if (global.use_envelope_request)
3777 return RequestEnvelope(text, req_state);
3779 return RequestDoor(text, req_state);
3782 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3784 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3785 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3788 if (dpo1->sort_priority != dpo2->sort_priority)
3789 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3791 compare_result = dpo1->nr - dpo2->nr;
3793 return compare_result;
3796 void InitGraphicCompatibilityInfo_Doors()
3802 struct DoorInfo *door;
3806 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3807 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3809 { -1, -1, -1, NULL }
3811 struct Rect door_rect_list[] =
3813 { DX, DY, DXSIZE, DYSIZE },
3814 { VX, VY, VXSIZE, VYSIZE }
3818 for (i = 0; doors[i].door_token != -1; i++)
3820 int door_token = doors[i].door_token;
3821 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3822 int part_1 = doors[i].part_1;
3823 int part_8 = doors[i].part_8;
3824 int part_2 = part_1 + 1;
3825 int part_3 = part_1 + 2;
3826 struct DoorInfo *door = doors[i].door;
3827 struct Rect *door_rect = &door_rect_list[door_index];
3828 boolean door_gfx_redefined = FALSE;
3830 /* check if any door part graphic definitions have been redefined */
3832 for (j = 0; door_part_controls[j].door_token != -1; j++)
3834 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3835 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3837 if (dpc->door_token == door_token && fi->redefined)
3838 door_gfx_redefined = TRUE;
3841 /* check for old-style door graphic/animation modifications */
3843 if (!door_gfx_redefined)
3845 if (door->anim_mode & ANIM_STATIC_PANEL)
3847 door->panel.step_xoffset = 0;
3848 door->panel.step_yoffset = 0;
3851 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3853 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3854 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3855 int num_door_steps, num_panel_steps;
3857 /* remove door part graphics other than the two default wings */
3859 for (j = 0; door_part_controls[j].door_token != -1; j++)
3861 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3862 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3864 if (dpc->graphic >= part_3 &&
3865 dpc->graphic <= part_8)
3869 /* set graphics and screen positions of the default wings */
3871 g_part_1->width = door_rect->width;
3872 g_part_1->height = door_rect->height;
3873 g_part_2->width = door_rect->width;
3874 g_part_2->height = door_rect->height;
3875 g_part_2->src_x = door_rect->width;
3876 g_part_2->src_y = g_part_1->src_y;
3878 door->part_2.x = door->part_1.x;
3879 door->part_2.y = door->part_1.y;
3881 if (door->width != -1)
3883 g_part_1->width = door->width;
3884 g_part_2->width = door->width;
3886 // special treatment for graphics and screen position of right wing
3887 g_part_2->src_x += door_rect->width - door->width;
3888 door->part_2.x += door_rect->width - door->width;
3891 if (door->height != -1)
3893 g_part_1->height = door->height;
3894 g_part_2->height = door->height;
3896 // special treatment for graphics and screen position of bottom wing
3897 g_part_2->src_y += door_rect->height - door->height;
3898 door->part_2.y += door_rect->height - door->height;
3901 /* set animation delays for the default wings and panels */
3903 door->part_1.step_delay = door->step_delay;
3904 door->part_2.step_delay = door->step_delay;
3905 door->panel.step_delay = door->step_delay;
3907 /* set animation draw order for the default wings */
3909 door->part_1.sort_priority = 2; /* draw left wing over ... */
3910 door->part_2.sort_priority = 1; /* ... right wing */
3912 /* set animation draw offset for the default wings */
3914 if (door->anim_mode & ANIM_HORIZONTAL)
3916 door->part_1.step_xoffset = door->step_offset;
3917 door->part_1.step_yoffset = 0;
3918 door->part_2.step_xoffset = door->step_offset * -1;
3919 door->part_2.step_yoffset = 0;
3921 num_door_steps = g_part_1->width / door->step_offset;
3923 else // ANIM_VERTICAL
3925 door->part_1.step_xoffset = 0;
3926 door->part_1.step_yoffset = door->step_offset;
3927 door->part_2.step_xoffset = 0;
3928 door->part_2.step_yoffset = door->step_offset * -1;
3930 num_door_steps = g_part_1->height / door->step_offset;
3933 /* set animation draw offset for the default panels */
3935 if (door->step_offset > 1)
3937 num_panel_steps = 2 * door_rect->height / door->step_offset;
3938 door->panel.start_step = num_panel_steps - num_door_steps;
3942 num_panel_steps = door_rect->height / door->step_offset;
3943 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3944 door->panel.step_delay *= 2;
3955 for (i = 0; door_part_controls[i].door_token != -1; i++)
3957 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3958 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3960 /* initialize "start_step_opening" and "start_step_closing", if needed */
3961 if (dpc->pos->start_step_opening == 0 &&
3962 dpc->pos->start_step_closing == 0)
3964 // dpc->pos->start_step_opening = dpc->pos->start_step;
3965 dpc->pos->start_step_closing = dpc->pos->start_step;
3968 /* fill structure for door part draw order (sorted below) */
3970 dpo->sort_priority = dpc->pos->sort_priority;
3973 /* sort door part controls according to sort_priority and graphic number */
3974 qsort(door_part_order, MAX_DOOR_PARTS,
3975 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3978 unsigned int OpenDoor(unsigned int door_state)
3980 if (door_state & DOOR_COPY_BACK)
3982 if (door_state & DOOR_OPEN_1)
3983 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3984 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3986 if (door_state & DOOR_OPEN_2)
3987 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3988 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3990 door_state &= ~DOOR_COPY_BACK;
3993 return MoveDoor(door_state);
3996 unsigned int CloseDoor(unsigned int door_state)
3998 unsigned int old_door_state = GetDoorState();
4000 if (!(door_state & DOOR_NO_COPY_BACK))
4002 if (old_door_state & DOOR_OPEN_1)
4003 BlitBitmap(backbuffer, bitmap_db_door_1,
4004 DX, DY, DXSIZE, DYSIZE, 0, 0);
4006 if (old_door_state & DOOR_OPEN_2)
4007 BlitBitmap(backbuffer, bitmap_db_door_2,
4008 VX, VY, VXSIZE, VYSIZE, 0, 0);
4010 door_state &= ~DOOR_NO_COPY_BACK;
4013 return MoveDoor(door_state);
4016 unsigned int GetDoorState()
4018 return MoveDoor(DOOR_GET_STATE);
4021 unsigned int SetDoorState(unsigned int door_state)
4023 return MoveDoor(door_state | DOOR_SET_STATE);
4026 int euclid(int a, int b)
4028 return (b ? euclid(b, a % b) : a);
4031 unsigned int MoveDoor(unsigned int door_state)
4033 struct Rect door_rect_list[] =
4035 { DX, DY, DXSIZE, DYSIZE },
4036 { VX, VY, VXSIZE, VYSIZE }
4038 static int door1 = DOOR_OPEN_1;
4039 static int door2 = DOOR_CLOSE_2;
4040 unsigned int door_delay = 0;
4041 unsigned int door_delay_value;
4044 if (door_1.width < 0 || door_1.width > DXSIZE)
4045 door_1.width = DXSIZE;
4046 if (door_1.height < 0 || door_1.height > DYSIZE)
4047 door_1.height = DYSIZE;
4048 if (door_2.width < 0 || door_2.width > VXSIZE)
4049 door_2.width = VXSIZE;
4050 if (door_2.height < 0 || door_2.height > VYSIZE)
4051 door_2.height = VYSIZE;
4053 if (door_state == DOOR_GET_STATE)
4054 return (door1 | door2);
4056 if (door_state & DOOR_SET_STATE)
4058 if (door_state & DOOR_ACTION_1)
4059 door1 = door_state & DOOR_ACTION_1;
4060 if (door_state & DOOR_ACTION_2)
4061 door2 = door_state & DOOR_ACTION_2;
4063 return (door1 | door2);
4066 if (!(door_state & DOOR_FORCE_REDRAW))
4068 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4069 door_state &= ~DOOR_OPEN_1;
4070 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4071 door_state &= ~DOOR_CLOSE_1;
4072 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4073 door_state &= ~DOOR_OPEN_2;
4074 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4075 door_state &= ~DOOR_CLOSE_2;
4078 if (global.autoplay_leveldir)
4080 door_state |= DOOR_NO_DELAY;
4081 door_state &= ~DOOR_CLOSE_ALL;
4084 if (game_status == GAME_MODE_EDITOR)
4085 door_state |= DOOR_NO_DELAY;
4087 if (door_state & DOOR_ACTION)
4089 boolean door_panel_drawn[NUM_DOORS];
4090 boolean panel_has_doors[NUM_DOORS];
4091 boolean door_part_skip[MAX_DOOR_PARTS];
4092 boolean door_part_done[MAX_DOOR_PARTS];
4093 boolean door_part_done_all;
4094 int num_steps[MAX_DOOR_PARTS];
4095 int max_move_delay = 0; // delay for complete animations of all doors
4096 int max_step_delay = 0; // delay (ms) between two animation frames
4097 int num_move_steps = 0; // number of animation steps for all doors
4098 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4099 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4100 int current_move_delay = 0;
4104 for (i = 0; i < NUM_DOORS; i++)
4105 panel_has_doors[i] = FALSE;
4107 for (i = 0; i < MAX_DOOR_PARTS; i++)
4109 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4110 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4111 int door_token = dpc->door_token;
4113 door_part_done[i] = FALSE;
4114 door_part_skip[i] = (!(door_state & door_token) ||
4118 for (i = 0; i < MAX_DOOR_PARTS; i++)
4120 int nr = door_part_order[i].nr;
4121 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4122 struct DoorPartPosInfo *pos = dpc->pos;
4123 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4124 int door_token = dpc->door_token;
4125 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4126 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4127 int step_xoffset = ABS(pos->step_xoffset);
4128 int step_yoffset = ABS(pos->step_yoffset);
4129 int step_delay = pos->step_delay;
4130 int current_door_state = door_state & door_token;
4131 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4132 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4133 boolean part_opening = (is_panel ? door_closing : door_opening);
4134 int start_step = (part_opening ? pos->start_step_opening :
4135 pos->start_step_closing);
4136 float move_xsize = (step_xoffset ? g->width : 0);
4137 float move_ysize = (step_yoffset ? g->height : 0);
4138 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4139 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4140 int move_steps = (move_xsteps && move_ysteps ?
4141 MIN(move_xsteps, move_ysteps) :
4142 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4143 int move_delay = move_steps * step_delay;
4145 if (door_part_skip[nr])
4148 max_move_delay = MAX(max_move_delay, move_delay);
4149 max_step_delay = (max_step_delay == 0 ? step_delay :
4150 euclid(max_step_delay, step_delay));
4151 num_steps[nr] = move_steps;
4155 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4157 panel_has_doors[door_index] = TRUE;
4161 num_move_steps = max_move_delay / max_step_delay;
4162 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4164 door_delay_value = max_step_delay;
4166 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4168 start = num_move_steps - 1;
4172 /* opening door sound has priority over simultaneously closing door */
4173 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4174 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4175 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4176 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4179 for (k = start; k < num_move_steps; k++)
4181 door_part_done_all = TRUE;
4183 for (i = 0; i < NUM_DOORS; i++)
4184 door_panel_drawn[i] = FALSE;
4186 for (i = 0; i < MAX_DOOR_PARTS; i++)
4188 int nr = door_part_order[i].nr;
4189 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4190 struct DoorPartPosInfo *pos = dpc->pos;
4191 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4192 int door_token = dpc->door_token;
4193 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4194 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4195 boolean is_panel_and_door_has_closed = FALSE;
4196 struct Rect *door_rect = &door_rect_list[door_index];
4197 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4199 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4200 int current_door_state = door_state & door_token;
4201 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4202 boolean door_closing = !door_opening;
4203 boolean part_opening = (is_panel ? door_closing : door_opening);
4204 boolean part_closing = !part_opening;
4205 int start_step = (part_opening ? pos->start_step_opening :
4206 pos->start_step_closing);
4207 int step_delay = pos->step_delay;
4208 int step_factor = step_delay / max_step_delay;
4209 int k1 = (step_factor ? k / step_factor + 1 : k);
4210 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4211 int kk = MAX(0, k2);
4214 int src_x, src_y, src_xx, src_yy;
4215 int dst_x, dst_y, dst_xx, dst_yy;
4218 if (door_part_skip[nr])
4221 if (!(door_state & door_token))
4229 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4230 int kk_door = MAX(0, k2_door);
4231 int sync_frame = kk_door * door_delay_value;
4232 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4234 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4239 if (!door_panel_drawn[door_index])
4241 ClearRectangle(drawto, door_rect->x, door_rect->y,
4242 door_rect->width, door_rect->height);
4244 door_panel_drawn[door_index] = TRUE;
4247 // draw opening or closing door parts
4249 if (pos->step_xoffset < 0) // door part on right side
4252 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4255 if (dst_xx + width > door_rect->width)
4256 width = door_rect->width - dst_xx;
4258 else // door part on left side
4261 dst_xx = pos->x - kk * pos->step_xoffset;
4265 src_xx = ABS(dst_xx);
4269 width = g->width - src_xx;
4271 // printf("::: k == %d [%d] \n", k, start_step);
4274 if (pos->step_yoffset < 0) // door part on bottom side
4277 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4280 if (dst_yy + height > door_rect->height)
4281 height = door_rect->height - dst_yy;
4283 else // door part on top side
4286 dst_yy = pos->y - kk * pos->step_yoffset;
4290 src_yy = ABS(dst_yy);
4294 height = g->height - src_yy;
4297 src_x = g_src_x + src_xx;
4298 src_y = g_src_y + src_yy;
4300 dst_x = door_rect->x + dst_xx;
4301 dst_y = door_rect->y + dst_yy;
4303 is_panel_and_door_has_closed =
4306 panel_has_doors[door_index] &&
4307 k >= num_move_steps_doors_only - 1);
4309 if (width >= 0 && width <= g->width &&
4310 height >= 0 && height <= g->height &&
4311 !is_panel_and_door_has_closed)
4313 if (is_panel || !pos->draw_masked)
4314 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4317 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4321 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4323 if ((part_opening && (width < 0 || height < 0)) ||
4324 (part_closing && (width >= g->width && height >= g->height)))
4325 door_part_done[nr] = TRUE;
4327 // continue door part animations, but not panel after door has closed
4328 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4329 door_part_done_all = FALSE;
4332 if (!(door_state & DOOR_NO_DELAY))
4336 if (game_status == GAME_MODE_MAIN)
4339 WaitUntilDelayReached(&door_delay, door_delay_value);
4341 current_move_delay += max_step_delay;
4344 if (door_part_done_all)
4349 if (door_state & DOOR_ACTION_1)
4350 door1 = door_state & DOOR_ACTION_1;
4351 if (door_state & DOOR_ACTION_2)
4352 door2 = door_state & DOOR_ACTION_2;
4354 return (door1 | door2);
4357 void DrawSpecialEditorDoor()
4359 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4360 int top_border_width = gfx1->width;
4361 int top_border_height = gfx1->height;
4362 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4363 int ex = EX - outer_border;
4364 int ey = EY - outer_border;
4365 int vy = VY - outer_border;
4366 int exsize = EXSIZE + 2 * outer_border;
4368 /* draw bigger level editor toolbox window */
4369 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4370 top_border_width, top_border_height, ex, ey - top_border_height);
4371 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4372 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4374 redraw_mask |= REDRAW_ALL;
4377 void UndrawSpecialEditorDoor()
4379 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4380 int top_border_width = gfx1->width;
4381 int top_border_height = gfx1->height;
4382 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4383 int ex = EX - outer_border;
4384 int ey = EY - outer_border;
4385 int ey_top = ey - top_border_height;
4386 int exsize = EXSIZE + 2 * outer_border;
4387 int eysize = EYSIZE + 2 * outer_border;
4389 /* draw normal tape recorder window */
4390 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4392 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4393 ex, ey_top, top_border_width, top_border_height,
4395 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4396 ex, ey, exsize, eysize, ex, ey);
4400 // if screen background is set to "[NONE]", clear editor toolbox window
4401 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4402 ClearRectangle(drawto, ex, ey, exsize, eysize);
4405 redraw_mask |= REDRAW_ALL;
4409 /* ---------- new tool button stuff ---------------------------------------- */
4414 struct TextPosInfo *pos;
4417 } toolbutton_info[NUM_TOOL_BUTTONS] =
4420 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4421 TOOL_CTRL_ID_YES, "yes"
4424 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4425 TOOL_CTRL_ID_NO, "no"
4428 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4429 TOOL_CTRL_ID_CONFIRM, "confirm"
4432 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4433 TOOL_CTRL_ID_PLAYER_1, "player 1"
4436 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4437 TOOL_CTRL_ID_PLAYER_2, "player 2"
4440 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4441 TOOL_CTRL_ID_PLAYER_3, "player 3"
4444 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4445 TOOL_CTRL_ID_PLAYER_4, "player 4"
4449 void CreateToolButtons()
4453 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4455 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4456 struct TextPosInfo *pos = toolbutton_info[i].pos;
4457 struct GadgetInfo *gi;
4458 Bitmap *deco_bitmap = None;
4459 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4460 unsigned int event_mask = GD_EVENT_RELEASED;
4463 int gd_x = gfx->src_x;
4464 int gd_y = gfx->src_y;
4465 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4466 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4469 if (global.use_envelope_request)
4470 setRequestPosition(&dx, &dy, TRUE);
4472 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4474 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4476 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4477 pos->size, &deco_bitmap, &deco_x, &deco_y);
4478 deco_xpos = (gfx->width - pos->size) / 2;
4479 deco_ypos = (gfx->height - pos->size) / 2;
4482 gi = CreateGadget(GDI_CUSTOM_ID, id,
4483 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4484 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4485 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4486 GDI_WIDTH, gfx->width,
4487 GDI_HEIGHT, gfx->height,
4488 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4489 GDI_STATE, GD_BUTTON_UNPRESSED,
4490 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4491 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4492 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4493 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4494 GDI_DECORATION_SIZE, pos->size, pos->size,
4495 GDI_DECORATION_SHIFTING, 1, 1,
4496 GDI_DIRECT_DRAW, FALSE,
4497 GDI_EVENT_MASK, event_mask,
4498 GDI_CALLBACK_ACTION, HandleToolButtons,
4502 Error(ERR_EXIT, "cannot create gadget");
4504 tool_gadget[id] = gi;
4508 void FreeToolButtons()
4512 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4513 FreeGadget(tool_gadget[i]);
4516 static void UnmapToolButtons()
4520 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4521 UnmapGadget(tool_gadget[i]);
4524 static void HandleToolButtons(struct GadgetInfo *gi)
4526 request_gadget_id = gi->custom_id;
4529 static struct Mapping_EM_to_RND_object
4532 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4533 boolean is_backside; /* backside of moving element */
4539 em_object_mapping_list[] =
4542 Xblank, TRUE, FALSE,
4546 Yacid_splash_eB, FALSE, FALSE,
4547 EL_ACID_SPLASH_RIGHT, -1, -1
4550 Yacid_splash_wB, FALSE, FALSE,
4551 EL_ACID_SPLASH_LEFT, -1, -1
4554 #ifdef EM_ENGINE_BAD_ROLL
4556 Xstone_force_e, FALSE, FALSE,
4557 EL_ROCK, -1, MV_BIT_RIGHT
4560 Xstone_force_w, FALSE, FALSE,
4561 EL_ROCK, -1, MV_BIT_LEFT
4564 Xnut_force_e, FALSE, FALSE,
4565 EL_NUT, -1, MV_BIT_RIGHT
4568 Xnut_force_w, FALSE, FALSE,
4569 EL_NUT, -1, MV_BIT_LEFT
4572 Xspring_force_e, FALSE, FALSE,
4573 EL_SPRING, -1, MV_BIT_RIGHT
4576 Xspring_force_w, FALSE, FALSE,
4577 EL_SPRING, -1, MV_BIT_LEFT
4580 Xemerald_force_e, FALSE, FALSE,
4581 EL_EMERALD, -1, MV_BIT_RIGHT
4584 Xemerald_force_w, FALSE, FALSE,
4585 EL_EMERALD, -1, MV_BIT_LEFT
4588 Xdiamond_force_e, FALSE, FALSE,
4589 EL_DIAMOND, -1, MV_BIT_RIGHT
4592 Xdiamond_force_w, FALSE, FALSE,
4593 EL_DIAMOND, -1, MV_BIT_LEFT
4596 Xbomb_force_e, FALSE, FALSE,
4597 EL_BOMB, -1, MV_BIT_RIGHT
4600 Xbomb_force_w, FALSE, FALSE,
4601 EL_BOMB, -1, MV_BIT_LEFT
4603 #endif /* EM_ENGINE_BAD_ROLL */
4606 Xstone, TRUE, FALSE,
4610 Xstone_pause, FALSE, FALSE,
4614 Xstone_fall, FALSE, FALSE,
4618 Ystone_s, FALSE, FALSE,
4619 EL_ROCK, ACTION_FALLING, -1
4622 Ystone_sB, FALSE, TRUE,
4623 EL_ROCK, ACTION_FALLING, -1
4626 Ystone_e, FALSE, FALSE,
4627 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4630 Ystone_eB, FALSE, TRUE,
4631 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4634 Ystone_w, FALSE, FALSE,
4635 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4638 Ystone_wB, FALSE, TRUE,
4639 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4646 Xnut_pause, FALSE, FALSE,
4650 Xnut_fall, FALSE, FALSE,
4654 Ynut_s, FALSE, FALSE,
4655 EL_NUT, ACTION_FALLING, -1
4658 Ynut_sB, FALSE, TRUE,
4659 EL_NUT, ACTION_FALLING, -1
4662 Ynut_e, FALSE, FALSE,
4663 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4666 Ynut_eB, FALSE, TRUE,
4667 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4670 Ynut_w, FALSE, FALSE,
4671 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4674 Ynut_wB, FALSE, TRUE,
4675 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4678 Xbug_n, TRUE, FALSE,
4682 Xbug_e, TRUE, FALSE,
4683 EL_BUG_RIGHT, -1, -1
4686 Xbug_s, TRUE, FALSE,
4690 Xbug_w, TRUE, FALSE,
4694 Xbug_gon, FALSE, FALSE,
4698 Xbug_goe, FALSE, FALSE,
4699 EL_BUG_RIGHT, -1, -1
4702 Xbug_gos, FALSE, FALSE,
4706 Xbug_gow, FALSE, FALSE,
4710 Ybug_n, FALSE, FALSE,
4711 EL_BUG, ACTION_MOVING, MV_BIT_UP
4714 Ybug_nB, FALSE, TRUE,
4715 EL_BUG, ACTION_MOVING, MV_BIT_UP
4718 Ybug_e, FALSE, FALSE,
4719 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4722 Ybug_eB, FALSE, TRUE,
4723 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4726 Ybug_s, FALSE, FALSE,
4727 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4730 Ybug_sB, FALSE, TRUE,
4731 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4734 Ybug_w, FALSE, FALSE,
4735 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4738 Ybug_wB, FALSE, TRUE,
4739 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4742 Ybug_w_n, FALSE, FALSE,
4743 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4746 Ybug_n_e, FALSE, FALSE,
4747 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4750 Ybug_e_s, FALSE, FALSE,
4751 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4754 Ybug_s_w, FALSE, FALSE,
4755 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4758 Ybug_e_n, FALSE, FALSE,
4759 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4762 Ybug_s_e, FALSE, FALSE,
4763 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4766 Ybug_w_s, FALSE, FALSE,
4767 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4770 Ybug_n_w, FALSE, FALSE,
4771 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4774 Ybug_stone, FALSE, FALSE,
4775 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4778 Ybug_spring, FALSE, FALSE,
4779 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4782 Xtank_n, TRUE, FALSE,
4783 EL_SPACESHIP_UP, -1, -1
4786 Xtank_e, TRUE, FALSE,
4787 EL_SPACESHIP_RIGHT, -1, -1
4790 Xtank_s, TRUE, FALSE,
4791 EL_SPACESHIP_DOWN, -1, -1
4794 Xtank_w, TRUE, FALSE,
4795 EL_SPACESHIP_LEFT, -1, -1
4798 Xtank_gon, FALSE, FALSE,
4799 EL_SPACESHIP_UP, -1, -1
4802 Xtank_goe, FALSE, FALSE,
4803 EL_SPACESHIP_RIGHT, -1, -1
4806 Xtank_gos, FALSE, FALSE,
4807 EL_SPACESHIP_DOWN, -1, -1
4810 Xtank_gow, FALSE, FALSE,
4811 EL_SPACESHIP_LEFT, -1, -1
4814 Ytank_n, FALSE, FALSE,
4815 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4818 Ytank_nB, FALSE, TRUE,
4819 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4822 Ytank_e, FALSE, FALSE,
4823 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4826 Ytank_eB, FALSE, TRUE,
4827 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4830 Ytank_s, FALSE, FALSE,
4831 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4834 Ytank_sB, FALSE, TRUE,
4835 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4838 Ytank_w, FALSE, FALSE,
4839 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4842 Ytank_wB, FALSE, TRUE,
4843 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4846 Ytank_w_n, FALSE, FALSE,
4847 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4850 Ytank_n_e, FALSE, FALSE,
4851 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4854 Ytank_e_s, FALSE, FALSE,
4855 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4858 Ytank_s_w, FALSE, FALSE,
4859 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4862 Ytank_e_n, FALSE, FALSE,
4863 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4866 Ytank_s_e, FALSE, FALSE,
4867 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4870 Ytank_w_s, FALSE, FALSE,
4871 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4874 Ytank_n_w, FALSE, FALSE,
4875 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4878 Ytank_stone, FALSE, FALSE,
4879 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4882 Ytank_spring, FALSE, FALSE,
4883 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4886 Xandroid, TRUE, FALSE,
4887 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4890 Xandroid_1_n, FALSE, FALSE,
4891 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4894 Xandroid_2_n, FALSE, FALSE,
4895 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4898 Xandroid_1_e, FALSE, FALSE,
4899 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4902 Xandroid_2_e, FALSE, FALSE,
4903 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4906 Xandroid_1_w, FALSE, FALSE,
4907 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4910 Xandroid_2_w, FALSE, FALSE,
4911 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4914 Xandroid_1_s, FALSE, FALSE,
4915 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4918 Xandroid_2_s, FALSE, FALSE,
4919 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4922 Yandroid_n, FALSE, FALSE,
4923 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4926 Yandroid_nB, FALSE, TRUE,
4927 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4930 Yandroid_ne, FALSE, FALSE,
4931 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4934 Yandroid_neB, FALSE, TRUE,
4935 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4938 Yandroid_e, FALSE, FALSE,
4939 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4942 Yandroid_eB, FALSE, TRUE,
4943 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4946 Yandroid_se, FALSE, FALSE,
4947 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4950 Yandroid_seB, FALSE, TRUE,
4951 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4954 Yandroid_s, FALSE, FALSE,
4955 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4958 Yandroid_sB, FALSE, TRUE,
4959 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4962 Yandroid_sw, FALSE, FALSE,
4963 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4966 Yandroid_swB, FALSE, TRUE,
4967 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4970 Yandroid_w, FALSE, FALSE,
4971 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4974 Yandroid_wB, FALSE, TRUE,
4975 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4978 Yandroid_nw, FALSE, FALSE,
4979 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4982 Yandroid_nwB, FALSE, TRUE,
4983 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4986 Xspring, TRUE, FALSE,
4990 Xspring_pause, FALSE, FALSE,
4994 Xspring_e, FALSE, FALSE,
4998 Xspring_w, FALSE, FALSE,
5002 Xspring_fall, FALSE, FALSE,
5006 Yspring_s, FALSE, FALSE,
5007 EL_SPRING, ACTION_FALLING, -1
5010 Yspring_sB, FALSE, TRUE,
5011 EL_SPRING, ACTION_FALLING, -1
5014 Yspring_e, FALSE, FALSE,
5015 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5018 Yspring_eB, FALSE, TRUE,
5019 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5022 Yspring_w, FALSE, FALSE,
5023 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5026 Yspring_wB, FALSE, TRUE,
5027 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5030 Yspring_kill_e, FALSE, FALSE,
5031 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5034 Yspring_kill_eB, FALSE, TRUE,
5035 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5038 Yspring_kill_w, FALSE, FALSE,
5039 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5042 Yspring_kill_wB, FALSE, TRUE,
5043 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5046 Xeater_n, TRUE, FALSE,
5047 EL_YAMYAM_UP, -1, -1
5050 Xeater_e, TRUE, FALSE,
5051 EL_YAMYAM_RIGHT, -1, -1
5054 Xeater_w, TRUE, FALSE,
5055 EL_YAMYAM_LEFT, -1, -1
5058 Xeater_s, TRUE, FALSE,
5059 EL_YAMYAM_DOWN, -1, -1
5062 Yeater_n, FALSE, FALSE,
5063 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5066 Yeater_nB, FALSE, TRUE,
5067 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5070 Yeater_e, FALSE, FALSE,
5071 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5074 Yeater_eB, FALSE, TRUE,
5075 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5078 Yeater_s, FALSE, FALSE,
5079 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5082 Yeater_sB, FALSE, TRUE,
5083 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5086 Yeater_w, FALSE, FALSE,
5087 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5090 Yeater_wB, FALSE, TRUE,
5091 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5094 Yeater_stone, FALSE, FALSE,
5095 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5098 Yeater_spring, FALSE, FALSE,
5099 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5102 Xalien, TRUE, FALSE,
5106 Xalien_pause, FALSE, FALSE,
5110 Yalien_n, FALSE, FALSE,
5111 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5114 Yalien_nB, FALSE, TRUE,
5115 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5118 Yalien_e, FALSE, FALSE,
5119 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5122 Yalien_eB, FALSE, TRUE,
5123 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5126 Yalien_s, FALSE, FALSE,
5127 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5130 Yalien_sB, FALSE, TRUE,
5131 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5134 Yalien_w, FALSE, FALSE,
5135 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5138 Yalien_wB, FALSE, TRUE,
5139 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5142 Yalien_stone, FALSE, FALSE,
5143 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5146 Yalien_spring, FALSE, FALSE,
5147 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5150 Xemerald, TRUE, FALSE,
5154 Xemerald_pause, FALSE, FALSE,
5158 Xemerald_fall, FALSE, FALSE,
5162 Xemerald_shine, FALSE, FALSE,
5163 EL_EMERALD, ACTION_TWINKLING, -1
5166 Yemerald_s, FALSE, FALSE,
5167 EL_EMERALD, ACTION_FALLING, -1
5170 Yemerald_sB, FALSE, TRUE,
5171 EL_EMERALD, ACTION_FALLING, -1
5174 Yemerald_e, FALSE, FALSE,
5175 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5178 Yemerald_eB, FALSE, TRUE,
5179 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5182 Yemerald_w, FALSE, FALSE,
5183 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5186 Yemerald_wB, FALSE, TRUE,
5187 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5190 Yemerald_eat, FALSE, FALSE,
5191 EL_EMERALD, ACTION_COLLECTING, -1
5194 Yemerald_stone, FALSE, FALSE,
5195 EL_NUT, ACTION_BREAKING, -1
5198 Xdiamond, TRUE, FALSE,
5202 Xdiamond_pause, FALSE, FALSE,
5206 Xdiamond_fall, FALSE, FALSE,
5210 Xdiamond_shine, FALSE, FALSE,
5211 EL_DIAMOND, ACTION_TWINKLING, -1
5214 Ydiamond_s, FALSE, FALSE,
5215 EL_DIAMOND, ACTION_FALLING, -1
5218 Ydiamond_sB, FALSE, TRUE,
5219 EL_DIAMOND, ACTION_FALLING, -1
5222 Ydiamond_e, FALSE, FALSE,
5223 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5226 Ydiamond_eB, FALSE, TRUE,
5227 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5230 Ydiamond_w, FALSE, FALSE,
5231 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5234 Ydiamond_wB, FALSE, TRUE,
5235 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5238 Ydiamond_eat, FALSE, FALSE,
5239 EL_DIAMOND, ACTION_COLLECTING, -1
5242 Ydiamond_stone, FALSE, FALSE,
5243 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5246 Xdrip_fall, TRUE, FALSE,
5247 EL_AMOEBA_DROP, -1, -1
5250 Xdrip_stretch, FALSE, FALSE,
5251 EL_AMOEBA_DROP, ACTION_FALLING, -1
5254 Xdrip_stretchB, FALSE, TRUE,
5255 EL_AMOEBA_DROP, ACTION_FALLING, -1
5258 Xdrip_eat, FALSE, FALSE,
5259 EL_AMOEBA_DROP, ACTION_GROWING, -1
5262 Ydrip_s1, FALSE, FALSE,
5263 EL_AMOEBA_DROP, ACTION_FALLING, -1
5266 Ydrip_s1B, FALSE, TRUE,
5267 EL_AMOEBA_DROP, ACTION_FALLING, -1
5270 Ydrip_s2, FALSE, FALSE,
5271 EL_AMOEBA_DROP, ACTION_FALLING, -1
5274 Ydrip_s2B, FALSE, TRUE,
5275 EL_AMOEBA_DROP, ACTION_FALLING, -1
5282 Xbomb_pause, FALSE, FALSE,
5286 Xbomb_fall, FALSE, FALSE,
5290 Ybomb_s, FALSE, FALSE,
5291 EL_BOMB, ACTION_FALLING, -1
5294 Ybomb_sB, FALSE, TRUE,
5295 EL_BOMB, ACTION_FALLING, -1
5298 Ybomb_e, FALSE, FALSE,
5299 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5302 Ybomb_eB, FALSE, TRUE,
5303 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5306 Ybomb_w, FALSE, FALSE,
5307 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5310 Ybomb_wB, FALSE, TRUE,
5311 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5314 Ybomb_eat, FALSE, FALSE,
5315 EL_BOMB, ACTION_ACTIVATING, -1
5318 Xballoon, TRUE, FALSE,
5322 Yballoon_n, FALSE, FALSE,
5323 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5326 Yballoon_nB, FALSE, TRUE,
5327 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5330 Yballoon_e, FALSE, FALSE,
5331 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5334 Yballoon_eB, FALSE, TRUE,
5335 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5338 Yballoon_s, FALSE, FALSE,
5339 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5342 Yballoon_sB, FALSE, TRUE,
5343 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5346 Yballoon_w, FALSE, FALSE,
5347 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5350 Yballoon_wB, FALSE, TRUE,
5351 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5354 Xgrass, TRUE, FALSE,
5355 EL_EMC_GRASS, -1, -1
5358 Ygrass_nB, FALSE, FALSE,
5359 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5362 Ygrass_eB, FALSE, FALSE,
5363 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5366 Ygrass_sB, FALSE, FALSE,
5367 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5370 Ygrass_wB, FALSE, FALSE,
5371 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5378 Ydirt_nB, FALSE, FALSE,
5379 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5382 Ydirt_eB, FALSE, FALSE,
5383 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5386 Ydirt_sB, FALSE, FALSE,
5387 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5390 Ydirt_wB, FALSE, FALSE,
5391 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5394 Xacid_ne, TRUE, FALSE,
5395 EL_ACID_POOL_TOPRIGHT, -1, -1
5398 Xacid_se, TRUE, FALSE,
5399 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5402 Xacid_s, TRUE, FALSE,
5403 EL_ACID_POOL_BOTTOM, -1, -1
5406 Xacid_sw, TRUE, FALSE,
5407 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5410 Xacid_nw, TRUE, FALSE,
5411 EL_ACID_POOL_TOPLEFT, -1, -1
5414 Xacid_1, TRUE, FALSE,
5418 Xacid_2, FALSE, FALSE,
5422 Xacid_3, FALSE, FALSE,
5426 Xacid_4, FALSE, FALSE,
5430 Xacid_5, FALSE, FALSE,
5434 Xacid_6, FALSE, FALSE,
5438 Xacid_7, FALSE, FALSE,
5442 Xacid_8, FALSE, FALSE,
5446 Xball_1, TRUE, FALSE,
5447 EL_EMC_MAGIC_BALL, -1, -1
5450 Xball_1B, FALSE, FALSE,
5451 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5454 Xball_2, FALSE, FALSE,
5455 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5458 Xball_2B, FALSE, FALSE,
5459 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5462 Yball_eat, FALSE, FALSE,
5463 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5466 Ykey_1_eat, FALSE, FALSE,
5467 EL_EM_KEY_1, ACTION_COLLECTING, -1
5470 Ykey_2_eat, FALSE, FALSE,
5471 EL_EM_KEY_2, ACTION_COLLECTING, -1
5474 Ykey_3_eat, FALSE, FALSE,
5475 EL_EM_KEY_3, ACTION_COLLECTING, -1
5478 Ykey_4_eat, FALSE, FALSE,
5479 EL_EM_KEY_4, ACTION_COLLECTING, -1
5482 Ykey_5_eat, FALSE, FALSE,
5483 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5486 Ykey_6_eat, FALSE, FALSE,
5487 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5490 Ykey_7_eat, FALSE, FALSE,
5491 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5494 Ykey_8_eat, FALSE, FALSE,
5495 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5498 Ylenses_eat, FALSE, FALSE,
5499 EL_EMC_LENSES, ACTION_COLLECTING, -1
5502 Ymagnify_eat, FALSE, FALSE,
5503 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5506 Ygrass_eat, FALSE, FALSE,
5507 EL_EMC_GRASS, ACTION_SNAPPING, -1
5510 Ydirt_eat, FALSE, FALSE,
5511 EL_SAND, ACTION_SNAPPING, -1
5514 Xgrow_ns, TRUE, FALSE,
5515 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5518 Ygrow_ns_eat, FALSE, FALSE,
5519 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5522 Xgrow_ew, TRUE, FALSE,
5523 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5526 Ygrow_ew_eat, FALSE, FALSE,
5527 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5530 Xwonderwall, TRUE, FALSE,
5531 EL_MAGIC_WALL, -1, -1
5534 XwonderwallB, FALSE, FALSE,
5535 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5538 Xamoeba_1, TRUE, FALSE,
5539 EL_AMOEBA_DRY, ACTION_OTHER, -1
5542 Xamoeba_2, FALSE, FALSE,
5543 EL_AMOEBA_DRY, ACTION_OTHER, -1
5546 Xamoeba_3, FALSE, FALSE,
5547 EL_AMOEBA_DRY, ACTION_OTHER, -1
5550 Xamoeba_4, FALSE, FALSE,
5551 EL_AMOEBA_DRY, ACTION_OTHER, -1
5554 Xamoeba_5, TRUE, FALSE,
5555 EL_AMOEBA_WET, ACTION_OTHER, -1
5558 Xamoeba_6, FALSE, FALSE,
5559 EL_AMOEBA_WET, ACTION_OTHER, -1
5562 Xamoeba_7, FALSE, FALSE,
5563 EL_AMOEBA_WET, ACTION_OTHER, -1
5566 Xamoeba_8, FALSE, FALSE,
5567 EL_AMOEBA_WET, ACTION_OTHER, -1
5570 Xdoor_1, TRUE, FALSE,
5571 EL_EM_GATE_1, -1, -1
5574 Xdoor_2, TRUE, FALSE,
5575 EL_EM_GATE_2, -1, -1
5578 Xdoor_3, TRUE, FALSE,
5579 EL_EM_GATE_3, -1, -1
5582 Xdoor_4, TRUE, FALSE,
5583 EL_EM_GATE_4, -1, -1
5586 Xdoor_5, TRUE, FALSE,
5587 EL_EMC_GATE_5, -1, -1
5590 Xdoor_6, TRUE, FALSE,
5591 EL_EMC_GATE_6, -1, -1
5594 Xdoor_7, TRUE, FALSE,
5595 EL_EMC_GATE_7, -1, -1
5598 Xdoor_8, TRUE, FALSE,
5599 EL_EMC_GATE_8, -1, -1
5602 Xkey_1, TRUE, FALSE,
5606 Xkey_2, TRUE, FALSE,
5610 Xkey_3, TRUE, FALSE,
5614 Xkey_4, TRUE, FALSE,
5618 Xkey_5, TRUE, FALSE,
5619 EL_EMC_KEY_5, -1, -1
5622 Xkey_6, TRUE, FALSE,
5623 EL_EMC_KEY_6, -1, -1
5626 Xkey_7, TRUE, FALSE,
5627 EL_EMC_KEY_7, -1, -1
5630 Xkey_8, TRUE, FALSE,
5631 EL_EMC_KEY_8, -1, -1
5634 Xwind_n, TRUE, FALSE,
5635 EL_BALLOON_SWITCH_UP, -1, -1
5638 Xwind_e, TRUE, FALSE,
5639 EL_BALLOON_SWITCH_RIGHT, -1, -1
5642 Xwind_s, TRUE, FALSE,
5643 EL_BALLOON_SWITCH_DOWN, -1, -1
5646 Xwind_w, TRUE, FALSE,
5647 EL_BALLOON_SWITCH_LEFT, -1, -1
5650 Xwind_nesw, TRUE, FALSE,
5651 EL_BALLOON_SWITCH_ANY, -1, -1
5654 Xwind_stop, TRUE, FALSE,
5655 EL_BALLOON_SWITCH_NONE, -1, -1
5659 EL_EM_EXIT_CLOSED, -1, -1
5662 Xexit_1, TRUE, FALSE,
5663 EL_EM_EXIT_OPEN, -1, -1
5666 Xexit_2, FALSE, FALSE,
5667 EL_EM_EXIT_OPEN, -1, -1
5670 Xexit_3, FALSE, FALSE,
5671 EL_EM_EXIT_OPEN, -1, -1
5674 Xdynamite, TRUE, FALSE,
5675 EL_EM_DYNAMITE, -1, -1
5678 Ydynamite_eat, FALSE, FALSE,
5679 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5682 Xdynamite_1, TRUE, FALSE,
5683 EL_EM_DYNAMITE_ACTIVE, -1, -1
5686 Xdynamite_2, FALSE, FALSE,
5687 EL_EM_DYNAMITE_ACTIVE, -1, -1
5690 Xdynamite_3, FALSE, FALSE,
5691 EL_EM_DYNAMITE_ACTIVE, -1, -1
5694 Xdynamite_4, FALSE, FALSE,
5695 EL_EM_DYNAMITE_ACTIVE, -1, -1
5698 Xbumper, TRUE, FALSE,
5699 EL_EMC_SPRING_BUMPER, -1, -1
5702 XbumperB, FALSE, FALSE,
5703 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5706 Xwheel, TRUE, FALSE,
5707 EL_ROBOT_WHEEL, -1, -1
5710 XwheelB, FALSE, FALSE,
5711 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5714 Xswitch, TRUE, FALSE,
5715 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5718 XswitchB, FALSE, FALSE,
5719 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5723 EL_QUICKSAND_EMPTY, -1, -1
5726 Xsand_stone, TRUE, FALSE,
5727 EL_QUICKSAND_FULL, -1, -1
5730 Xsand_stonein_1, FALSE, TRUE,
5731 EL_ROCK, ACTION_FILLING, -1
5734 Xsand_stonein_2, FALSE, TRUE,
5735 EL_ROCK, ACTION_FILLING, -1
5738 Xsand_stonein_3, FALSE, TRUE,
5739 EL_ROCK, ACTION_FILLING, -1
5742 Xsand_stonein_4, FALSE, TRUE,
5743 EL_ROCK, ACTION_FILLING, -1
5746 Xsand_stonesand_1, FALSE, FALSE,
5747 EL_QUICKSAND_EMPTYING, -1, -1
5750 Xsand_stonesand_2, FALSE, FALSE,
5751 EL_QUICKSAND_EMPTYING, -1, -1
5754 Xsand_stonesand_3, FALSE, FALSE,
5755 EL_QUICKSAND_EMPTYING, -1, -1
5758 Xsand_stonesand_4, FALSE, FALSE,
5759 EL_QUICKSAND_EMPTYING, -1, -1
5762 Xsand_stonesand_quickout_1, FALSE, FALSE,
5763 EL_QUICKSAND_EMPTYING, -1, -1
5766 Xsand_stonesand_quickout_2, FALSE, FALSE,
5767 EL_QUICKSAND_EMPTYING, -1, -1
5770 Xsand_stoneout_1, FALSE, FALSE,
5771 EL_ROCK, ACTION_EMPTYING, -1
5774 Xsand_stoneout_2, FALSE, FALSE,
5775 EL_ROCK, ACTION_EMPTYING, -1
5778 Xsand_sandstone_1, FALSE, FALSE,
5779 EL_QUICKSAND_FILLING, -1, -1
5782 Xsand_sandstone_2, FALSE, FALSE,
5783 EL_QUICKSAND_FILLING, -1, -1
5786 Xsand_sandstone_3, FALSE, FALSE,
5787 EL_QUICKSAND_FILLING, -1, -1
5790 Xsand_sandstone_4, FALSE, FALSE,
5791 EL_QUICKSAND_FILLING, -1, -1
5794 Xplant, TRUE, FALSE,
5795 EL_EMC_PLANT, -1, -1
5798 Yplant, FALSE, FALSE,
5799 EL_EMC_PLANT, -1, -1
5802 Xlenses, TRUE, FALSE,
5803 EL_EMC_LENSES, -1, -1
5806 Xmagnify, TRUE, FALSE,
5807 EL_EMC_MAGNIFIER, -1, -1
5810 Xdripper, TRUE, FALSE,
5811 EL_EMC_DRIPPER, -1, -1
5814 XdripperB, FALSE, FALSE,
5815 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5818 Xfake_blank, TRUE, FALSE,
5819 EL_INVISIBLE_WALL, -1, -1
5822 Xfake_blankB, FALSE, FALSE,
5823 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5826 Xfake_grass, TRUE, FALSE,
5827 EL_EMC_FAKE_GRASS, -1, -1
5830 Xfake_grassB, FALSE, FALSE,
5831 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5834 Xfake_door_1, TRUE, FALSE,
5835 EL_EM_GATE_1_GRAY, -1, -1
5838 Xfake_door_2, TRUE, FALSE,
5839 EL_EM_GATE_2_GRAY, -1, -1
5842 Xfake_door_3, TRUE, FALSE,
5843 EL_EM_GATE_3_GRAY, -1, -1
5846 Xfake_door_4, TRUE, FALSE,
5847 EL_EM_GATE_4_GRAY, -1, -1
5850 Xfake_door_5, TRUE, FALSE,
5851 EL_EMC_GATE_5_GRAY, -1, -1
5854 Xfake_door_6, TRUE, FALSE,
5855 EL_EMC_GATE_6_GRAY, -1, -1
5858 Xfake_door_7, TRUE, FALSE,
5859 EL_EMC_GATE_7_GRAY, -1, -1
5862 Xfake_door_8, TRUE, FALSE,
5863 EL_EMC_GATE_8_GRAY, -1, -1
5866 Xfake_acid_1, TRUE, FALSE,
5867 EL_EMC_FAKE_ACID, -1, -1
5870 Xfake_acid_2, FALSE, FALSE,
5871 EL_EMC_FAKE_ACID, -1, -1
5874 Xfake_acid_3, FALSE, FALSE,
5875 EL_EMC_FAKE_ACID, -1, -1
5878 Xfake_acid_4, FALSE, FALSE,
5879 EL_EMC_FAKE_ACID, -1, -1
5882 Xfake_acid_5, FALSE, FALSE,
5883 EL_EMC_FAKE_ACID, -1, -1
5886 Xfake_acid_6, FALSE, FALSE,
5887 EL_EMC_FAKE_ACID, -1, -1
5890 Xfake_acid_7, FALSE, FALSE,
5891 EL_EMC_FAKE_ACID, -1, -1
5894 Xfake_acid_8, FALSE, FALSE,
5895 EL_EMC_FAKE_ACID, -1, -1
5898 Xsteel_1, TRUE, FALSE,
5899 EL_STEELWALL, -1, -1
5902 Xsteel_2, TRUE, FALSE,
5903 EL_EMC_STEELWALL_2, -1, -1
5906 Xsteel_3, TRUE, FALSE,
5907 EL_EMC_STEELWALL_3, -1, -1
5910 Xsteel_4, TRUE, FALSE,
5911 EL_EMC_STEELWALL_4, -1, -1
5914 Xwall_1, TRUE, FALSE,
5918 Xwall_2, TRUE, FALSE,
5919 EL_EMC_WALL_14, -1, -1
5922 Xwall_3, TRUE, FALSE,
5923 EL_EMC_WALL_15, -1, -1
5926 Xwall_4, TRUE, FALSE,
5927 EL_EMC_WALL_16, -1, -1
5930 Xround_wall_1, TRUE, FALSE,
5931 EL_WALL_SLIPPERY, -1, -1
5934 Xround_wall_2, TRUE, FALSE,
5935 EL_EMC_WALL_SLIPPERY_2, -1, -1
5938 Xround_wall_3, TRUE, FALSE,
5939 EL_EMC_WALL_SLIPPERY_3, -1, -1
5942 Xround_wall_4, TRUE, FALSE,
5943 EL_EMC_WALL_SLIPPERY_4, -1, -1
5946 Xdecor_1, TRUE, FALSE,
5947 EL_EMC_WALL_8, -1, -1
5950 Xdecor_2, TRUE, FALSE,
5951 EL_EMC_WALL_6, -1, -1
5954 Xdecor_3, TRUE, FALSE,
5955 EL_EMC_WALL_4, -1, -1
5958 Xdecor_4, TRUE, FALSE,
5959 EL_EMC_WALL_7, -1, -1
5962 Xdecor_5, TRUE, FALSE,
5963 EL_EMC_WALL_5, -1, -1
5966 Xdecor_6, TRUE, FALSE,
5967 EL_EMC_WALL_9, -1, -1
5970 Xdecor_7, TRUE, FALSE,
5971 EL_EMC_WALL_10, -1, -1
5974 Xdecor_8, TRUE, FALSE,
5975 EL_EMC_WALL_1, -1, -1
5978 Xdecor_9, TRUE, FALSE,
5979 EL_EMC_WALL_2, -1, -1
5982 Xdecor_10, TRUE, FALSE,
5983 EL_EMC_WALL_3, -1, -1
5986 Xdecor_11, TRUE, FALSE,
5987 EL_EMC_WALL_11, -1, -1
5990 Xdecor_12, TRUE, FALSE,
5991 EL_EMC_WALL_12, -1, -1
5994 Xalpha_0, TRUE, FALSE,
5995 EL_CHAR('0'), -1, -1
5998 Xalpha_1, TRUE, FALSE,
5999 EL_CHAR('1'), -1, -1
6002 Xalpha_2, TRUE, FALSE,
6003 EL_CHAR('2'), -1, -1
6006 Xalpha_3, TRUE, FALSE,
6007 EL_CHAR('3'), -1, -1
6010 Xalpha_4, TRUE, FALSE,
6011 EL_CHAR('4'), -1, -1
6014 Xalpha_5, TRUE, FALSE,
6015 EL_CHAR('5'), -1, -1
6018 Xalpha_6, TRUE, FALSE,
6019 EL_CHAR('6'), -1, -1
6022 Xalpha_7, TRUE, FALSE,
6023 EL_CHAR('7'), -1, -1
6026 Xalpha_8, TRUE, FALSE,
6027 EL_CHAR('8'), -1, -1
6030 Xalpha_9, TRUE, FALSE,
6031 EL_CHAR('9'), -1, -1
6034 Xalpha_excla, TRUE, FALSE,
6035 EL_CHAR('!'), -1, -1
6038 Xalpha_quote, TRUE, FALSE,
6039 EL_CHAR('"'), -1, -1
6042 Xalpha_comma, TRUE, FALSE,
6043 EL_CHAR(','), -1, -1
6046 Xalpha_minus, TRUE, FALSE,
6047 EL_CHAR('-'), -1, -1
6050 Xalpha_perio, TRUE, FALSE,
6051 EL_CHAR('.'), -1, -1
6054 Xalpha_colon, TRUE, FALSE,
6055 EL_CHAR(':'), -1, -1
6058 Xalpha_quest, TRUE, FALSE,
6059 EL_CHAR('?'), -1, -1
6062 Xalpha_a, TRUE, FALSE,
6063 EL_CHAR('A'), -1, -1
6066 Xalpha_b, TRUE, FALSE,
6067 EL_CHAR('B'), -1, -1
6070 Xalpha_c, TRUE, FALSE,
6071 EL_CHAR('C'), -1, -1
6074 Xalpha_d, TRUE, FALSE,
6075 EL_CHAR('D'), -1, -1
6078 Xalpha_e, TRUE, FALSE,
6079 EL_CHAR('E'), -1, -1
6082 Xalpha_f, TRUE, FALSE,
6083 EL_CHAR('F'), -1, -1
6086 Xalpha_g, TRUE, FALSE,
6087 EL_CHAR('G'), -1, -1
6090 Xalpha_h, TRUE, FALSE,
6091 EL_CHAR('H'), -1, -1
6094 Xalpha_i, TRUE, FALSE,
6095 EL_CHAR('I'), -1, -1
6098 Xalpha_j, TRUE, FALSE,
6099 EL_CHAR('J'), -1, -1
6102 Xalpha_k, TRUE, FALSE,
6103 EL_CHAR('K'), -1, -1
6106 Xalpha_l, TRUE, FALSE,
6107 EL_CHAR('L'), -1, -1
6110 Xalpha_m, TRUE, FALSE,
6111 EL_CHAR('M'), -1, -1
6114 Xalpha_n, TRUE, FALSE,
6115 EL_CHAR('N'), -1, -1
6118 Xalpha_o, TRUE, FALSE,
6119 EL_CHAR('O'), -1, -1
6122 Xalpha_p, TRUE, FALSE,
6123 EL_CHAR('P'), -1, -1
6126 Xalpha_q, TRUE, FALSE,
6127 EL_CHAR('Q'), -1, -1
6130 Xalpha_r, TRUE, FALSE,
6131 EL_CHAR('R'), -1, -1
6134 Xalpha_s, TRUE, FALSE,
6135 EL_CHAR('S'), -1, -1
6138 Xalpha_t, TRUE, FALSE,
6139 EL_CHAR('T'), -1, -1
6142 Xalpha_u, TRUE, FALSE,
6143 EL_CHAR('U'), -1, -1
6146 Xalpha_v, TRUE, FALSE,
6147 EL_CHAR('V'), -1, -1
6150 Xalpha_w, TRUE, FALSE,
6151 EL_CHAR('W'), -1, -1
6154 Xalpha_x, TRUE, FALSE,
6155 EL_CHAR('X'), -1, -1
6158 Xalpha_y, TRUE, FALSE,
6159 EL_CHAR('Y'), -1, -1
6162 Xalpha_z, TRUE, FALSE,
6163 EL_CHAR('Z'), -1, -1
6166 Xalpha_arrow_e, TRUE, FALSE,
6167 EL_CHAR('>'), -1, -1
6170 Xalpha_arrow_w, TRUE, FALSE,
6171 EL_CHAR('<'), -1, -1
6174 Xalpha_copyr, TRUE, FALSE,
6175 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6179 Xboom_bug, FALSE, FALSE,
6180 EL_BUG, ACTION_EXPLODING, -1
6183 Xboom_bomb, FALSE, FALSE,
6184 EL_BOMB, ACTION_EXPLODING, -1
6187 Xboom_android, FALSE, FALSE,
6188 EL_EMC_ANDROID, ACTION_OTHER, -1
6191 Xboom_1, FALSE, FALSE,
6192 EL_DEFAULT, ACTION_EXPLODING, -1
6195 Xboom_2, FALSE, FALSE,
6196 EL_DEFAULT, ACTION_EXPLODING, -1
6199 Znormal, FALSE, FALSE,
6203 Zdynamite, FALSE, FALSE,
6207 Zplayer, FALSE, FALSE,
6211 ZBORDER, FALSE, FALSE,
6221 static struct Mapping_EM_to_RND_player
6230 em_player_mapping_list[] =
6234 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6238 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6242 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6246 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6250 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6254 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6258 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6262 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6266 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6270 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6274 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6278 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6282 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6286 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6290 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6294 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6298 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6302 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6306 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6310 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6314 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6318 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6322 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6326 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6330 EL_PLAYER_1, ACTION_DEFAULT, -1,
6334 EL_PLAYER_2, ACTION_DEFAULT, -1,
6338 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6342 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6346 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6350 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6354 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6358 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6362 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6366 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6370 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6374 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6378 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6382 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6386 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6390 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6394 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6398 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6402 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6406 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6410 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6414 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6418 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6422 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6426 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6430 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6434 EL_PLAYER_3, ACTION_DEFAULT, -1,
6438 EL_PLAYER_4, ACTION_DEFAULT, -1,
6447 int map_element_RND_to_EM(int element_rnd)
6449 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6450 static boolean mapping_initialized = FALSE;
6452 if (!mapping_initialized)
6456 /* return "Xalpha_quest" for all undefined elements in mapping array */
6457 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6458 mapping_RND_to_EM[i] = Xalpha_quest;
6460 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6461 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6462 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6463 em_object_mapping_list[i].element_em;
6465 mapping_initialized = TRUE;
6468 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6469 return mapping_RND_to_EM[element_rnd];
6471 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6476 int map_element_EM_to_RND(int element_em)
6478 static unsigned short mapping_EM_to_RND[TILE_MAX];
6479 static boolean mapping_initialized = FALSE;
6481 if (!mapping_initialized)
6485 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6486 for (i = 0; i < TILE_MAX; i++)
6487 mapping_EM_to_RND[i] = EL_UNKNOWN;
6489 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6490 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6491 em_object_mapping_list[i].element_rnd;
6493 mapping_initialized = TRUE;
6496 if (element_em >= 0 && element_em < TILE_MAX)
6497 return mapping_EM_to_RND[element_em];
6499 Error(ERR_WARN, "invalid EM level element %d", element_em);
6504 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6506 struct LevelInfo_EM *level_em = level->native_em_level;
6507 struct LEVEL *lev = level_em->lev;
6510 for (i = 0; i < TILE_MAX; i++)
6511 lev->android_array[i] = Xblank;
6513 for (i = 0; i < level->num_android_clone_elements; i++)
6515 int element_rnd = level->android_clone_element[i];
6516 int element_em = map_element_RND_to_EM(element_rnd);
6518 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6519 if (em_object_mapping_list[j].element_rnd == element_rnd)
6520 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6524 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6526 struct LevelInfo_EM *level_em = level->native_em_level;
6527 struct LEVEL *lev = level_em->lev;
6530 level->num_android_clone_elements = 0;
6532 for (i = 0; i < TILE_MAX; i++)
6534 int element_em = lev->android_array[i];
6536 boolean element_found = FALSE;
6538 if (element_em == Xblank)
6541 element_rnd = map_element_EM_to_RND(element_em);
6543 for (j = 0; j < level->num_android_clone_elements; j++)
6544 if (level->android_clone_element[j] == element_rnd)
6545 element_found = TRUE;
6549 level->android_clone_element[level->num_android_clone_elements++] =
6552 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6557 if (level->num_android_clone_elements == 0)
6559 level->num_android_clone_elements = 1;
6560 level->android_clone_element[0] = EL_EMPTY;
6564 int map_direction_RND_to_EM(int direction)
6566 return (direction == MV_UP ? 0 :
6567 direction == MV_RIGHT ? 1 :
6568 direction == MV_DOWN ? 2 :
6569 direction == MV_LEFT ? 3 :
6573 int map_direction_EM_to_RND(int direction)
6575 return (direction == 0 ? MV_UP :
6576 direction == 1 ? MV_RIGHT :
6577 direction == 2 ? MV_DOWN :
6578 direction == 3 ? MV_LEFT :
6582 int map_element_RND_to_SP(int element_rnd)
6584 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6586 if (element_rnd >= EL_SP_START &&
6587 element_rnd <= EL_SP_END)
6588 element_sp = element_rnd - EL_SP_START;
6589 else if (element_rnd == EL_EMPTY_SPACE)
6591 else if (element_rnd == EL_INVISIBLE_WALL)
6597 int map_element_SP_to_RND(int element_sp)
6599 int element_rnd = EL_UNKNOWN;
6601 if (element_sp >= 0x00 &&
6603 element_rnd = EL_SP_START + element_sp;
6604 else if (element_sp == 0x28)
6605 element_rnd = EL_INVISIBLE_WALL;
6610 int map_action_SP_to_RND(int action_sp)
6614 case actActive: return ACTION_ACTIVE;
6615 case actImpact: return ACTION_IMPACT;
6616 case actExploding: return ACTION_EXPLODING;
6617 case actDigging: return ACTION_DIGGING;
6618 case actSnapping: return ACTION_SNAPPING;
6619 case actCollecting: return ACTION_COLLECTING;
6620 case actPassing: return ACTION_PASSING;
6621 case actPushing: return ACTION_PUSHING;
6622 case actDropping: return ACTION_DROPPING;
6624 default: return ACTION_DEFAULT;
6628 int get_next_element(int element)
6632 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6633 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6634 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6635 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6636 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6637 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6638 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6639 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6640 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6641 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6642 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6644 default: return element;
6648 int el_act_dir2img(int element, int action, int direction)
6650 element = GFX_ELEMENT(element);
6651 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6653 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6654 return element_info[element].direction_graphic[action][direction];
6657 static int el_act_dir2crm(int element, int action, int direction)
6659 element = GFX_ELEMENT(element);
6660 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6662 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6663 return element_info[element].direction_crumbled[action][direction];
6666 int el_act2img(int element, int action)
6668 element = GFX_ELEMENT(element);
6670 return element_info[element].graphic[action];
6673 int el_act2crm(int element, int action)
6675 element = GFX_ELEMENT(element);
6677 return element_info[element].crumbled[action];
6680 int el_dir2img(int element, int direction)
6682 element = GFX_ELEMENT(element);
6684 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6687 int el2baseimg(int element)
6689 return element_info[element].graphic[ACTION_DEFAULT];
6692 int el2img(int element)
6694 element = GFX_ELEMENT(element);
6696 return element_info[element].graphic[ACTION_DEFAULT];
6699 int el2edimg(int element)
6701 element = GFX_ELEMENT(element);
6703 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6706 int el2preimg(int element)
6708 element = GFX_ELEMENT(element);
6710 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6713 int el2panelimg(int element)
6715 element = GFX_ELEMENT(element);
6717 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6720 int font2baseimg(int font_nr)
6722 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6725 int getBeltNrFromBeltElement(int element)
6727 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6728 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6729 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6732 int getBeltNrFromBeltActiveElement(int element)
6734 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6735 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6736 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6739 int getBeltNrFromBeltSwitchElement(int element)
6741 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6742 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6743 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6746 int getBeltDirNrFromBeltElement(int element)
6748 static int belt_base_element[4] =
6750 EL_CONVEYOR_BELT_1_LEFT,
6751 EL_CONVEYOR_BELT_2_LEFT,
6752 EL_CONVEYOR_BELT_3_LEFT,
6753 EL_CONVEYOR_BELT_4_LEFT
6756 int belt_nr = getBeltNrFromBeltElement(element);
6757 int belt_dir_nr = element - belt_base_element[belt_nr];
6759 return (belt_dir_nr % 3);
6762 int getBeltDirNrFromBeltSwitchElement(int element)
6764 static int belt_base_element[4] =
6766 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6767 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6768 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6769 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6772 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6773 int belt_dir_nr = element - belt_base_element[belt_nr];
6775 return (belt_dir_nr % 3);
6778 int getBeltDirFromBeltElement(int element)
6780 static int belt_move_dir[3] =
6787 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6789 return belt_move_dir[belt_dir_nr];
6792 int getBeltDirFromBeltSwitchElement(int element)
6794 static int belt_move_dir[3] =
6801 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6803 return belt_move_dir[belt_dir_nr];
6806 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6808 static int belt_base_element[4] =
6810 EL_CONVEYOR_BELT_1_LEFT,
6811 EL_CONVEYOR_BELT_2_LEFT,
6812 EL_CONVEYOR_BELT_3_LEFT,
6813 EL_CONVEYOR_BELT_4_LEFT
6816 return belt_base_element[belt_nr] + belt_dir_nr;
6819 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6821 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6823 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6826 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6828 static int belt_base_element[4] =
6830 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6831 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6832 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6833 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6836 return belt_base_element[belt_nr] + belt_dir_nr;
6839 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6841 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6843 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6846 boolean getTeamMode_EM()
6848 return game.team_mode;
6851 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6853 int game_frame_delay_value;
6855 game_frame_delay_value =
6856 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6857 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6860 if (tape.playing && tape.warp_forward && !tape.pausing)
6861 game_frame_delay_value = 0;
6863 return game_frame_delay_value;
6866 unsigned int InitRND(int seed)
6868 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6869 return InitEngineRandom_EM(seed);
6870 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6871 return InitEngineRandom_SP(seed);
6873 return InitEngineRandom_RND(seed);
6876 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6877 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6879 inline static int get_effective_element_EM(int tile, int frame_em)
6881 int element = object_mapping[tile].element_rnd;
6882 int action = object_mapping[tile].action;
6883 boolean is_backside = object_mapping[tile].is_backside;
6884 boolean action_removing = (action == ACTION_DIGGING ||
6885 action == ACTION_SNAPPING ||
6886 action == ACTION_COLLECTING);
6892 case Yacid_splash_eB:
6893 case Yacid_splash_wB:
6894 return (frame_em > 5 ? EL_EMPTY : element);
6900 else /* frame_em == 7 */
6904 case Yacid_splash_eB:
6905 case Yacid_splash_wB:
6908 case Yemerald_stone:
6911 case Ydiamond_stone:
6915 case Xdrip_stretchB:
6934 case Xsand_stonein_1:
6935 case Xsand_stonein_2:
6936 case Xsand_stonein_3:
6937 case Xsand_stonein_4:
6941 return (is_backside || action_removing ? EL_EMPTY : element);
6946 inline static boolean check_linear_animation_EM(int tile)
6950 case Xsand_stonesand_1:
6951 case Xsand_stonesand_quickout_1:
6952 case Xsand_sandstone_1:
6953 case Xsand_stonein_1:
6954 case Xsand_stoneout_1:
6973 case Yacid_splash_eB:
6974 case Yacid_splash_wB:
6975 case Yemerald_stone:
6982 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6983 boolean has_crumbled_graphics,
6984 int crumbled, int sync_frame)
6986 /* if element can be crumbled, but certain action graphics are just empty
6987 space (like instantly snapping sand to empty space in 1 frame), do not
6988 treat these empty space graphics as crumbled graphics in EMC engine */
6989 if (crumbled == IMG_EMPTY_SPACE)
6990 has_crumbled_graphics = FALSE;
6992 if (has_crumbled_graphics)
6994 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6995 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6996 g_crumbled->anim_delay,
6997 g_crumbled->anim_mode,
6998 g_crumbled->anim_start_frame,
7001 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7002 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7004 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7006 g_em->has_crumbled_graphics = TRUE;
7010 g_em->crumbled_bitmap = NULL;
7011 g_em->crumbled_src_x = 0;
7012 g_em->crumbled_src_y = 0;
7013 g_em->crumbled_border_size = 0;
7015 g_em->has_crumbled_graphics = FALSE;
7019 void ResetGfxAnimation_EM(int x, int y, int tile)
7024 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7025 int tile, int frame_em, int x, int y)
7027 int action = object_mapping[tile].action;
7028 int direction = object_mapping[tile].direction;
7029 int effective_element = get_effective_element_EM(tile, frame_em);
7030 int graphic = (direction == MV_NONE ?
7031 el_act2img(effective_element, action) :
7032 el_act_dir2img(effective_element, action, direction));
7033 struct GraphicInfo *g = &graphic_info[graphic];
7035 boolean action_removing = (action == ACTION_DIGGING ||
7036 action == ACTION_SNAPPING ||
7037 action == ACTION_COLLECTING);
7038 boolean action_moving = (action == ACTION_FALLING ||
7039 action == ACTION_MOVING ||
7040 action == ACTION_PUSHING ||
7041 action == ACTION_EATING ||
7042 action == ACTION_FILLING ||
7043 action == ACTION_EMPTYING);
7044 boolean action_falling = (action == ACTION_FALLING ||
7045 action == ACTION_FILLING ||
7046 action == ACTION_EMPTYING);
7048 /* special case: graphic uses "2nd movement tile" and has defined
7049 7 frames for movement animation (or less) => use default graphic
7050 for last (8th) frame which ends the movement animation */
7051 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7053 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7054 graphic = (direction == MV_NONE ?
7055 el_act2img(effective_element, action) :
7056 el_act_dir2img(effective_element, action, direction));
7058 g = &graphic_info[graphic];
7061 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7065 else if (action_moving)
7067 boolean is_backside = object_mapping[tile].is_backside;
7071 int direction = object_mapping[tile].direction;
7072 int move_dir = (action_falling ? MV_DOWN : direction);
7077 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7078 if (g->double_movement && frame_em == 0)
7082 if (move_dir == MV_LEFT)
7083 GfxFrame[x - 1][y] = GfxFrame[x][y];
7084 else if (move_dir == MV_RIGHT)
7085 GfxFrame[x + 1][y] = GfxFrame[x][y];
7086 else if (move_dir == MV_UP)
7087 GfxFrame[x][y - 1] = GfxFrame[x][y];
7088 else if (move_dir == MV_DOWN)
7089 GfxFrame[x][y + 1] = GfxFrame[x][y];
7096 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7097 if (tile == Xsand_stonesand_quickout_1 ||
7098 tile == Xsand_stonesand_quickout_2)
7102 if (graphic_info[graphic].anim_global_sync)
7103 sync_frame = FrameCounter;
7104 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7105 sync_frame = GfxFrame[x][y];
7107 sync_frame = 0; /* playfield border (pseudo steel) */
7109 SetRandomAnimationValue(x, y);
7111 int frame = getAnimationFrame(g->anim_frames,
7114 g->anim_start_frame,
7117 g_em->unique_identifier =
7118 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7121 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7122 int tile, int frame_em, int x, int y)
7124 int action = object_mapping[tile].action;
7125 int direction = object_mapping[tile].direction;
7126 boolean is_backside = object_mapping[tile].is_backside;
7127 int effective_element = get_effective_element_EM(tile, frame_em);
7128 int effective_action = action;
7129 int graphic = (direction == MV_NONE ?
7130 el_act2img(effective_element, effective_action) :
7131 el_act_dir2img(effective_element, effective_action,
7133 int crumbled = (direction == MV_NONE ?
7134 el_act2crm(effective_element, effective_action) :
7135 el_act_dir2crm(effective_element, effective_action,
7137 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7138 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7139 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7140 struct GraphicInfo *g = &graphic_info[graphic];
7143 /* special case: graphic uses "2nd movement tile" and has defined
7144 7 frames for movement animation (or less) => use default graphic
7145 for last (8th) frame which ends the movement animation */
7146 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7148 effective_action = ACTION_DEFAULT;
7149 graphic = (direction == MV_NONE ?
7150 el_act2img(effective_element, effective_action) :
7151 el_act_dir2img(effective_element, effective_action,
7153 crumbled = (direction == MV_NONE ?
7154 el_act2crm(effective_element, effective_action) :
7155 el_act_dir2crm(effective_element, effective_action,
7158 g = &graphic_info[graphic];
7161 if (graphic_info[graphic].anim_global_sync)
7162 sync_frame = FrameCounter;
7163 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7164 sync_frame = GfxFrame[x][y];
7166 sync_frame = 0; /* playfield border (pseudo steel) */
7168 SetRandomAnimationValue(x, y);
7170 int frame = getAnimationFrame(g->anim_frames,
7173 g->anim_start_frame,
7176 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7177 g->double_movement && is_backside);
7179 /* (updating the "crumbled" graphic definitions is probably not really needed,
7180 as animations for crumbled graphics can't be longer than one EMC cycle) */
7181 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7185 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7186 int player_nr, int anim, int frame_em)
7188 int element = player_mapping[player_nr][anim].element_rnd;
7189 int action = player_mapping[player_nr][anim].action;
7190 int direction = player_mapping[player_nr][anim].direction;
7191 int graphic = (direction == MV_NONE ?
7192 el_act2img(element, action) :
7193 el_act_dir2img(element, action, direction));
7194 struct GraphicInfo *g = &graphic_info[graphic];
7197 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7199 stored_player[player_nr].StepFrame = frame_em;
7201 sync_frame = stored_player[player_nr].Frame;
7203 int frame = getAnimationFrame(g->anim_frames,
7206 g->anim_start_frame,
7209 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7210 &g_em->src_x, &g_em->src_y, FALSE);
7213 void InitGraphicInfo_EM(void)
7218 int num_em_gfx_errors = 0;
7220 if (graphic_info_em_object[0][0].bitmap == NULL)
7222 /* EM graphics not yet initialized in em_open_all() */
7227 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7230 /* always start with reliable default values */
7231 for (i = 0; i < TILE_MAX; i++)
7233 object_mapping[i].element_rnd = EL_UNKNOWN;
7234 object_mapping[i].is_backside = FALSE;
7235 object_mapping[i].action = ACTION_DEFAULT;
7236 object_mapping[i].direction = MV_NONE;
7239 /* always start with reliable default values */
7240 for (p = 0; p < MAX_PLAYERS; p++)
7242 for (i = 0; i < SPR_MAX; i++)
7244 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7245 player_mapping[p][i].action = ACTION_DEFAULT;
7246 player_mapping[p][i].direction = MV_NONE;
7250 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7252 int e = em_object_mapping_list[i].element_em;
7254 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7255 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7257 if (em_object_mapping_list[i].action != -1)
7258 object_mapping[e].action = em_object_mapping_list[i].action;
7260 if (em_object_mapping_list[i].direction != -1)
7261 object_mapping[e].direction =
7262 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7265 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7267 int a = em_player_mapping_list[i].action_em;
7268 int p = em_player_mapping_list[i].player_nr;
7270 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7272 if (em_player_mapping_list[i].action != -1)
7273 player_mapping[p][a].action = em_player_mapping_list[i].action;
7275 if (em_player_mapping_list[i].direction != -1)
7276 player_mapping[p][a].direction =
7277 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7280 for (i = 0; i < TILE_MAX; i++)
7282 int element = object_mapping[i].element_rnd;
7283 int action = object_mapping[i].action;
7284 int direction = object_mapping[i].direction;
7285 boolean is_backside = object_mapping[i].is_backside;
7286 boolean action_exploding = ((action == ACTION_EXPLODING ||
7287 action == ACTION_SMASHED_BY_ROCK ||
7288 action == ACTION_SMASHED_BY_SPRING) &&
7289 element != EL_DIAMOND);
7290 boolean action_active = (action == ACTION_ACTIVE);
7291 boolean action_other = (action == ACTION_OTHER);
7293 for (j = 0; j < 8; j++)
7295 int effective_element = get_effective_element_EM(i, j);
7296 int effective_action = (j < 7 ? action :
7297 i == Xdrip_stretch ? action :
7298 i == Xdrip_stretchB ? action :
7299 i == Ydrip_s1 ? action :
7300 i == Ydrip_s1B ? action :
7301 i == Xball_1B ? action :
7302 i == Xball_2 ? action :
7303 i == Xball_2B ? action :
7304 i == Yball_eat ? action :
7305 i == Ykey_1_eat ? action :
7306 i == Ykey_2_eat ? action :
7307 i == Ykey_3_eat ? action :
7308 i == Ykey_4_eat ? action :
7309 i == Ykey_5_eat ? action :
7310 i == Ykey_6_eat ? action :
7311 i == Ykey_7_eat ? action :
7312 i == Ykey_8_eat ? action :
7313 i == Ylenses_eat ? action :
7314 i == Ymagnify_eat ? action :
7315 i == Ygrass_eat ? action :
7316 i == Ydirt_eat ? action :
7317 i == Xsand_stonein_1 ? action :
7318 i == Xsand_stonein_2 ? action :
7319 i == Xsand_stonein_3 ? action :
7320 i == Xsand_stonein_4 ? action :
7321 i == Xsand_stoneout_1 ? action :
7322 i == Xsand_stoneout_2 ? action :
7323 i == Xboom_android ? ACTION_EXPLODING :
7324 action_exploding ? ACTION_EXPLODING :
7325 action_active ? action :
7326 action_other ? action :
7328 int graphic = (el_act_dir2img(effective_element, effective_action,
7330 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7332 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7333 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7334 boolean has_action_graphics = (graphic != base_graphic);
7335 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7336 struct GraphicInfo *g = &graphic_info[graphic];
7337 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7340 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7341 boolean special_animation = (action != ACTION_DEFAULT &&
7342 g->anim_frames == 3 &&
7343 g->anim_delay == 2 &&
7344 g->anim_mode & ANIM_LINEAR);
7345 int sync_frame = (i == Xdrip_stretch ? 7 :
7346 i == Xdrip_stretchB ? 7 :
7347 i == Ydrip_s2 ? j + 8 :
7348 i == Ydrip_s2B ? j + 8 :
7357 i == Xfake_acid_1 ? 0 :
7358 i == Xfake_acid_2 ? 10 :
7359 i == Xfake_acid_3 ? 20 :
7360 i == Xfake_acid_4 ? 30 :
7361 i == Xfake_acid_5 ? 40 :
7362 i == Xfake_acid_6 ? 50 :
7363 i == Xfake_acid_7 ? 60 :
7364 i == Xfake_acid_8 ? 70 :
7366 i == Xball_2B ? j + 8 :
7367 i == Yball_eat ? j + 1 :
7368 i == Ykey_1_eat ? j + 1 :
7369 i == Ykey_2_eat ? j + 1 :
7370 i == Ykey_3_eat ? j + 1 :
7371 i == Ykey_4_eat ? j + 1 :
7372 i == Ykey_5_eat ? j + 1 :
7373 i == Ykey_6_eat ? j + 1 :
7374 i == Ykey_7_eat ? j + 1 :
7375 i == Ykey_8_eat ? j + 1 :
7376 i == Ylenses_eat ? j + 1 :
7377 i == Ymagnify_eat ? j + 1 :
7378 i == Ygrass_eat ? j + 1 :
7379 i == Ydirt_eat ? j + 1 :
7380 i == Xamoeba_1 ? 0 :
7381 i == Xamoeba_2 ? 1 :
7382 i == Xamoeba_3 ? 2 :
7383 i == Xamoeba_4 ? 3 :
7384 i == Xamoeba_5 ? 0 :
7385 i == Xamoeba_6 ? 1 :
7386 i == Xamoeba_7 ? 2 :
7387 i == Xamoeba_8 ? 3 :
7388 i == Xexit_2 ? j + 8 :
7389 i == Xexit_3 ? j + 16 :
7390 i == Xdynamite_1 ? 0 :
7391 i == Xdynamite_2 ? 8 :
7392 i == Xdynamite_3 ? 16 :
7393 i == Xdynamite_4 ? 24 :
7394 i == Xsand_stonein_1 ? j + 1 :
7395 i == Xsand_stonein_2 ? j + 9 :
7396 i == Xsand_stonein_3 ? j + 17 :
7397 i == Xsand_stonein_4 ? j + 25 :
7398 i == Xsand_stoneout_1 && j == 0 ? 0 :
7399 i == Xsand_stoneout_1 && j == 1 ? 0 :
7400 i == Xsand_stoneout_1 && j == 2 ? 1 :
7401 i == Xsand_stoneout_1 && j == 3 ? 2 :
7402 i == Xsand_stoneout_1 && j == 4 ? 2 :
7403 i == Xsand_stoneout_1 && j == 5 ? 3 :
7404 i == Xsand_stoneout_1 && j == 6 ? 4 :
7405 i == Xsand_stoneout_1 && j == 7 ? 4 :
7406 i == Xsand_stoneout_2 && j == 0 ? 5 :
7407 i == Xsand_stoneout_2 && j == 1 ? 6 :
7408 i == Xsand_stoneout_2 && j == 2 ? 7 :
7409 i == Xsand_stoneout_2 && j == 3 ? 8 :
7410 i == Xsand_stoneout_2 && j == 4 ? 9 :
7411 i == Xsand_stoneout_2 && j == 5 ? 11 :
7412 i == Xsand_stoneout_2 && j == 6 ? 13 :
7413 i == Xsand_stoneout_2 && j == 7 ? 15 :
7414 i == Xboom_bug && j == 1 ? 2 :
7415 i == Xboom_bug && j == 2 ? 2 :
7416 i == Xboom_bug && j == 3 ? 4 :
7417 i == Xboom_bug && j == 4 ? 4 :
7418 i == Xboom_bug && j == 5 ? 2 :
7419 i == Xboom_bug && j == 6 ? 2 :
7420 i == Xboom_bug && j == 7 ? 0 :
7421 i == Xboom_bomb && j == 1 ? 2 :
7422 i == Xboom_bomb && j == 2 ? 2 :
7423 i == Xboom_bomb && j == 3 ? 4 :
7424 i == Xboom_bomb && j == 4 ? 4 :
7425 i == Xboom_bomb && j == 5 ? 2 :
7426 i == Xboom_bomb && j == 6 ? 2 :
7427 i == Xboom_bomb && j == 7 ? 0 :
7428 i == Xboom_android && j == 7 ? 6 :
7429 i == Xboom_1 && j == 1 ? 2 :
7430 i == Xboom_1 && j == 2 ? 2 :
7431 i == Xboom_1 && j == 3 ? 4 :
7432 i == Xboom_1 && j == 4 ? 4 :
7433 i == Xboom_1 && j == 5 ? 6 :
7434 i == Xboom_1 && j == 6 ? 6 :
7435 i == Xboom_1 && j == 7 ? 8 :
7436 i == Xboom_2 && j == 0 ? 8 :
7437 i == Xboom_2 && j == 1 ? 8 :
7438 i == Xboom_2 && j == 2 ? 10 :
7439 i == Xboom_2 && j == 3 ? 10 :
7440 i == Xboom_2 && j == 4 ? 10 :
7441 i == Xboom_2 && j == 5 ? 12 :
7442 i == Xboom_2 && j == 6 ? 12 :
7443 i == Xboom_2 && j == 7 ? 12 :
7444 special_animation && j == 4 ? 3 :
7445 effective_action != action ? 0 :
7449 Bitmap *debug_bitmap = g_em->bitmap;
7450 int debug_src_x = g_em->src_x;
7451 int debug_src_y = g_em->src_y;
7454 int frame = getAnimationFrame(g->anim_frames,
7457 g->anim_start_frame,
7460 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7461 g->double_movement && is_backside);
7463 g_em->bitmap = src_bitmap;
7464 g_em->src_x = src_x;
7465 g_em->src_y = src_y;
7466 g_em->src_offset_x = 0;
7467 g_em->src_offset_y = 0;
7468 g_em->dst_offset_x = 0;
7469 g_em->dst_offset_y = 0;
7470 g_em->width = TILEX;
7471 g_em->height = TILEY;
7473 g_em->preserve_background = FALSE;
7475 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7478 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7479 effective_action == ACTION_MOVING ||
7480 effective_action == ACTION_PUSHING ||
7481 effective_action == ACTION_EATING)) ||
7482 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7483 effective_action == ACTION_EMPTYING)))
7486 (effective_action == ACTION_FALLING ||
7487 effective_action == ACTION_FILLING ||
7488 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7489 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7490 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7491 int num_steps = (i == Ydrip_s1 ? 16 :
7492 i == Ydrip_s1B ? 16 :
7493 i == Ydrip_s2 ? 16 :
7494 i == Ydrip_s2B ? 16 :
7495 i == Xsand_stonein_1 ? 32 :
7496 i == Xsand_stonein_2 ? 32 :
7497 i == Xsand_stonein_3 ? 32 :
7498 i == Xsand_stonein_4 ? 32 :
7499 i == Xsand_stoneout_1 ? 16 :
7500 i == Xsand_stoneout_2 ? 16 : 8);
7501 int cx = ABS(dx) * (TILEX / num_steps);
7502 int cy = ABS(dy) * (TILEY / num_steps);
7503 int step_frame = (i == Ydrip_s2 ? j + 8 :
7504 i == Ydrip_s2B ? j + 8 :
7505 i == Xsand_stonein_2 ? j + 8 :
7506 i == Xsand_stonein_3 ? j + 16 :
7507 i == Xsand_stonein_4 ? j + 24 :
7508 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7509 int step = (is_backside ? step_frame : num_steps - step_frame);
7511 if (is_backside) /* tile where movement starts */
7513 if (dx < 0 || dy < 0)
7515 g_em->src_offset_x = cx * step;
7516 g_em->src_offset_y = cy * step;
7520 g_em->dst_offset_x = cx * step;
7521 g_em->dst_offset_y = cy * step;
7524 else /* tile where movement ends */
7526 if (dx < 0 || dy < 0)
7528 g_em->dst_offset_x = cx * step;
7529 g_em->dst_offset_y = cy * step;
7533 g_em->src_offset_x = cx * step;
7534 g_em->src_offset_y = cy * step;
7538 g_em->width = TILEX - cx * step;
7539 g_em->height = TILEY - cy * step;
7542 /* create unique graphic identifier to decide if tile must be redrawn */
7543 /* bit 31 - 16 (16 bit): EM style graphic
7544 bit 15 - 12 ( 4 bit): EM style frame
7545 bit 11 - 6 ( 6 bit): graphic width
7546 bit 5 - 0 ( 6 bit): graphic height */
7547 g_em->unique_identifier =
7548 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7552 /* skip check for EMC elements not contained in original EMC artwork */
7553 if (element == EL_EMC_FAKE_ACID)
7556 if (g_em->bitmap != debug_bitmap ||
7557 g_em->src_x != debug_src_x ||
7558 g_em->src_y != debug_src_y ||
7559 g_em->src_offset_x != 0 ||
7560 g_em->src_offset_y != 0 ||
7561 g_em->dst_offset_x != 0 ||
7562 g_em->dst_offset_y != 0 ||
7563 g_em->width != TILEX ||
7564 g_em->height != TILEY)
7566 static int last_i = -1;
7574 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7575 i, element, element_info[element].token_name,
7576 element_action_info[effective_action].suffix, direction);
7578 if (element != effective_element)
7579 printf(" [%d ('%s')]",
7581 element_info[effective_element].token_name);
7585 if (g_em->bitmap != debug_bitmap)
7586 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7587 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7589 if (g_em->src_x != debug_src_x ||
7590 g_em->src_y != debug_src_y)
7591 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7592 j, (is_backside ? 'B' : 'F'),
7593 g_em->src_x, g_em->src_y,
7594 g_em->src_x / 32, g_em->src_y / 32,
7595 debug_src_x, debug_src_y,
7596 debug_src_x / 32, debug_src_y / 32);
7598 if (g_em->src_offset_x != 0 ||
7599 g_em->src_offset_y != 0 ||
7600 g_em->dst_offset_x != 0 ||
7601 g_em->dst_offset_y != 0)
7602 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7604 g_em->src_offset_x, g_em->src_offset_y,
7605 g_em->dst_offset_x, g_em->dst_offset_y);
7607 if (g_em->width != TILEX ||
7608 g_em->height != TILEY)
7609 printf(" %d (%d): size %d,%d should be %d,%d\n",
7611 g_em->width, g_em->height, TILEX, TILEY);
7613 num_em_gfx_errors++;
7620 for (i = 0; i < TILE_MAX; i++)
7622 for (j = 0; j < 8; j++)
7624 int element = object_mapping[i].element_rnd;
7625 int action = object_mapping[i].action;
7626 int direction = object_mapping[i].direction;
7627 boolean is_backside = object_mapping[i].is_backside;
7628 int graphic_action = el_act_dir2img(element, action, direction);
7629 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7631 if ((action == ACTION_SMASHED_BY_ROCK ||
7632 action == ACTION_SMASHED_BY_SPRING ||
7633 action == ACTION_EATING) &&
7634 graphic_action == graphic_default)
7636 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7637 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7638 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7639 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7642 /* no separate animation for "smashed by rock" -- use rock instead */
7643 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7644 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7646 g_em->bitmap = g_xx->bitmap;
7647 g_em->src_x = g_xx->src_x;
7648 g_em->src_y = g_xx->src_y;
7649 g_em->src_offset_x = g_xx->src_offset_x;
7650 g_em->src_offset_y = g_xx->src_offset_y;
7651 g_em->dst_offset_x = g_xx->dst_offset_x;
7652 g_em->dst_offset_y = g_xx->dst_offset_y;
7653 g_em->width = g_xx->width;
7654 g_em->height = g_xx->height;
7655 g_em->unique_identifier = g_xx->unique_identifier;
7658 g_em->preserve_background = TRUE;
7663 for (p = 0; p < MAX_PLAYERS; p++)
7665 for (i = 0; i < SPR_MAX; i++)
7667 int element = player_mapping[p][i].element_rnd;
7668 int action = player_mapping[p][i].action;
7669 int direction = player_mapping[p][i].direction;
7671 for (j = 0; j < 8; j++)
7673 int effective_element = element;
7674 int effective_action = action;
7675 int graphic = (direction == MV_NONE ?
7676 el_act2img(effective_element, effective_action) :
7677 el_act_dir2img(effective_element, effective_action,
7679 struct GraphicInfo *g = &graphic_info[graphic];
7680 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7686 Bitmap *debug_bitmap = g_em->bitmap;
7687 int debug_src_x = g_em->src_x;
7688 int debug_src_y = g_em->src_y;
7691 int frame = getAnimationFrame(g->anim_frames,
7694 g->anim_start_frame,
7697 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7699 g_em->bitmap = src_bitmap;
7700 g_em->src_x = src_x;
7701 g_em->src_y = src_y;
7702 g_em->src_offset_x = 0;
7703 g_em->src_offset_y = 0;
7704 g_em->dst_offset_x = 0;
7705 g_em->dst_offset_y = 0;
7706 g_em->width = TILEX;
7707 g_em->height = TILEY;
7711 /* skip check for EMC elements not contained in original EMC artwork */
7712 if (element == EL_PLAYER_3 ||
7713 element == EL_PLAYER_4)
7716 if (g_em->bitmap != debug_bitmap ||
7717 g_em->src_x != debug_src_x ||
7718 g_em->src_y != debug_src_y)
7720 static int last_i = -1;
7728 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7729 p, i, element, element_info[element].token_name,
7730 element_action_info[effective_action].suffix, direction);
7732 if (element != effective_element)
7733 printf(" [%d ('%s')]",
7735 element_info[effective_element].token_name);
7739 if (g_em->bitmap != debug_bitmap)
7740 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7741 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7743 if (g_em->src_x != debug_src_x ||
7744 g_em->src_y != debug_src_y)
7745 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7747 g_em->src_x, g_em->src_y,
7748 g_em->src_x / 32, g_em->src_y / 32,
7749 debug_src_x, debug_src_y,
7750 debug_src_x / 32, debug_src_y / 32);
7752 num_em_gfx_errors++;
7762 printf("::: [%d errors found]\n", num_em_gfx_errors);
7768 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7769 boolean any_player_moving,
7770 boolean player_is_dropping)
7772 if (tape.single_step && tape.recording && !tape.pausing)
7773 if (frame == 0 && !player_is_dropping)
7774 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7777 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7778 boolean murphy_is_dropping)
7780 if (tape.single_step && tape.recording && !tape.pausing)
7781 if (murphy_is_waiting)
7782 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7785 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7786 int graphic, int sync_frame, int x, int y)
7788 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7790 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7793 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7795 return (IS_NEXT_FRAME(sync_frame, graphic));
7798 int getGraphicInfo_Delay(int graphic)
7800 return graphic_info[graphic].anim_delay;
7803 void PlayMenuSoundExt(int sound)
7805 if (sound == SND_UNDEFINED)
7808 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7809 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7812 if (IS_LOOP_SOUND(sound))
7813 PlaySoundLoop(sound);
7818 void PlayMenuSound()
7820 PlayMenuSoundExt(menu.sound[game_status]);
7823 void PlayMenuSoundStereo(int sound, int stereo_position)
7825 if (sound == SND_UNDEFINED)
7828 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7829 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7832 if (IS_LOOP_SOUND(sound))
7833 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7835 PlaySoundStereo(sound, stereo_position);
7838 void PlayMenuSoundIfLoopExt(int sound)
7840 if (sound == SND_UNDEFINED)
7843 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7844 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7847 if (IS_LOOP_SOUND(sound))
7848 PlaySoundLoop(sound);
7851 void PlayMenuSoundIfLoop()
7853 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7856 void PlayMenuMusicExt(int music)
7858 if (music == MUS_UNDEFINED)
7861 if (!setup.sound_music)
7867 void PlayMenuMusic()
7869 PlayMenuMusicExt(menu.music[game_status]);
7872 void PlaySoundActivating()
7875 PlaySound(SND_MENU_ITEM_ACTIVATING);
7879 void PlaySoundSelecting()
7882 PlaySound(SND_MENU_ITEM_SELECTING);
7886 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7888 boolean change_fullscreen = (setup.fullscreen !=
7889 video.fullscreen_enabled);
7890 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7891 !strEqual(setup.fullscreen_mode,
7892 video.fullscreen_mode_current));
7893 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7894 setup.window_scaling_percent !=
7895 video.window_scaling_percent);
7897 if (change_window_scaling_percent && video.fullscreen_enabled)
7900 if (!change_window_scaling_percent && !video.fullscreen_available)
7903 #if defined(TARGET_SDL2)
7904 if (change_window_scaling_percent)
7906 SDLSetWindowScaling(setup.window_scaling_percent);
7910 else if (change_fullscreen)
7912 SDLSetWindowFullscreen(setup.fullscreen);
7914 /* set setup value according to successfully changed fullscreen mode */
7915 setup.fullscreen = video.fullscreen_enabled;
7921 if (change_fullscreen ||
7922 change_fullscreen_mode ||
7923 change_window_scaling_percent)
7925 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7927 /* save backbuffer content which gets lost when toggling fullscreen mode */
7928 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7930 if (change_fullscreen_mode)
7932 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7933 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7936 if (change_window_scaling_percent)
7938 /* keep window mode, but change window scaling */
7939 video.fullscreen_enabled = TRUE; /* force new window scaling */
7942 /* toggle fullscreen */
7943 ChangeVideoModeIfNeeded(setup.fullscreen);
7945 /* set setup value according to successfully changed fullscreen mode */
7946 setup.fullscreen = video.fullscreen_enabled;
7948 /* restore backbuffer content from temporary backbuffer backup bitmap */
7949 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7951 FreeBitmap(tmp_backbuffer);
7953 /* update visible window/screen */
7954 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7958 void ChangeViewportPropertiesIfNeeded()
7960 int gfx_game_mode = game_status;
7961 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7963 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7964 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7965 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7966 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7967 int border_size = vp_playfield->border_size;
7968 int new_sx = vp_playfield->x + border_size;
7969 int new_sy = vp_playfield->y + border_size;
7970 int new_sxsize = vp_playfield->width - 2 * border_size;
7971 int new_sysize = vp_playfield->height - 2 * border_size;
7972 int new_real_sx = vp_playfield->x;
7973 int new_real_sy = vp_playfield->y;
7974 int new_full_sxsize = vp_playfield->width;
7975 int new_full_sysize = vp_playfield->height;
7976 int new_dx = vp_door_1->x;
7977 int new_dy = vp_door_1->y;
7978 int new_dxsize = vp_door_1->width;
7979 int new_dysize = vp_door_1->height;
7980 int new_vx = vp_door_2->x;
7981 int new_vy = vp_door_2->y;
7982 int new_vxsize = vp_door_2->width;
7983 int new_vysize = vp_door_2->height;
7984 int new_ex = vp_door_3->x;
7985 int new_ey = vp_door_3->y;
7986 int new_exsize = vp_door_3->width;
7987 int new_eysize = vp_door_3->height;
7988 int new_tilesize_var =
7989 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
7991 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
7992 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
7993 int new_scr_fieldx = new_sxsize / tilesize;
7994 int new_scr_fieldy = new_sysize / tilesize;
7995 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
7996 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
7997 boolean init_gfx_buffers = FALSE;
7998 boolean init_video_buffer = FALSE;
7999 boolean init_gadgets_and_toons = FALSE;
8000 boolean init_em_graphics = FALSE;
8001 boolean drawing_area_changed = FALSE;
8003 if (viewport.window.width != WIN_XSIZE ||
8004 viewport.window.height != WIN_YSIZE)
8006 WIN_XSIZE = viewport.window.width;
8007 WIN_YSIZE = viewport.window.height;
8009 init_video_buffer = TRUE;
8010 init_gfx_buffers = TRUE;
8012 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
8015 if (new_scr_fieldx != SCR_FIELDX ||
8016 new_scr_fieldy != SCR_FIELDY)
8018 /* this always toggles between MAIN and GAME when using small tile size */
8020 SCR_FIELDX = new_scr_fieldx;
8021 SCR_FIELDY = new_scr_fieldy;
8023 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8034 new_sxsize != SXSIZE ||
8035 new_sysize != SYSIZE ||
8036 new_dxsize != DXSIZE ||
8037 new_dysize != DYSIZE ||
8038 new_vxsize != VXSIZE ||
8039 new_vysize != VYSIZE ||
8040 new_exsize != EXSIZE ||
8041 new_eysize != EYSIZE ||
8042 new_real_sx != REAL_SX ||
8043 new_real_sy != REAL_SY ||
8044 new_full_sxsize != FULL_SXSIZE ||
8045 new_full_sysize != FULL_SYSIZE ||
8046 new_tilesize_var != TILESIZE_VAR
8049 if (new_tilesize_var != TILESIZE_VAR)
8051 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8053 // changing tile size invalidates scroll values of engine snapshots
8054 FreeEngineSnapshot();
8056 // changing tile size requires update of graphic mapping for EM engine
8057 init_em_graphics = TRUE;
8062 new_sxsize != SXSIZE ||
8063 new_sysize != SYSIZE ||
8064 new_real_sx != REAL_SX ||
8065 new_real_sy != REAL_SY ||
8066 new_full_sxsize != FULL_SXSIZE ||
8067 new_full_sysize != FULL_SYSIZE)
8069 if (!init_video_buffer)
8070 drawing_area_changed = TRUE;
8081 SXSIZE = new_sxsize;
8082 SYSIZE = new_sysize;
8083 DXSIZE = new_dxsize;
8084 DYSIZE = new_dysize;
8085 VXSIZE = new_vxsize;
8086 VYSIZE = new_vysize;
8087 EXSIZE = new_exsize;
8088 EYSIZE = new_eysize;
8089 REAL_SX = new_real_sx;
8090 REAL_SY = new_real_sy;
8091 FULL_SXSIZE = new_full_sxsize;
8092 FULL_SYSIZE = new_full_sysize;
8093 TILESIZE_VAR = new_tilesize_var;
8095 init_gfx_buffers = TRUE;
8096 init_gadgets_and_toons = TRUE;
8098 // printf("::: viewports: init_gfx_buffers\n");
8099 // printf("::: viewports: init_gadgets_and_toons\n");
8102 if (init_gfx_buffers)
8104 // printf("::: init_gfx_buffers\n");
8106 SCR_FIELDX = new_scr_fieldx_buffers;
8107 SCR_FIELDY = new_scr_fieldy_buffers;
8111 SCR_FIELDX = new_scr_fieldx;
8112 SCR_FIELDY = new_scr_fieldy;
8114 gfx.drawing_area_changed = drawing_area_changed;
8116 SetDrawDeactivationMask(REDRAW_NONE);
8117 SetDrawBackgroundMask(REDRAW_FIELD);
8120 if (init_video_buffer)
8122 // printf("::: init_video_buffer\n");
8124 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8127 if (init_gadgets_and_toons)
8129 // printf("::: init_gadgets_and_toons\n");
8135 if (init_em_graphics)
8137 InitGraphicInfo_EM();