1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
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 /* forward declaration for internal use */
41 static void UnmapToolButtons();
42 static void HandleToolButtons(struct GadgetInfo *);
43 static int el_act_dir2crm(int, int, int);
44 static int el_act2crm(int, int);
46 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
47 static int request_gadget_id = -1;
49 static char *print_if_not_empty(int element)
51 static char *s = NULL;
52 char *token_name = element_info[element].token_name;
57 s = checked_malloc(strlen(token_name) + 10 + 1);
59 if (element != EL_EMPTY)
60 sprintf(s, "%d\t['%s']", element, token_name);
62 sprintf(s, "%d", element);
67 void DumpTile(int x, int y)
72 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
79 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
82 if (!IN_LEV_FIELD(x, y))
84 printf("(not in level field)\n");
90 printf(" Feld: %d\t['%s']\n", Feld[x][y],
91 element_info[Feld[x][y]].token_name);
92 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
93 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
94 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
95 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
96 printf(" MovPos: %d\n", MovPos[x][y]);
97 printf(" MovDir: %d\n", MovDir[x][y]);
98 printf(" MovDelay: %d\n", MovDelay[x][y]);
99 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
100 printf(" CustomValue: %d\n", CustomValue[x][y]);
101 printf(" GfxElement: %d\n", GfxElement[x][y]);
102 printf(" GfxAction: %d\n", GfxAction[x][y]);
103 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
107 void SetDrawtoField(int mode)
109 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
117 BX2 = SCR_FIELDX + 1;
118 BY2 = SCR_FIELDY + 1;
137 BX2 = SCR_FIELDX + 1;
138 BY2 = SCR_FIELDY + 1;
153 drawto_field = fieldbuffer;
155 else /* DRAW_BACKBUFFER */
161 BX2 = SCR_FIELDX - 1;
162 BY2 = SCR_FIELDY - 1;
166 drawto_field = backbuffer;
170 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
172 if (game_status == GAME_MODE_PLAYING &&
173 level.game_engine_type == GAME_ENGINE_TYPE_EM)
175 /* currently there is no partial redraw -- always redraw whole playfield */
176 RedrawPlayfield_EM(TRUE);
178 /* blit playfield from scroll buffer to normal back buffer for fading in */
179 BlitScreenToBitmap_EM(backbuffer);
181 else if (game_status == GAME_MODE_PLAYING &&
182 level.game_engine_type == GAME_ENGINE_TYPE_SP)
184 /* currently there is no partial redraw -- always redraw whole playfield */
185 RedrawPlayfield_SP(TRUE);
187 /* blit playfield from scroll buffer to normal back buffer for fading in */
188 BlitScreenToBitmap_SP(backbuffer);
190 else if (game_status == GAME_MODE_PLAYING &&
191 !game.envelope_active)
197 width = gfx.sxsize + 2 * TILEX;
198 height = gfx.sysize + 2 * TILEY;
204 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
205 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
207 for (xx = BX1; xx <= BX2; xx++)
208 for (yy = BY1; yy <= BY2; yy++)
209 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
210 DrawScreenField(xx, yy);
214 if (setup.soft_scrolling)
216 int fx = FX, fy = FY;
218 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
219 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
221 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
233 BlitBitmap(drawto, window, x, y, width, height, x, y);
236 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
238 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
240 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
241 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
244 void DrawMaskedBorder_FIELD()
246 if (global.border_status >= GAME_MODE_TITLE &&
247 global.border_status <= GAME_MODE_PLAYING &&
248 border.draw_masked[global.border_status])
249 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
252 void DrawMaskedBorder_DOOR_1()
254 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
255 (global.border_status != GAME_MODE_EDITOR ||
256 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
257 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
260 void DrawMaskedBorder_DOOR_2()
262 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
263 global.border_status != GAME_MODE_EDITOR)
264 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
267 void DrawMaskedBorder_DOOR_3()
269 /* currently not available */
272 void DrawMaskedBorder_ALL()
274 DrawMaskedBorder_FIELD();
275 DrawMaskedBorder_DOOR_1();
276 DrawMaskedBorder_DOOR_2();
277 DrawMaskedBorder_DOOR_3();
280 void DrawMaskedBorder(int redraw_mask)
282 /* never draw masked screen borders on borderless screens */
283 if (effectiveGameStatus() == GAME_MODE_LOADING ||
284 effectiveGameStatus() == GAME_MODE_TITLE)
287 /* never draw masked screen borders when displaying request outside door */
288 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
289 global.use_envelope_request)
292 if (redraw_mask & REDRAW_ALL)
293 DrawMaskedBorder_ALL();
296 if (redraw_mask & REDRAW_FIELD)
297 DrawMaskedBorder_FIELD();
298 if (redraw_mask & REDRAW_DOOR_1)
299 DrawMaskedBorder_DOOR_1();
300 if (redraw_mask & REDRAW_DOOR_2)
301 DrawMaskedBorder_DOOR_2();
302 if (redraw_mask & REDRAW_DOOR_3)
303 DrawMaskedBorder_DOOR_3();
310 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
313 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
314 for (x = 0; x < SCR_FIELDX; x++)
315 for (y = 0 ; y < SCR_FIELDY; y++)
316 if (redraw[redraw_x1 + x][redraw_y1 + y])
317 printf("::: - %d, %d [%s]\n",
318 LEVELX(x), LEVELY(y),
319 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
322 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
323 redraw_mask |= REDRAW_FIELD;
325 if (redraw_mask & REDRAW_FIELD)
326 redraw_mask &= ~REDRAW_TILES;
328 if (redraw_mask == REDRAW_NONE)
331 if (redraw_mask & REDRAW_TILES &&
332 game_status == GAME_MODE_PLAYING &&
333 border.draw_masked[GAME_MODE_PLAYING])
334 redraw_mask |= REDRAW_FIELD;
336 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
338 static boolean last_frame_skipped = FALSE;
339 boolean skip_even_when_not_scrolling = TRUE;
340 boolean just_scrolling = (ScreenMovDir != 0);
341 boolean verbose = FALSE;
343 if (global.fps_slowdown_factor > 1 &&
344 (FrameCounter % global.fps_slowdown_factor) &&
345 (just_scrolling || skip_even_when_not_scrolling))
347 redraw_mask &= ~REDRAW_MAIN;
349 last_frame_skipped = TRUE;
352 printf("FRAME SKIPPED\n");
356 if (last_frame_skipped)
357 redraw_mask |= REDRAW_FIELD;
359 last_frame_skipped = FALSE;
362 printf("frame not skipped\n");
366 /* synchronize X11 graphics at this point; if we would synchronize the
367 display immediately after the buffer switching (after the XFlush),
368 this could mean that we have to wait for the graphics to complete,
369 although we could go on doing calculations for the next frame */
373 /* never draw masked border to backbuffer when using playfield buffer */
374 if (game_status != GAME_MODE_PLAYING ||
375 redraw_mask & REDRAW_FROM_BACKBUFFER ||
376 buffer == backbuffer)
377 DrawMaskedBorder(redraw_mask);
379 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
381 if (redraw_mask & REDRAW_ALL)
383 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
385 redraw_mask = REDRAW_NONE;
388 if (redraw_mask & REDRAW_FIELD)
391 printf("::: REDRAW_FIELD\n");
394 if (game_status != GAME_MODE_PLAYING ||
395 redraw_mask & REDRAW_FROM_BACKBUFFER)
397 BlitBitmap(backbuffer, window,
398 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
402 int fx = FX, fy = FY;
404 if (setup.soft_scrolling)
407 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
408 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
410 fx += dx * TILESIZE_VAR / TILESIZE;
411 fy += dy * TILESIZE_VAR / TILESIZE;
413 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
414 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
418 printf("::: %d, %d [%d, %d] [%d, %d]\n",
419 fx, fy, FX, FY, ScreenMovDir, ScreenGfxPos);
424 fx = fx * TILESIZE_VAR / TILESIZE;
425 fy = fy * TILESIZE_VAR / TILESIZE;
430 if (setup.soft_scrolling ||
431 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
432 ABS(ScreenMovPos) == ScrollStepSize ||
433 redraw_tiles > REDRAWTILES_THRESHOLD)
435 if (border.draw_masked[GAME_MODE_PLAYING])
437 if (buffer != backbuffer)
439 /* copy playfield buffer to backbuffer to add masked border */
440 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
441 DrawMaskedBorder(REDRAW_FIELD);
444 BlitBitmap(backbuffer, window,
445 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
450 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
455 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
457 (setup.soft_scrolling ?
458 "setup.soft_scrolling" :
459 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
460 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
461 ABS(ScreenGfxPos) == ScrollStepSize ?
462 "ABS(ScreenGfxPos) == ScrollStepSize" :
463 "redraw_tiles > REDRAWTILES_THRESHOLD"));
469 redraw_mask &= ~REDRAW_MAIN;
472 if (redraw_mask & REDRAW_DOORS)
474 if (redraw_mask & REDRAW_DOOR_1)
475 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
477 if (redraw_mask & REDRAW_DOOR_2)
478 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
480 if (redraw_mask & REDRAW_DOOR_3)
481 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
483 redraw_mask &= ~REDRAW_DOORS;
486 if (redraw_mask & REDRAW_MICROLEVEL)
488 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
489 SX, SY + 10 * TILEY);
491 redraw_mask &= ~REDRAW_MICROLEVEL;
494 if (redraw_mask & REDRAW_TILES)
497 printf("::: REDRAW_TILES\n");
501 for (x = 0; x < SCR_FIELDX; x++)
502 for (y = 0 ; y < SCR_FIELDY; y++)
503 if (redraw[redraw_x1 + x][redraw_y1 + y])
504 BlitBitmap(buffer, window,
505 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
506 TILEX_VAR, TILEY_VAR,
507 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
509 for (x = 0; x < SCR_FIELDX; x++)
510 for (y = 0 ; y < SCR_FIELDY; y++)
511 if (redraw[redraw_x1 + x][redraw_y1 + y])
512 BlitBitmap(buffer, window,
513 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
514 SX + x * TILEX, SY + y * TILEY);
518 if (redraw_mask & REDRAW_FPS) /* display frames per second */
523 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
524 if (!global.fps_slowdown)
527 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
529 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
531 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
537 for (x = 0; x < MAX_BUF_XSIZE; x++)
538 for (y = 0; y < MAX_BUF_YSIZE; y++)
541 redraw_mask = REDRAW_NONE;
544 static void FadeCrossSaveBackbuffer()
546 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
549 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
551 static int fade_type_skip = FADE_TYPE_NONE;
552 void (*draw_border_function)(void) = NULL;
553 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
554 int x, y, width, height;
555 int fade_delay, post_delay;
557 if (fade_type == FADE_TYPE_FADE_OUT)
559 if (fade_type_skip != FADE_TYPE_NONE)
562 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
565 /* skip all fade operations until specified fade operation */
566 if (fade_type & fade_type_skip)
567 fade_type_skip = FADE_TYPE_NONE;
572 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
574 FadeCrossSaveBackbuffer();
580 redraw_mask |= fade_mask;
582 if (fade_type == FADE_TYPE_SKIP)
585 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
588 fade_type_skip = fade_mode;
594 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
599 fade_delay = fading.fade_delay;
600 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
603 if (fade_type_skip != FADE_TYPE_NONE)
606 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
609 /* skip all fade operations until specified fade operation */
610 if (fade_type & fade_type_skip)
611 fade_type_skip = FADE_TYPE_NONE;
621 if (global.autoplay_leveldir)
623 // fading.fade_mode = FADE_MODE_NONE;
630 if (fading.fade_mode == FADE_MODE_NONE)
638 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
641 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
645 if (fade_mask == REDRAW_NONE)
646 fade_mask = REDRAW_FIELD;
649 // if (fade_mask & REDRAW_FIELD)
650 if (fade_mask == REDRAW_FIELD)
655 height = FULL_SYSIZE;
658 fade_delay = fading.fade_delay;
659 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
662 if (border.draw_masked_when_fading)
663 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
665 DrawMaskedBorder_FIELD(); /* draw once */
667 else /* REDRAW_ALL */
675 fade_delay = fading.fade_delay;
676 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
681 if (!setup.fade_screens ||
683 fading.fade_mode == FADE_MODE_NONE)
685 if (!setup.fade_screens || fade_delay == 0)
688 if (fade_mode == FADE_MODE_FADE_OUT)
692 if (fade_mode == FADE_MODE_FADE_OUT &&
693 fading.fade_mode != FADE_MODE_NONE)
694 ClearRectangle(backbuffer, x, y, width, height);
698 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
699 redraw_mask = REDRAW_NONE;
707 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
708 draw_border_function);
710 redraw_mask &= ~fade_mask;
713 void FadeIn(int fade_mask)
715 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
716 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
718 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
721 void FadeOut(int fade_mask)
723 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
724 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
726 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
728 global.border_status = game_status;
731 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
733 static struct TitleFadingInfo fading_leave_stored;
736 fading_leave_stored = fading_leave;
738 fading = fading_leave_stored;
741 void FadeSetEnterMenu()
743 fading = menu.enter_menu;
746 printf("::: storing enter_menu\n");
749 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
752 void FadeSetLeaveMenu()
754 fading = menu.leave_menu;
757 printf("::: storing leave_menu\n");
760 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
763 void FadeSetEnterScreen()
765 fading = menu.enter_screen[game_status];
768 printf("::: storing leave_screen[%d]\n", game_status);
771 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
774 void FadeSetNextScreen()
776 fading = menu.next_screen;
779 printf("::: storing next_screen\n");
782 // (do not overwrite fade mode set by FadeSetEnterScreen)
783 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
786 void FadeSetLeaveScreen()
789 printf("::: recalling last stored value\n");
792 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
795 void FadeSetFromType(int type)
797 if (type & TYPE_ENTER_SCREEN)
798 FadeSetEnterScreen();
799 else if (type & TYPE_ENTER)
801 else if (type & TYPE_LEAVE)
805 void FadeSetDisabled()
807 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
809 fading = fading_none;
812 void FadeSkipNextFadeIn()
814 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
817 void FadeSkipNextFadeOut()
819 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
822 void SetWindowBackgroundImageIfDefined(int graphic)
824 if (graphic_info[graphic].bitmap)
825 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
828 void SetMainBackgroundImageIfDefined(int graphic)
830 if (graphic_info[graphic].bitmap)
831 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
834 void SetDoorBackgroundImageIfDefined(int graphic)
836 if (graphic_info[graphic].bitmap)
837 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
840 void SetWindowBackgroundImage(int graphic)
842 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
843 graphic_info[graphic].bitmap ?
844 graphic_info[graphic].bitmap :
845 graphic_info[IMG_BACKGROUND].bitmap);
848 void SetMainBackgroundImage(int graphic)
850 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
851 graphic_info[graphic].bitmap ?
852 graphic_info[graphic].bitmap :
853 graphic_info[IMG_BACKGROUND].bitmap);
856 void SetDoorBackgroundImage(int graphic)
858 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
859 graphic_info[graphic].bitmap ?
860 graphic_info[graphic].bitmap :
861 graphic_info[IMG_BACKGROUND].bitmap);
864 void SetPanelBackground()
867 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
870 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
871 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
873 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
874 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
875 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
876 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
879 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
880 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
883 SetDoorBackgroundBitmap(bitmap_db_panel);
886 void DrawBackground(int x, int y, int width, int height)
888 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
889 /* (when entering hall of fame after playing) */
891 ClearRectangleOnBackground(drawto, x, y, width, height);
893 ClearRectangleOnBackground(backbuffer, x, y, width, height);
896 redraw_mask |= REDRAW_FIELD;
899 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
901 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
903 if (font->bitmap == NULL)
906 DrawBackground(x, y, width, height);
909 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
911 struct GraphicInfo *g = &graphic_info[graphic];
913 if (g->bitmap == NULL)
916 DrawBackground(x, y, width, height);
921 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
922 /* (when entering hall of fame after playing) */
923 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
925 /* !!! maybe this should be done before clearing the background !!! */
926 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
928 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
929 SetDrawtoField(DRAW_BUFFERED);
932 SetDrawtoField(DRAW_BACKBUFFER);
935 void MarkTileDirty(int x, int y)
937 int xx = redraw_x1 + x;
938 int yy = redraw_y1 + y;
943 redraw[xx][yy] = TRUE;
944 redraw_mask |= REDRAW_TILES;
947 void SetBorderElement()
951 BorderElement = EL_EMPTY;
953 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
955 for (x = 0; x < lev_fieldx; x++)
957 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
958 BorderElement = EL_STEELWALL;
960 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
966 void FloodFillLevel(int from_x, int from_y, int fill_element,
967 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
968 int max_fieldx, int max_fieldy)
972 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
973 static int safety = 0;
975 /* check if starting field still has the desired content */
976 if (field[from_x][from_y] == fill_element)
981 if (safety > max_fieldx * max_fieldy)
982 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
984 old_element = field[from_x][from_y];
985 field[from_x][from_y] = fill_element;
987 for (i = 0; i < 4; i++)
989 x = from_x + check[i][0];
990 y = from_y + check[i][1];
992 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
993 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
999 void SetRandomAnimationValue(int x, int y)
1001 gfx.anim_random_frame = GfxRandom[x][y];
1004 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1006 /* animation synchronized with global frame counter, not move position */
1007 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1008 sync_frame = FrameCounter;
1010 return getAnimationFrame(graphic_info[graphic].anim_frames,
1011 graphic_info[graphic].anim_delay,
1012 graphic_info[graphic].anim_mode,
1013 graphic_info[graphic].anim_start_frame,
1017 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1018 Bitmap **bitmap, int *x, int *y,
1019 boolean get_backside)
1023 int width_mult, width_div;
1024 int height_mult, height_div;
1028 { 15, 16, 2, 3 }, /* 1 x 1 */
1029 { 7, 8, 2, 3 }, /* 2 x 2 */
1030 { 3, 4, 2, 3 }, /* 4 x 4 */
1031 { 1, 2, 2, 3 }, /* 8 x 8 */
1032 { 0, 1, 2, 3 }, /* 16 x 16 */
1033 { 0, 1, 0, 1 }, /* 32 x 32 */
1035 struct GraphicInfo *g = &graphic_info[graphic];
1036 Bitmap *src_bitmap = g->bitmap;
1037 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1038 int offset_calc_pos = log_2(tilesize);
1039 int width_mult = offset_calc[offset_calc_pos].width_mult;
1040 int width_div = offset_calc[offset_calc_pos].width_div;
1041 int height_mult = offset_calc[offset_calc_pos].height_mult;
1042 int height_div = offset_calc[offset_calc_pos].height_div;
1043 int startx = src_bitmap->width * width_mult / width_div;
1044 int starty = src_bitmap->height * height_mult / height_div;
1046 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1047 tilesize / TILESIZE;
1048 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1049 tilesize / TILESIZE;
1051 int src_x = g->src_x * tilesize / TILESIZE;
1052 int src_y = g->src_y * tilesize / TILESIZE;
1054 int width = g->width * tilesize / TILESIZE;
1055 int height = g->height * tilesize / TILESIZE;
1056 int offset_x = g->offset_x * tilesize / TILESIZE;
1057 int offset_y = g->offset_y * tilesize / TILESIZE;
1059 if (g->offset_y == 0) /* frames are ordered horizontally */
1061 int max_width = g->anim_frames_per_line * width;
1062 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1064 src_x = pos % max_width;
1065 src_y = src_y % height + pos / max_width * height;
1067 else if (g->offset_x == 0) /* frames are ordered vertically */
1069 int max_height = g->anim_frames_per_line * height;
1070 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1072 src_x = src_x % width + pos / max_height * width;
1073 src_y = pos % max_height;
1075 else /* frames are ordered diagonally */
1077 src_x = src_x + frame * offset_x;
1078 src_y = src_y + frame * offset_y;
1081 *bitmap = src_bitmap;
1082 *x = startx + src_x;
1083 *y = starty + src_y;
1086 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1087 int *x, int *y, boolean get_backside)
1089 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1093 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1094 Bitmap **bitmap, int *x, int *y)
1096 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1099 void getFixedGraphicSource(int graphic, int frame,
1100 Bitmap **bitmap, int *x, int *y)
1102 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1105 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1108 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1110 struct GraphicInfo *g = &graphic_info[graphic];
1111 int mini_startx = 0;
1112 int mini_starty = g->bitmap->height * 2 / 3;
1114 *bitmap = g->bitmap;
1115 *x = mini_startx + g->src_x / 2;
1116 *y = mini_starty + g->src_y / 2;
1120 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1121 int *x, int *y, boolean get_backside)
1123 struct GraphicInfo *g = &graphic_info[graphic];
1124 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1125 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1128 if (TILESIZE_VAR != TILESIZE)
1129 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1133 *bitmap = g->bitmap;
1135 if (g->offset_y == 0) /* frames are ordered horizontally */
1137 int max_width = g->anim_frames_per_line * g->width;
1138 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1140 *x = pos % max_width;
1141 *y = src_y % g->height + pos / max_width * g->height;
1143 else if (g->offset_x == 0) /* frames are ordered vertically */
1145 int max_height = g->anim_frames_per_line * g->height;
1146 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1148 *x = src_x % g->width + pos / max_height * g->width;
1149 *y = pos % max_height;
1151 else /* frames are ordered diagonally */
1153 *x = src_x + frame * g->offset_x;
1154 *y = src_y + frame * g->offset_y;
1158 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1160 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1163 void DrawGraphic(int x, int y, int graphic, int frame)
1166 if (!IN_SCR_FIELD(x, y))
1168 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1169 printf("DrawGraphic(): This should never happen!\n");
1175 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1178 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1180 MarkTileDirty(x, y);
1183 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1186 if (!IN_SCR_FIELD(x, y))
1188 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1189 printf("DrawGraphic(): This should never happen!\n");
1194 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1196 MarkTileDirty(x, y);
1199 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1205 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1207 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1209 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1213 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1219 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1220 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1223 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1226 if (!IN_SCR_FIELD(x, y))
1228 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1229 printf("DrawGraphicThruMask(): This should never happen!\n");
1235 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1238 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1241 MarkTileDirty(x, y);
1244 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1247 if (!IN_SCR_FIELD(x, y))
1249 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1250 printf("DrawGraphicThruMask(): This should never happen!\n");
1255 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1257 MarkTileDirty(x, y);
1260 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1266 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1268 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1269 dst_x - src_x, dst_y - src_y);
1271 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1274 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1278 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1279 int graphic, int frame)
1284 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1286 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1287 dst_x - src_x, dst_y - src_y);
1288 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1291 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1293 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1295 MarkTileDirty(x / tilesize, y / tilesize);
1298 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1304 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1305 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1308 void DrawMiniGraphic(int x, int y, int graphic)
1310 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1311 MarkTileDirty(x / 2, y / 2);
1314 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1319 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1320 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1323 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1324 int graphic, int frame,
1325 int cut_mode, int mask_mode)
1330 int width = TILEX, height = TILEY;
1333 if (dx || dy) /* shifted graphic */
1335 if (x < BX1) /* object enters playfield from the left */
1342 else if (x > BX2) /* object enters playfield from the right */
1348 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1354 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1356 else if (dx) /* general horizontal movement */
1357 MarkTileDirty(x + SIGN(dx), y);
1359 if (y < BY1) /* object enters playfield from the top */
1361 if (cut_mode==CUT_BELOW) /* object completely above top border */
1369 else if (y > BY2) /* object enters playfield from the bottom */
1375 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1381 else if (dy > 0 && cut_mode == CUT_ABOVE)
1383 if (y == BY2) /* object completely above bottom border */
1389 MarkTileDirty(x, y + 1);
1390 } /* object leaves playfield to the bottom */
1391 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1393 else if (dy) /* general vertical movement */
1394 MarkTileDirty(x, y + SIGN(dy));
1398 if (!IN_SCR_FIELD(x, y))
1400 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1401 printf("DrawGraphicShifted(): This should never happen!\n");
1407 width = width * TILESIZE_VAR / TILESIZE;
1408 height = height * TILESIZE_VAR / TILESIZE;
1409 cx = cx * TILESIZE_VAR / TILESIZE;
1410 cy = cy * TILESIZE_VAR / TILESIZE;
1411 dx = dx * TILESIZE_VAR / TILESIZE;
1412 dy = dy * TILESIZE_VAR / TILESIZE;
1415 if (width > 0 && height > 0)
1417 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1423 dst_x = FX + x * TILEX_VAR + dx;
1424 dst_y = FY + y * TILEY_VAR + dy;
1426 dst_x = FX + x * TILEX + dx;
1427 dst_y = FY + y * TILEY + dy;
1430 if (mask_mode == USE_MASKING)
1432 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1433 dst_x - src_x, dst_y - src_y);
1434 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1438 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1441 MarkTileDirty(x, y);
1445 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1446 int graphic, int frame,
1447 int cut_mode, int mask_mode)
1453 int width = TILEX_VAR, height = TILEY_VAR;
1455 int width = TILEX, height = TILEY;
1459 int x2 = x + SIGN(dx);
1460 int y2 = y + SIGN(dy);
1462 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1463 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1465 /* movement with two-tile animations must be sync'ed with movement position,
1466 not with current GfxFrame (which can be higher when using slow movement) */
1467 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1468 int anim_frames = graphic_info[graphic].anim_frames;
1470 /* (we also need anim_delay here for movement animations with less frames) */
1471 int anim_delay = graphic_info[graphic].anim_delay;
1472 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1474 int sync_frame = anim_pos * anim_frames / TILESIZE;
1477 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1478 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1480 /* re-calculate animation frame for two-tile movement animation */
1481 frame = getGraphicAnimationFrame(graphic, sync_frame);
1485 printf("::: %d, %d, %d => %d [%d]\n",
1486 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1488 printf("::: %d, %d => %d\n",
1489 anim_pos, anim_frames, sync_frame);
1494 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1495 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1498 /* check if movement start graphic inside screen area and should be drawn */
1499 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1501 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1504 dst_x = FX + x1 * TILEX_VAR;
1505 dst_y = FY + y1 * TILEY_VAR;
1507 dst_x = FX + x1 * TILEX;
1508 dst_y = FY + y1 * TILEY;
1511 if (mask_mode == USE_MASKING)
1513 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1514 dst_x - src_x, dst_y - src_y);
1515 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1519 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1522 MarkTileDirty(x1, y1);
1525 /* check if movement end graphic inside screen area and should be drawn */
1526 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1528 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1531 dst_x = FX + x2 * TILEX_VAR;
1532 dst_y = FY + y2 * TILEY_VAR;
1534 dst_x = FX + x2 * TILEX;
1535 dst_y = FY + y2 * TILEY;
1538 if (mask_mode == USE_MASKING)
1540 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1541 dst_x - src_x, dst_y - src_y);
1542 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1546 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1549 MarkTileDirty(x2, y2);
1553 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1554 int graphic, int frame,
1555 int cut_mode, int mask_mode)
1559 DrawGraphic(x, y, graphic, frame);
1564 if (graphic_info[graphic].double_movement) /* EM style movement images */
1565 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1567 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1570 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1571 int frame, int cut_mode)
1573 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1576 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1577 int cut_mode, int mask_mode)
1579 int lx = LEVELX(x), ly = LEVELY(y);
1583 if (IN_LEV_FIELD(lx, ly))
1585 SetRandomAnimationValue(lx, ly);
1587 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1588 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1590 /* do not use double (EM style) movement graphic when not moving */
1591 if (graphic_info[graphic].double_movement && !dx && !dy)
1593 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1594 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1597 else /* border element */
1599 graphic = el2img(element);
1600 frame = getGraphicAnimationFrame(graphic, -1);
1603 if (element == EL_EXPANDABLE_WALL)
1605 boolean left_stopped = FALSE, right_stopped = FALSE;
1607 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1608 left_stopped = TRUE;
1609 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1610 right_stopped = TRUE;
1612 if (left_stopped && right_stopped)
1614 else if (left_stopped)
1616 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1617 frame = graphic_info[graphic].anim_frames - 1;
1619 else if (right_stopped)
1621 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1622 frame = graphic_info[graphic].anim_frames - 1;
1627 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1628 else if (mask_mode == USE_MASKING)
1629 DrawGraphicThruMask(x, y, graphic, frame);
1631 DrawGraphic(x, y, graphic, frame);
1634 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1635 int cut_mode, int mask_mode)
1637 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1638 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1639 cut_mode, mask_mode);
1642 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1645 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1648 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1651 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1654 void DrawLevelElementThruMask(int x, int y, int element)
1656 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1659 void DrawLevelFieldThruMask(int x, int y)
1661 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1664 /* !!! implementation of quicksand is totally broken !!! */
1665 #define IS_CRUMBLED_TILE(x, y, e) \
1666 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1667 !IS_MOVING(x, y) || \
1668 (e) == EL_QUICKSAND_EMPTYING || \
1669 (e) == EL_QUICKSAND_FAST_EMPTYING))
1671 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1676 int width, height, cx, cy;
1677 int sx = SCREENX(x), sy = SCREENY(y);
1678 int crumbled_border_size = graphic_info[graphic].border_size;
1681 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1683 for (i = 1; i < 4; i++)
1685 int dxx = (i & 1 ? dx : 0);
1686 int dyy = (i & 2 ? dy : 0);
1689 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1692 /* check if neighbour field is of same crumble type */
1693 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1694 graphic_info[graphic].class ==
1695 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1697 /* return if check prevents inner corner */
1698 if (same == (dxx == dx && dyy == dy))
1702 /* if we reach this point, we have an inner corner */
1704 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1707 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1708 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1709 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1710 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1712 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1713 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1715 width = crumbled_border_size;
1716 height = crumbled_border_size;
1717 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1718 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1720 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1721 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1725 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1730 int width, height, bx, by, cx, cy;
1731 int sx = SCREENX(x), sy = SCREENY(y);
1732 int crumbled_border_size = graphic_info[graphic].border_size;
1735 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1737 /* draw simple, sloppy, non-corner-accurate crumbled border */
1740 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1741 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1742 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1743 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1745 if (dir == 1 || dir == 2) /* left or right crumbled border */
1747 width = crumbled_border_size;
1749 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1752 else /* top or bottom crumbled border */
1755 height = crumbled_border_size;
1757 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1762 BlitBitmap(src_bitmap, drawto_field,
1763 src_x + cx * TILESIZE_VAR / TILESIZE,
1764 src_y + cy * TILESIZE_VAR / TILESIZE,
1765 width * TILESIZE_VAR / TILESIZE,
1766 height * TILESIZE_VAR / TILESIZE,
1767 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
1768 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
1770 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1771 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1774 /* (remaining middle border part must be at least as big as corner part) */
1775 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1776 crumbled_border_size >= TILESIZE / 3)
1779 /* correct corners of crumbled border, if needed */
1782 for (i = -1; i <= 1; i+=2)
1784 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1785 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1786 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1789 /* check if neighbour field is of same crumble type */
1790 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1791 graphic_info[graphic].class ==
1792 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1794 /* no crumbled corner, but continued crumbled border */
1796 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
1797 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
1798 int b1 = (i == 1 ? crumbled_border_size :
1799 TILESIZE - 2 * crumbled_border_size);
1801 width = crumbled_border_size;
1802 height = crumbled_border_size;
1804 if (dir == 1 || dir == 2)
1820 BlitBitmap(src_bitmap, drawto_field,
1821 src_x + bx * TILESIZE_VAR / TILESIZE,
1822 src_y + by * TILESIZE_VAR / TILESIZE,
1823 width * TILESIZE_VAR / TILESIZE,
1824 height * TILESIZE_VAR / TILESIZE,
1825 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
1826 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
1828 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1829 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1834 if (dir == 1 || dir == 2) /* left or right crumbled border */
1836 for (i = -1; i <= 1; i+=2)
1840 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1843 /* check if neighbour field is of same crumble type */
1844 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1845 graphic_info[graphic].class ==
1846 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1848 /* no crumbled corner, but continued crumbled border */
1850 width = crumbled_border_size;
1851 height = crumbled_border_size;
1852 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1853 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
1855 by = (i == 1 ? crumbled_border_size :
1856 TILEY - 2 * crumbled_border_size);
1858 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1859 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1863 else /* top or bottom crumbled border */
1865 for (i = -1; i <= 1; i+=2)
1869 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1872 /* check if neighbour field is of same crumble type */
1873 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1874 graphic_info[graphic].class ==
1875 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1877 /* no crumbled corner, but continued crumbled border */
1879 width = crumbled_border_size;
1880 height = crumbled_border_size;
1881 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1882 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1883 bx = (i == 1 ? crumbled_border_size :
1884 TILEX - 2 * crumbled_border_size);
1887 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1888 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1895 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1897 int sx = SCREENX(x), sy = SCREENY(y);
1900 static int xy[4][2] =
1908 if (!IN_LEV_FIELD(x, y))
1911 element = TILE_GFX_ELEMENT(x, y);
1913 /* crumble field itself */
1914 if (IS_CRUMBLED_TILE(x, y, element))
1916 if (!IN_SCR_FIELD(sx, sy))
1919 for (i = 0; i < 4; i++)
1921 int xx = x + xy[i][0];
1922 int yy = y + xy[i][1];
1924 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1927 /* check if neighbour field is of same crumble type */
1929 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1930 graphic_info[graphic].class ==
1931 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1934 if (IS_CRUMBLED_TILE(xx, yy, element))
1938 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1941 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1942 graphic_info[graphic].anim_frames == 2)
1944 for (i = 0; i < 4; i++)
1946 int dx = (i & 1 ? +1 : -1);
1947 int dy = (i & 2 ? +1 : -1);
1949 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1953 MarkTileDirty(sx, sy);
1955 else /* center field not crumbled -- crumble neighbour fields */
1957 for (i = 0; i < 4; i++)
1959 int xx = x + xy[i][0];
1960 int yy = y + xy[i][1];
1961 int sxx = sx + xy[i][0];
1962 int syy = sy + xy[i][1];
1964 if (!IN_LEV_FIELD(xx, yy) ||
1965 !IN_SCR_FIELD(sxx, syy))
1968 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1971 element = TILE_GFX_ELEMENT(xx, yy);
1973 if (!IS_CRUMBLED_TILE(xx, yy, element))
1976 graphic = el_act2crm(element, ACTION_DEFAULT);
1978 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1980 MarkTileDirty(sxx, syy);
1985 void DrawLevelFieldCrumbled(int x, int y)
1989 if (!IN_LEV_FIELD(x, y))
1993 /* !!! CHECK THIS !!! */
1996 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1997 GFX_CRUMBLED(GfxElement[x][y]))
2000 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2001 GfxElement[x][y] != EL_UNDEFINED &&
2002 GFX_CRUMBLED(GfxElement[x][y]))
2004 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2011 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2013 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2016 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2019 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2022 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2023 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2024 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2025 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2026 int sx = SCREENX(x), sy = SCREENY(y);
2028 DrawGraphic(sx, sy, graphic1, frame1);
2029 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2032 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2034 int sx = SCREENX(x), sy = SCREENY(y);
2035 static int xy[4][2] =
2044 for (i = 0; i < 4; i++)
2046 int xx = x + xy[i][0];
2047 int yy = y + xy[i][1];
2048 int sxx = sx + xy[i][0];
2049 int syy = sy + xy[i][1];
2051 if (!IN_LEV_FIELD(xx, yy) ||
2052 !IN_SCR_FIELD(sxx, syy) ||
2053 !GFX_CRUMBLED(Feld[xx][yy]) ||
2057 DrawLevelField(xx, yy);
2061 static int getBorderElement(int x, int y)
2065 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2066 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2067 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2068 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2069 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2070 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2071 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2073 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2074 int steel_position = (x == -1 && y == -1 ? 0 :
2075 x == lev_fieldx && y == -1 ? 1 :
2076 x == -1 && y == lev_fieldy ? 2 :
2077 x == lev_fieldx && y == lev_fieldy ? 3 :
2078 x == -1 || x == lev_fieldx ? 4 :
2079 y == -1 || y == lev_fieldy ? 5 : 6);
2081 return border[steel_position][steel_type];
2084 void DrawScreenElement(int x, int y, int element)
2086 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2087 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2090 void DrawLevelElement(int x, int y, int element)
2092 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2093 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2096 void DrawScreenField(int x, int y)
2098 int lx = LEVELX(x), ly = LEVELY(y);
2099 int element, content;
2101 if (!IN_LEV_FIELD(lx, ly))
2103 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2106 element = getBorderElement(lx, ly);
2108 DrawScreenElement(x, y, element);
2113 element = Feld[lx][ly];
2114 content = Store[lx][ly];
2116 if (IS_MOVING(lx, ly))
2118 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2119 boolean cut_mode = NO_CUTTING;
2121 if (element == EL_QUICKSAND_EMPTYING ||
2122 element == EL_QUICKSAND_FAST_EMPTYING ||
2123 element == EL_MAGIC_WALL_EMPTYING ||
2124 element == EL_BD_MAGIC_WALL_EMPTYING ||
2125 element == EL_DC_MAGIC_WALL_EMPTYING ||
2126 element == EL_AMOEBA_DROPPING)
2127 cut_mode = CUT_ABOVE;
2128 else if (element == EL_QUICKSAND_FILLING ||
2129 element == EL_QUICKSAND_FAST_FILLING ||
2130 element == EL_MAGIC_WALL_FILLING ||
2131 element == EL_BD_MAGIC_WALL_FILLING ||
2132 element == EL_DC_MAGIC_WALL_FILLING)
2133 cut_mode = CUT_BELOW;
2136 if (lx == 9 && ly == 1)
2137 printf("::: %s [%d] [%d, %d] [%d]\n",
2138 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2139 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2140 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2141 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2142 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2145 if (cut_mode == CUT_ABOVE)
2147 DrawScreenElement(x, y, element);
2149 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2152 DrawScreenElement(x, y, EL_EMPTY);
2155 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2156 else if (cut_mode == NO_CUTTING)
2157 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2160 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2163 if (cut_mode == CUT_BELOW &&
2164 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2165 DrawLevelElement(lx, ly + 1, element);
2169 if (content == EL_ACID)
2171 int dir = MovDir[lx][ly];
2172 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2173 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2175 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2178 else if (IS_BLOCKED(lx, ly))
2183 boolean cut_mode = NO_CUTTING;
2184 int element_old, content_old;
2186 Blocked2Moving(lx, ly, &oldx, &oldy);
2189 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2190 MovDir[oldx][oldy] == MV_RIGHT);
2192 element_old = Feld[oldx][oldy];
2193 content_old = Store[oldx][oldy];
2195 if (element_old == EL_QUICKSAND_EMPTYING ||
2196 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2197 element_old == EL_MAGIC_WALL_EMPTYING ||
2198 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2199 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2200 element_old == EL_AMOEBA_DROPPING)
2201 cut_mode = CUT_ABOVE;
2203 DrawScreenElement(x, y, EL_EMPTY);
2206 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2208 else if (cut_mode == NO_CUTTING)
2209 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2212 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2215 else if (IS_DRAWABLE(element))
2216 DrawScreenElement(x, y, element);
2218 DrawScreenElement(x, y, EL_EMPTY);
2221 void DrawLevelField(int x, int y)
2223 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2224 DrawScreenField(SCREENX(x), SCREENY(y));
2225 else if (IS_MOVING(x, y))
2229 Moving2Blocked(x, y, &newx, &newy);
2230 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2231 DrawScreenField(SCREENX(newx), SCREENY(newy));
2233 else if (IS_BLOCKED(x, y))
2237 Blocked2Moving(x, y, &oldx, &oldy);
2238 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2239 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2243 void DrawMiniElement(int x, int y, int element)
2247 graphic = el2edimg(element);
2248 DrawMiniGraphic(x, y, graphic);
2251 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2253 int x = sx + scroll_x, y = sy + scroll_y;
2255 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2256 DrawMiniElement(sx, sy, EL_EMPTY);
2257 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2258 DrawMiniElement(sx, sy, Feld[x][y]);
2260 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2263 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
2264 int x, int y, int xsize, int ysize, int font_nr)
2266 int font_width = getFontWidth(font_nr);
2267 int font_height = getFontHeight(font_nr);
2268 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2271 int dst_x = SX + startx + x * font_width;
2272 int dst_y = SY + starty + y * font_height;
2273 int width = graphic_info[graphic].width;
2274 int height = graphic_info[graphic].height;
2275 int inner_width = MAX(width - 2 * font_width, font_width);
2276 int inner_height = MAX(height - 2 * font_height, font_height);
2277 int inner_sx = (width >= 3 * font_width ? font_width : 0);
2278 int inner_sy = (height >= 3 * font_height ? font_height : 0);
2279 boolean draw_masked = graphic_info[graphic].draw_masked;
2281 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2283 if (src_bitmap == NULL || width < font_width || height < font_height)
2285 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
2289 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
2290 inner_sx + (x - 1) * font_width % inner_width);
2291 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
2292 inner_sy + (y - 1) * font_height % inner_height);
2296 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2297 dst_x - src_x, dst_y - src_y);
2298 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2302 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2306 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2308 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2309 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2310 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2311 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2312 boolean no_delay = (tape.warp_forward);
2313 unsigned long anim_delay = 0;
2314 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2315 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2316 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2317 int font_width = getFontWidth(font_nr);
2318 int font_height = getFontHeight(font_nr);
2319 int max_xsize = level.envelope[envelope_nr].xsize;
2320 int max_ysize = level.envelope[envelope_nr].ysize;
2321 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2322 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2323 int xend = max_xsize;
2324 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2325 int xstep = (xstart < xend ? 1 : 0);
2326 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2329 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2331 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2332 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2333 int sx = (SXSIZE - xsize * font_width) / 2;
2334 int sy = (SYSIZE - ysize * font_height) / 2;
2337 SetDrawtoField(DRAW_BUFFERED);
2339 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2341 SetDrawtoField(DRAW_BACKBUFFER);
2343 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2344 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2347 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2348 level.envelope[envelope_nr].text, font_nr, max_xsize,
2349 xsize - 2, ysize - 2, 0, mask_mode,
2350 level.envelope[envelope_nr].autowrap,
2351 level.envelope[envelope_nr].centered, FALSE);
2353 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2354 level.envelope[envelope_nr].text, font_nr, max_xsize,
2355 xsize - 2, ysize - 2, mask_mode);
2358 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2361 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2365 void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
2368 int envelope_nr = 0;
2370 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2371 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2372 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2373 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2374 boolean no_delay = (tape.warp_forward);
2375 unsigned long anim_delay = 0;
2376 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2377 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2379 int max_word_len = maxWordLengthInString(text);
2380 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2382 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2384 int font_width = getFontWidth(font_nr);
2385 int font_height = getFontHeight(font_nr);
2389 int max_xsize = DXSIZE / font_width;
2390 int max_ysize = DYSIZE / font_height;
2392 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2393 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
2397 int max_xsize = level.envelope[envelope_nr].xsize;
2398 int max_ysize = level.envelope[envelope_nr].ysize;
2400 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2401 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2402 int xend = max_xsize;
2403 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2404 int xstep = (xstart < xend ? 1 : 0);
2405 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2410 char *text_copy = getStringCopy(text);
2413 font_nr = FONT_TEXT_2;
2415 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
2417 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2418 font_nr = FONT_TEXT_1;
2421 int max_word_len = 0;
2423 char *text_copy = getStringCopy(text);
2425 font_nr = FONT_TEXT_2;
2427 for (text_ptr = text; *text_ptr; text_ptr++)
2429 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2431 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2433 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2434 font_nr = FONT_TEXT_1;
2443 for (text_ptr = text_copy; *text_ptr; text_ptr++)
2444 if (*text_ptr == ' ')
2449 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
2450 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
2452 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
2453 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
2456 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2458 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2459 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2460 int sx = (SXSIZE - xsize * font_width) / 2;
2461 int sy = (SYSIZE - ysize * font_height) / 2;
2465 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2467 SetDrawtoField(DRAW_BUFFERED);
2469 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2471 SetDrawtoField(DRAW_BACKBUFFER);
2474 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2475 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2480 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height + 8,
2481 text_copy, font_nr, max_xsize,
2482 xsize - 2, ysize - 2, 2, mask_mode,
2483 FALSE, TRUE, FALSE);
2485 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2486 level.envelope[envelope_nr].text, font_nr, max_xsize,
2487 xsize - 2, ysize - 2, 0, mask_mode,
2488 level.envelope[envelope_nr].autowrap,
2489 level.envelope[envelope_nr].centered, FALSE);
2493 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2494 level.envelope[envelope_nr].text, font_nr, max_xsize,
2495 xsize - 2, ysize - 2, mask_mode);
2498 /* copy request gadgets to door backbuffer */
2500 if ((ysize - 2) > 13)
2501 BlitBitmap(bitmap_db_door, drawto,
2502 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2503 DOOR_GFX_PAGEY1 + 13 * font_height,
2504 (xsize - 2) * font_width,
2505 (ysize - 2 - 13) * font_height,
2506 SX + sx + font_width,
2507 SY + sy + font_height * (1 + 13));
2509 if ((ysize - 2) > 13)
2510 BlitBitmap(bitmap_db_door, drawto,
2511 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2512 DOOR_GFX_PAGEY1 + 13 * font_height,
2513 (xsize - 2) * font_width,
2514 (ysize - 2 - 13) * font_height,
2515 SX + sx + font_width,
2516 SY + sy + font_height * (1 + 13));
2520 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2521 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2523 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2533 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2541 void ShowEnvelope(int envelope_nr)
2543 int element = EL_ENVELOPE_1 + envelope_nr;
2544 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2545 int sound_opening = element_info[element].sound[ACTION_OPENING];
2546 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2547 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2548 boolean no_delay = (tape.warp_forward);
2549 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2550 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2551 int anim_mode = graphic_info[graphic].anim_mode;
2552 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2553 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2555 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2557 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2559 if (anim_mode == ANIM_DEFAULT)
2560 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2562 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2565 Delay(wait_delay_value);
2567 WaitForEventToContinue();
2569 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2571 if (anim_mode != ANIM_NONE)
2572 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2574 if (anim_mode == ANIM_DEFAULT)
2575 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2577 game.envelope_active = FALSE;
2579 SetDrawtoField(DRAW_BUFFERED);
2581 redraw_mask |= REDRAW_FIELD;
2585 void ShowEnvelopeDoor(char *text, int action)
2588 int last_game_status = game_status; /* save current game status */
2589 // int last_draw_background_mask = gfx.draw_background_mask;
2590 int envelope_nr = 0;
2592 int element = EL_ENVELOPE_1 + envelope_nr;
2593 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2594 int sound_opening = element_info[element].sound[ACTION_OPENING];
2595 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2597 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2598 boolean no_delay = (tape.warp_forward);
2599 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2600 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2602 int anim_mode = graphic_info[graphic].anim_mode;
2603 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2604 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2607 if (game_status == GAME_MODE_PLAYING)
2609 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2610 BlitScreenToBitmap_EM(backbuffer);
2611 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2612 BlitScreenToBitmap_SP(backbuffer);
2615 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2619 SetDrawtoField(DRAW_BACKBUFFER);
2621 // SetDrawBackgroundMask(REDRAW_NONE);
2623 if (action == ACTION_OPENING)
2625 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2627 if (game_status != GAME_MODE_MAIN)
2631 /* force DOOR font inside door area */
2632 game_status = GAME_MODE_PSEUDO_DOOR;
2635 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2637 if (action == ACTION_OPENING)
2639 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2641 if (anim_mode == ANIM_DEFAULT)
2642 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING);
2644 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING);
2648 Delay(wait_delay_value);
2650 WaitForEventToContinue();
2655 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2657 if (anim_mode != ANIM_NONE)
2658 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING);
2660 if (anim_mode == ANIM_DEFAULT)
2661 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING);
2664 game.envelope_active = FALSE;
2667 // game_status = last_game_status; /* restore current game status */
2669 if (action == ACTION_CLOSING)
2671 if (game_status != GAME_MODE_MAIN)
2674 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2677 SetDrawtoField(DRAW_BUFFERED);
2680 // SetDrawBackgroundMask(last_draw_background_mask);
2683 redraw_mask = REDRAW_FIELD;
2684 // redraw_mask |= REDRAW_ALL;
2686 redraw_mask |= REDRAW_FIELD;
2690 if (game_status == GAME_MODE_MAIN)
2695 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
2696 game_status = last_game_status; /* restore current game status */
2698 if (game_status == GAME_MODE_PLAYING &&
2699 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2700 SetDrawtoField(DRAW_BUFFERED);
2706 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2710 int graphic = el2preimg(element);
2712 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2713 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2721 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2722 SetDrawBackgroundMask(REDRAW_FIELD);
2724 SetDrawBackgroundMask(REDRAW_NONE);
2729 for (x = BX1; x <= BX2; x++)
2730 for (y = BY1; y <= BY2; y++)
2731 DrawScreenField(x, y);
2733 redraw_mask |= REDRAW_FIELD;
2736 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2740 for (x = 0; x < size_x; x++)
2741 for (y = 0; y < size_y; y++)
2742 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2744 redraw_mask |= REDRAW_FIELD;
2747 static void DrawPreviewLevelExt(int from_x, int from_y)
2749 boolean show_level_border = (BorderElement != EL_EMPTY);
2750 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2751 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2752 int tile_size = preview.tile_size;
2753 int preview_width = preview.xsize * tile_size;
2754 int preview_height = preview.ysize * tile_size;
2755 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2756 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2757 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2758 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2761 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2763 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2764 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2766 for (x = 0; x < real_preview_xsize; x++)
2768 for (y = 0; y < real_preview_ysize; y++)
2770 int lx = from_x + x + (show_level_border ? -1 : 0);
2771 int ly = from_y + y + (show_level_border ? -1 : 0);
2772 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2773 getBorderElement(lx, ly));
2775 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2776 element, tile_size);
2780 redraw_mask |= REDRAW_MICROLEVEL;
2783 #define MICROLABEL_EMPTY 0
2784 #define MICROLABEL_LEVEL_NAME 1
2785 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2786 #define MICROLABEL_LEVEL_AUTHOR 3
2787 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2788 #define MICROLABEL_IMPORTED_FROM 5
2789 #define MICROLABEL_IMPORTED_BY_HEAD 6
2790 #define MICROLABEL_IMPORTED_BY 7
2792 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2794 int max_text_width = SXSIZE;
2795 int font_width = getFontWidth(font_nr);
2797 if (pos->align == ALIGN_CENTER)
2798 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2799 else if (pos->align == ALIGN_RIGHT)
2800 max_text_width = pos->x;
2802 max_text_width = SXSIZE - pos->x;
2804 return max_text_width / font_width;
2807 static void DrawPreviewLevelLabelExt(int mode)
2809 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2810 char label_text[MAX_OUTPUT_LINESIZE + 1];
2811 int max_len_label_text;
2813 int font_nr = pos->font;
2816 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2817 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2818 mode == MICROLABEL_IMPORTED_BY_HEAD)
2819 font_nr = pos->font_alt;
2821 int font_nr = FONT_TEXT_2;
2824 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2825 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2826 mode == MICROLABEL_IMPORTED_BY_HEAD)
2827 font_nr = FONT_TEXT_3;
2831 max_len_label_text = getMaxTextLength(pos, font_nr);
2833 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2837 if (pos->size != -1)
2838 max_len_label_text = pos->size;
2841 for (i = 0; i < max_len_label_text; i++)
2842 label_text[i] = ' ';
2843 label_text[max_len_label_text] = '\0';
2845 if (strlen(label_text) > 0)
2848 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2850 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2851 int lypos = MICROLABEL2_YPOS;
2853 DrawText(lxpos, lypos, label_text, font_nr);
2858 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2859 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2860 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2861 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2862 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2863 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2864 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2865 max_len_label_text);
2866 label_text[max_len_label_text] = '\0';
2868 if (strlen(label_text) > 0)
2871 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2873 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2874 int lypos = MICROLABEL2_YPOS;
2876 DrawText(lxpos, lypos, label_text, font_nr);
2880 redraw_mask |= REDRAW_MICROLEVEL;
2883 void DrawPreviewLevel(boolean restart)
2885 static unsigned long scroll_delay = 0;
2886 static unsigned long label_delay = 0;
2887 static int from_x, from_y, scroll_direction;
2888 static int label_state, label_counter;
2889 unsigned long scroll_delay_value = preview.step_delay;
2890 boolean show_level_border = (BorderElement != EL_EMPTY);
2891 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2892 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2893 int last_game_status = game_status; /* save current game status */
2896 /* force PREVIEW font on preview level */
2897 game_status = GAME_MODE_PSEUDO_PREVIEW;
2905 if (preview.anim_mode == ANIM_CENTERED)
2907 if (level_xsize > preview.xsize)
2908 from_x = (level_xsize - preview.xsize) / 2;
2909 if (level_ysize > preview.ysize)
2910 from_y = (level_ysize - preview.ysize) / 2;
2913 from_x += preview.xoffset;
2914 from_y += preview.yoffset;
2916 scroll_direction = MV_RIGHT;
2920 DrawPreviewLevelExt(from_x, from_y);
2921 DrawPreviewLevelLabelExt(label_state);
2923 /* initialize delay counters */
2924 DelayReached(&scroll_delay, 0);
2925 DelayReached(&label_delay, 0);
2927 if (leveldir_current->name)
2929 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2930 char label_text[MAX_OUTPUT_LINESIZE + 1];
2932 int font_nr = pos->font;
2934 int font_nr = FONT_TEXT_1;
2937 int max_len_label_text = getMaxTextLength(pos, font_nr);
2939 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2947 if (pos->size != -1)
2948 max_len_label_text = pos->size;
2951 strncpy(label_text, leveldir_current->name, max_len_label_text);
2952 label_text[max_len_label_text] = '\0';
2955 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2957 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2958 lypos = SY + MICROLABEL1_YPOS;
2960 DrawText(lxpos, lypos, label_text, font_nr);
2964 game_status = last_game_status; /* restore current game status */
2969 /* scroll preview level, if needed */
2970 if (preview.anim_mode != ANIM_NONE &&
2971 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2972 DelayReached(&scroll_delay, scroll_delay_value))
2974 switch (scroll_direction)
2979 from_x -= preview.step_offset;
2980 from_x = (from_x < 0 ? 0 : from_x);
2983 scroll_direction = MV_UP;
2987 if (from_x < level_xsize - preview.xsize)
2989 from_x += preview.step_offset;
2990 from_x = (from_x > level_xsize - preview.xsize ?
2991 level_xsize - preview.xsize : from_x);
2994 scroll_direction = MV_DOWN;
3000 from_y -= preview.step_offset;
3001 from_y = (from_y < 0 ? 0 : from_y);
3004 scroll_direction = MV_RIGHT;
3008 if (from_y < level_ysize - preview.ysize)
3010 from_y += preview.step_offset;
3011 from_y = (from_y > level_ysize - preview.ysize ?
3012 level_ysize - preview.ysize : from_y);
3015 scroll_direction = MV_LEFT;
3022 DrawPreviewLevelExt(from_x, from_y);
3025 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3026 /* redraw micro level label, if needed */
3027 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3028 !strEqual(level.author, ANONYMOUS_NAME) &&
3029 !strEqual(level.author, leveldir_current->name) &&
3030 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3032 int max_label_counter = 23;
3034 if (leveldir_current->imported_from != NULL &&
3035 strlen(leveldir_current->imported_from) > 0)
3036 max_label_counter += 14;
3037 if (leveldir_current->imported_by != NULL &&
3038 strlen(leveldir_current->imported_by) > 0)
3039 max_label_counter += 14;
3041 label_counter = (label_counter + 1) % max_label_counter;
3042 label_state = (label_counter >= 0 && label_counter <= 7 ?
3043 MICROLABEL_LEVEL_NAME :
3044 label_counter >= 9 && label_counter <= 12 ?
3045 MICROLABEL_LEVEL_AUTHOR_HEAD :
3046 label_counter >= 14 && label_counter <= 21 ?
3047 MICROLABEL_LEVEL_AUTHOR :
3048 label_counter >= 23 && label_counter <= 26 ?
3049 MICROLABEL_IMPORTED_FROM_HEAD :
3050 label_counter >= 28 && label_counter <= 35 ?
3051 MICROLABEL_IMPORTED_FROM :
3052 label_counter >= 37 && label_counter <= 40 ?
3053 MICROLABEL_IMPORTED_BY_HEAD :
3054 label_counter >= 42 && label_counter <= 49 ?
3055 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3057 if (leveldir_current->imported_from == NULL &&
3058 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3059 label_state == MICROLABEL_IMPORTED_FROM))
3060 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3061 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3063 DrawPreviewLevelLabelExt(label_state);
3066 game_status = last_game_status; /* restore current game status */
3069 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3070 int graphic, int sync_frame, int mask_mode)
3072 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3074 if (mask_mode == USE_MASKING)
3075 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3077 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3080 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3081 int graphic, int sync_frame,
3084 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3086 if (mask_mode == USE_MASKING)
3087 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3089 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3092 inline void DrawGraphicAnimation(int x, int y, int graphic)
3094 int lx = LEVELX(x), ly = LEVELY(y);
3096 if (!IN_SCR_FIELD(x, y))
3100 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3101 graphic, GfxFrame[lx][ly], NO_MASKING);
3103 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3104 graphic, GfxFrame[lx][ly], NO_MASKING);
3106 MarkTileDirty(x, y);
3109 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3111 int lx = LEVELX(x), ly = LEVELY(y);
3113 if (!IN_SCR_FIELD(x, y))
3116 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3117 graphic, GfxFrame[lx][ly], NO_MASKING);
3118 MarkTileDirty(x, y);
3121 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3123 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3126 void DrawLevelElementAnimation(int x, int y, int element)
3128 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3130 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3133 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3135 int sx = SCREENX(x), sy = SCREENY(y);
3137 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3140 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3143 DrawGraphicAnimation(sx, sy, graphic);
3146 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3147 DrawLevelFieldCrumbled(x, y);
3149 if (GFX_CRUMBLED(Feld[x][y]))
3150 DrawLevelFieldCrumbled(x, y);
3154 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3156 int sx = SCREENX(x), sy = SCREENY(y);
3159 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3162 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3164 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3167 DrawGraphicAnimation(sx, sy, graphic);
3169 if (GFX_CRUMBLED(element))
3170 DrawLevelFieldCrumbled(x, y);
3173 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3175 if (player->use_murphy)
3177 /* this works only because currently only one player can be "murphy" ... */
3178 static int last_horizontal_dir = MV_LEFT;
3179 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3181 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3182 last_horizontal_dir = move_dir;
3184 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3186 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3188 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3194 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3197 static boolean equalGraphics(int graphic1, int graphic2)
3199 struct GraphicInfo *g1 = &graphic_info[graphic1];
3200 struct GraphicInfo *g2 = &graphic_info[graphic2];
3202 return (g1->bitmap == g2->bitmap &&
3203 g1->src_x == g2->src_x &&
3204 g1->src_y == g2->src_y &&
3205 g1->anim_frames == g2->anim_frames &&
3206 g1->anim_delay == g2->anim_delay &&
3207 g1->anim_mode == g2->anim_mode);
3210 void DrawAllPlayers()
3214 for (i = 0; i < MAX_PLAYERS; i++)
3215 if (stored_player[i].active)
3216 DrawPlayer(&stored_player[i]);
3219 void DrawPlayerField(int x, int y)
3221 if (!IS_PLAYER(x, y))
3224 DrawPlayer(PLAYERINFO(x, y));
3227 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3229 void DrawPlayer(struct PlayerInfo *player)
3231 int jx = player->jx;
3232 int jy = player->jy;
3233 int move_dir = player->MovDir;
3234 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3235 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3236 int last_jx = (player->is_moving ? jx - dx : jx);
3237 int last_jy = (player->is_moving ? jy - dy : jy);
3238 int next_jx = jx + dx;
3239 int next_jy = jy + dy;
3240 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3241 boolean player_is_opaque = FALSE;
3242 int sx = SCREENX(jx), sy = SCREENY(jy);
3243 int sxx = 0, syy = 0;
3244 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3246 int action = ACTION_DEFAULT;
3247 int last_player_graphic = getPlayerGraphic(player, move_dir);
3248 int last_player_frame = player->Frame;
3251 /* GfxElement[][] is set to the element the player is digging or collecting;
3252 remove also for off-screen player if the player is not moving anymore */
3253 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3254 GfxElement[jx][jy] = EL_UNDEFINED;
3256 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3260 if (!IN_LEV_FIELD(jx, jy))
3262 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3263 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3264 printf("DrawPlayerField(): This should never happen!\n");
3269 if (element == EL_EXPLOSION)
3272 action = (player->is_pushing ? ACTION_PUSHING :
3273 player->is_digging ? ACTION_DIGGING :
3274 player->is_collecting ? ACTION_COLLECTING :
3275 player->is_moving ? ACTION_MOVING :
3276 player->is_snapping ? ACTION_SNAPPING :
3277 player->is_dropping ? ACTION_DROPPING :
3278 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3280 if (player->is_waiting)
3281 move_dir = player->dir_waiting;
3283 InitPlayerGfxAnimation(player, action, move_dir);
3285 /* ----------------------------------------------------------------------- */
3286 /* draw things in the field the player is leaving, if needed */
3287 /* ----------------------------------------------------------------------- */
3289 if (player->is_moving)
3291 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3293 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3295 if (last_element == EL_DYNAMITE_ACTIVE ||
3296 last_element == EL_EM_DYNAMITE_ACTIVE ||
3297 last_element == EL_SP_DISK_RED_ACTIVE)
3298 DrawDynamite(last_jx, last_jy);
3300 DrawLevelFieldThruMask(last_jx, last_jy);
3302 else if (last_element == EL_DYNAMITE_ACTIVE ||
3303 last_element == EL_EM_DYNAMITE_ACTIVE ||
3304 last_element == EL_SP_DISK_RED_ACTIVE)
3305 DrawDynamite(last_jx, last_jy);
3307 /* !!! this is not enough to prevent flickering of players which are
3308 moving next to each others without a free tile between them -- this
3309 can only be solved by drawing all players layer by layer (first the
3310 background, then the foreground etc.) !!! => TODO */
3311 else if (!IS_PLAYER(last_jx, last_jy))
3312 DrawLevelField(last_jx, last_jy);
3315 DrawLevelField(last_jx, last_jy);
3318 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3319 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3322 if (!IN_SCR_FIELD(sx, sy))
3325 /* ----------------------------------------------------------------------- */
3326 /* draw things behind the player, if needed */
3327 /* ----------------------------------------------------------------------- */
3330 DrawLevelElement(jx, jy, Back[jx][jy]);
3331 else if (IS_ACTIVE_BOMB(element))
3332 DrawLevelElement(jx, jy, EL_EMPTY);
3335 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3337 int old_element = GfxElement[jx][jy];
3338 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3339 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3341 if (GFX_CRUMBLED(old_element))
3342 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3344 DrawGraphic(sx, sy, old_graphic, frame);
3346 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3347 player_is_opaque = TRUE;
3351 GfxElement[jx][jy] = EL_UNDEFINED;
3353 /* make sure that pushed elements are drawn with correct frame rate */
3355 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3357 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3358 GfxFrame[jx][jy] = player->StepFrame;
3360 if (player->is_pushing && player->is_moving)
3361 GfxFrame[jx][jy] = player->StepFrame;
3364 DrawLevelField(jx, jy);
3368 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3369 /* ----------------------------------------------------------------------- */
3370 /* draw player himself */
3371 /* ----------------------------------------------------------------------- */
3373 graphic = getPlayerGraphic(player, move_dir);
3375 /* in the case of changed player action or direction, prevent the current
3376 animation frame from being restarted for identical animations */
3377 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3378 player->Frame = last_player_frame;
3380 frame = getGraphicAnimationFrame(graphic, player->Frame);
3384 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3385 sxx = player->GfxPos;
3387 syy = player->GfxPos;
3390 if (!setup.soft_scrolling && ScreenMovPos)
3393 if (player_is_opaque)
3394 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3396 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3398 if (SHIELD_ON(player))
3400 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3401 IMG_SHIELD_NORMAL_ACTIVE);
3402 int frame = getGraphicAnimationFrame(graphic, -1);
3404 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3408 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3411 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3412 sxx = player->GfxPos;
3414 syy = player->GfxPos;
3418 /* ----------------------------------------------------------------------- */
3419 /* draw things the player is pushing, if needed */
3420 /* ----------------------------------------------------------------------- */
3423 printf("::: %d, %d [%d, %d] [%d]\n",
3424 player->is_pushing, player_is_moving, player->GfxAction,
3425 player->is_moving, player_is_moving);
3429 if (player->is_pushing && player->is_moving)
3431 int px = SCREENX(jx), py = SCREENY(jy);
3432 int pxx = (TILEX - ABS(sxx)) * dx;
3433 int pyy = (TILEY - ABS(syy)) * dy;
3434 int gfx_frame = GfxFrame[jx][jy];
3440 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3442 element = Feld[next_jx][next_jy];
3443 gfx_frame = GfxFrame[next_jx][next_jy];
3446 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3449 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3450 frame = getGraphicAnimationFrame(graphic, sync_frame);
3452 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3455 /* draw background element under pushed element (like the Sokoban field) */
3457 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3459 /* this allows transparent pushing animation over non-black background */
3462 DrawLevelElement(jx, jy, Back[jx][jy]);
3464 DrawLevelElement(jx, jy, EL_EMPTY);
3466 if (Back[next_jx][next_jy])
3467 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3469 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3471 else if (Back[next_jx][next_jy])
3472 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3474 if (Back[next_jx][next_jy])
3475 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3479 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3480 jx, px, player->GfxPos, player->StepFrame,
3485 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3489 /* do not draw (EM style) pushing animation when pushing is finished */
3490 /* (two-tile animations usually do not contain start and end frame) */
3491 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3492 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3494 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3496 /* masked drawing is needed for EMC style (double) movement graphics */
3497 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3498 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3503 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3504 /* ----------------------------------------------------------------------- */
3505 /* draw player himself */
3506 /* ----------------------------------------------------------------------- */
3508 graphic = getPlayerGraphic(player, move_dir);
3510 /* in the case of changed player action or direction, prevent the current
3511 animation frame from being restarted for identical animations */
3512 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3513 player->Frame = last_player_frame;
3515 frame = getGraphicAnimationFrame(graphic, player->Frame);
3519 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3520 sxx = player->GfxPos;
3522 syy = player->GfxPos;
3525 if (!setup.soft_scrolling && ScreenMovPos)
3528 if (player_is_opaque)
3529 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3531 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3533 if (SHIELD_ON(player))
3535 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3536 IMG_SHIELD_NORMAL_ACTIVE);
3537 int frame = getGraphicAnimationFrame(graphic, -1);
3539 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3543 /* ----------------------------------------------------------------------- */
3544 /* draw things in front of player (active dynamite or dynabombs) */
3545 /* ----------------------------------------------------------------------- */
3547 if (IS_ACTIVE_BOMB(element))
3549 graphic = el2img(element);
3550 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3552 if (game.emulation == EMU_SUPAPLEX)
3553 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3555 DrawGraphicThruMask(sx, sy, graphic, frame);
3558 if (player_is_moving && last_element == EL_EXPLOSION)
3560 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3561 GfxElement[last_jx][last_jy] : EL_EMPTY);
3562 int graphic = el_act2img(element, ACTION_EXPLODING);
3563 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3564 int phase = ExplodePhase[last_jx][last_jy] - 1;
3565 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3568 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3571 /* ----------------------------------------------------------------------- */
3572 /* draw elements the player is just walking/passing through/under */
3573 /* ----------------------------------------------------------------------- */
3575 if (player_is_moving)
3577 /* handle the field the player is leaving ... */
3578 if (IS_ACCESSIBLE_INSIDE(last_element))
3579 DrawLevelField(last_jx, last_jy);
3580 else if (IS_ACCESSIBLE_UNDER(last_element))
3581 DrawLevelFieldThruMask(last_jx, last_jy);
3584 /* do not redraw accessible elements if the player is just pushing them */
3585 if (!player_is_moving || !player->is_pushing)
3587 /* ... and the field the player is entering */
3588 if (IS_ACCESSIBLE_INSIDE(element))
3589 DrawLevelField(jx, jy);
3590 else if (IS_ACCESSIBLE_UNDER(element))
3591 DrawLevelFieldThruMask(jx, jy);
3594 MarkTileDirty(sx, sy);
3597 /* ------------------------------------------------------------------------- */
3599 void WaitForEventToContinue()
3601 boolean still_wait = TRUE;
3603 /* simulate releasing mouse button over last gadget, if still pressed */
3605 HandleGadgets(-1, -1, 0);
3607 button_status = MB_RELEASED;
3623 case EVENT_BUTTONPRESS:
3624 case EVENT_KEYPRESS:
3628 case EVENT_KEYRELEASE:
3629 ClearPlayerAction();
3633 HandleOtherEvents(&event);
3637 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3644 /* don't eat all CPU time */
3649 #define MAX_REQUEST_LINES 13
3650 #define MAX_REQUEST_LINE_FONT1_LEN 7
3651 #define MAX_REQUEST_LINE_FONT2_LEN 10
3653 boolean Request(char *text, unsigned int req_state)
3655 int mx, my, ty, result = -1;
3656 unsigned int old_door_state;
3657 int last_game_status = game_status; /* save current game status */
3658 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3659 int font_nr = FONT_TEXT_2;
3661 int max_word_len = 0;
3666 global.use_envelope_request = TRUE * 1;
3669 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3671 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3672 font_nr = FONT_TEXT_1;
3675 for (text_ptr = text; *text_ptr; text_ptr++)
3677 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3679 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3681 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3683 font_nr = FONT_TEXT_1;
3685 font_nr = FONT_LEVEL_NUMBER;
3693 if (game_status == GAME_MODE_PLAYING)
3695 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3696 BlitScreenToBitmap_EM(backbuffer);
3697 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3698 BlitScreenToBitmap_SP(backbuffer);
3701 /* disable deactivated drawing when quick-loading level tape recording */
3702 if (tape.playing && tape.deactivate_display)
3703 TapeDeactivateDisplayOff(TRUE);
3705 SetMouseCursor(CURSOR_DEFAULT);
3707 #if defined(NETWORK_AVALIABLE)
3708 /* pause network game while waiting for request to answer */
3709 if (options.network &&
3710 game_status == GAME_MODE_PLAYING &&
3711 req_state & REQUEST_WAIT_FOR_INPUT)
3712 SendToServer_PausePlaying();
3715 old_door_state = GetDoorState();
3717 /* simulate releasing mouse button over last gadget, if still pressed */
3719 HandleGadgets(-1, -1, 0);
3723 /* draw released gadget before proceeding */
3727 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
3729 if (old_door_state & DOOR_OPEN_1)
3733 if (!global.use_envelope_request)
3734 CloseDoor(DOOR_CLOSE_1);
3736 CloseDoor(DOOR_CLOSE_1);
3739 /* save old door content */
3740 BlitBitmap(bitmap_db_door, bitmap_db_door,
3741 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3742 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3746 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3749 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3751 /* clear door drawing field */
3752 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3754 /* force DOOR font inside door area */
3755 game_status = GAME_MODE_PSEUDO_DOOR;
3757 /* write text for request */
3758 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3760 char text_line[max_request_line_len + 1];
3766 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3768 tc = *(text_ptr + tx);
3769 if (!tc || tc == ' ')
3780 strncpy(text_line, text_ptr, tl);
3783 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3784 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3785 text_line, font_nr);
3787 text_ptr += tl + (tc == ' ' ? 1 : 0);
3790 game_status = last_game_status; /* restore current game status */
3793 if (global.use_envelope_request)
3797 CreateToolButtons();
3801 if (req_state & REQ_ASK)
3803 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3804 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3806 else if (req_state & REQ_CONFIRM)
3808 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3810 else if (req_state & REQ_PLAYER)
3812 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3813 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3814 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3815 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3818 /* copy request gadgets to door backbuffer */
3819 BlitBitmap(drawto, bitmap_db_door,
3820 DX, DY, DXSIZE, DYSIZE,
3821 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3824 if (global.use_envelope_request)
3826 ShowEnvelopeDoor(text, ACTION_OPENING);
3828 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3830 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
3831 i == TOOL_CTRL_ID_NO)) ||
3832 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
3833 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
3834 i == TOOL_CTRL_ID_PLAYER_2 &&
3835 i == TOOL_CTRL_ID_PLAYER_3 &&
3836 i == TOOL_CTRL_ID_PLAYER_4)))
3838 int x = tool_gadget[i]->x + dDX;
3839 int y = tool_gadget[i]->y + dDY;
3841 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
3848 if (!global.use_envelope_request)
3849 OpenDoor(DOOR_OPEN_1);
3851 OpenDoor(DOOR_OPEN_1);
3854 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3856 if (game_status == GAME_MODE_PLAYING)
3858 SetPanelBackground();
3859 SetDrawBackgroundMask(REDRAW_DOOR_1);
3863 SetDrawBackgroundMask(REDRAW_FIELD);
3870 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
3873 if (game_status != GAME_MODE_MAIN)
3877 button_status = MB_RELEASED;
3879 request_gadget_id = -1;
3881 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3893 case EVENT_BUTTONPRESS:
3894 case EVENT_BUTTONRELEASE:
3895 case EVENT_MOTIONNOTIFY:
3897 if (event.type == EVENT_MOTIONNOTIFY)
3899 if (!PointerInWindow(window))
3900 continue; /* window and pointer are on different screens */
3905 motion_status = TRUE;
3906 mx = ((MotionEvent *) &event)->x;
3907 my = ((MotionEvent *) &event)->y;
3911 motion_status = FALSE;
3912 mx = ((ButtonEvent *) &event)->x;
3913 my = ((ButtonEvent *) &event)->y;
3914 if (event.type == EVENT_BUTTONPRESS)
3915 button_status = ((ButtonEvent *) &event)->button;
3917 button_status = MB_RELEASED;
3920 /* this sets 'request_gadget_id' */
3921 HandleGadgets(mx, my, button_status);
3923 switch (request_gadget_id)
3925 case TOOL_CTRL_ID_YES:
3928 case TOOL_CTRL_ID_NO:
3931 case TOOL_CTRL_ID_CONFIRM:
3932 result = TRUE | FALSE;
3935 case TOOL_CTRL_ID_PLAYER_1:
3938 case TOOL_CTRL_ID_PLAYER_2:
3941 case TOOL_CTRL_ID_PLAYER_3:
3944 case TOOL_CTRL_ID_PLAYER_4:
3955 case EVENT_KEYPRESS:
3956 switch (GetEventKey((KeyEvent *)&event, TRUE))
3959 if (req_state & REQ_CONFIRM)
3975 if (req_state & REQ_PLAYER)
3979 case EVENT_KEYRELEASE:
3980 ClearPlayerAction();
3984 HandleOtherEvents(&event);
3988 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3990 int joy = AnyJoystick();
3992 if (joy & JOY_BUTTON_1)
3994 else if (joy & JOY_BUTTON_2)
4000 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4002 HandleGameActions();
4008 if (!PendingEvent()) /* delay only if no pending events */
4013 game_status = GAME_MODE_PSEUDO_DOOR;
4019 game_status = last_game_status; /* restore current game status */
4027 if (!PendingEvent()) /* delay only if no pending events */
4030 /* don't eat all CPU time */
4037 if (game_status != GAME_MODE_MAIN)
4043 if (global.use_envelope_request)
4044 ShowEnvelopeDoor(text, ACTION_CLOSING);
4048 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
4050 if (!(req_state & REQ_STAY_OPEN))
4053 CloseDoor(DOOR_CLOSE_1);
4055 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4056 (req_state & REQ_REOPEN))
4057 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4062 if (game_status == GAME_MODE_PLAYING)
4064 SetPanelBackground();
4065 SetDrawBackgroundMask(REDRAW_DOOR_1);
4069 SetDrawBackgroundMask(REDRAW_FIELD);
4072 #if defined(NETWORK_AVALIABLE)
4073 /* continue network game after request */
4074 if (options.network &&
4075 game_status == GAME_MODE_PLAYING &&
4076 req_state & REQUEST_WAIT_FOR_INPUT)
4077 SendToServer_ContinuePlaying();
4080 /* restore deactivated drawing when quick-loading level tape recording */
4081 if (tape.playing && tape.deactivate_display)
4082 TapeDeactivateDisplayOn();
4087 unsigned int OpenDoor(unsigned int door_state)
4089 if (door_state & DOOR_COPY_BACK)
4091 if (door_state & DOOR_OPEN_1)
4092 BlitBitmap(bitmap_db_door, bitmap_db_door,
4093 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4094 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4096 if (door_state & DOOR_OPEN_2)
4097 BlitBitmap(bitmap_db_door, bitmap_db_door,
4098 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
4099 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4101 door_state &= ~DOOR_COPY_BACK;
4104 return MoveDoor(door_state);
4107 unsigned int CloseDoor(unsigned int door_state)
4109 unsigned int old_door_state = GetDoorState();
4111 if (!(door_state & DOOR_NO_COPY_BACK))
4113 if (old_door_state & DOOR_OPEN_1)
4114 BlitBitmap(backbuffer, bitmap_db_door,
4115 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4117 if (old_door_state & DOOR_OPEN_2)
4118 BlitBitmap(backbuffer, bitmap_db_door,
4119 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4121 door_state &= ~DOOR_NO_COPY_BACK;
4124 return MoveDoor(door_state);
4127 unsigned int GetDoorState()
4129 return MoveDoor(DOOR_GET_STATE);
4132 unsigned int SetDoorState(unsigned int door_state)
4134 return MoveDoor(door_state | DOOR_SET_STATE);
4137 unsigned int MoveDoor(unsigned int door_state)
4139 static int door1 = DOOR_OPEN_1;
4140 static int door2 = DOOR_CLOSE_2;
4141 unsigned long door_delay = 0;
4142 unsigned long door_delay_value;
4145 if (door_1.width < 0 || door_1.width > DXSIZE)
4146 door_1.width = DXSIZE;
4147 if (door_1.height < 0 || door_1.height > DYSIZE)
4148 door_1.height = DYSIZE;
4149 if (door_2.width < 0 || door_2.width > VXSIZE)
4150 door_2.width = VXSIZE;
4151 if (door_2.height < 0 || door_2.height > VYSIZE)
4152 door_2.height = VYSIZE;
4154 if (door_state == DOOR_GET_STATE)
4155 return (door1 | door2);
4157 if (door_state & DOOR_SET_STATE)
4159 if (door_state & DOOR_ACTION_1)
4160 door1 = door_state & DOOR_ACTION_1;
4161 if (door_state & DOOR_ACTION_2)
4162 door2 = door_state & DOOR_ACTION_2;
4164 return (door1 | door2);
4167 if (!(door_state & DOOR_FORCE_REDRAW))
4169 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4170 door_state &= ~DOOR_OPEN_1;
4171 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4172 door_state &= ~DOOR_CLOSE_1;
4173 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4174 door_state &= ~DOOR_OPEN_2;
4175 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4176 door_state &= ~DOOR_CLOSE_2;
4179 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
4182 if (setup.quick_doors)
4184 stepsize = 20; /* must be chosen to always draw last frame */
4185 door_delay_value = 0;
4188 if (global.autoplay_leveldir)
4190 door_state |= DOOR_NO_DELAY;
4191 door_state &= ~DOOR_CLOSE_ALL;
4195 if (game_status == GAME_MODE_EDITOR)
4196 door_state |= DOOR_NO_DELAY;
4199 if (door_state & DOOR_ACTION)
4201 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
4202 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
4203 boolean door_1_done = (!handle_door_1);
4204 boolean door_2_done = (!handle_door_2);
4205 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
4206 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
4207 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
4208 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
4209 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
4210 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
4211 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
4212 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
4213 int door_skip = max_door_size - door_size;
4214 int end = door_size;
4215 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
4218 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
4220 /* opening door sound has priority over simultaneously closing door */
4221 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4222 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4223 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4224 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4227 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
4230 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4231 GC gc = bitmap->stored_clip_gc;
4233 if (door_state & DOOR_ACTION_1)
4235 int a = MIN(x * door_1.step_offset, end);
4236 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
4237 int i = p + door_skip;
4239 if (door_1.anim_mode & ANIM_STATIC_PANEL)
4241 BlitBitmap(bitmap_db_door, drawto,
4242 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
4243 DXSIZE, DYSIZE, DX, DY);
4247 BlitBitmap(bitmap_db_door, drawto,
4248 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
4249 DXSIZE, DYSIZE - p / 2, DX, DY);
4251 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
4254 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
4256 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4257 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
4258 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
4259 int dst2_x = DX, dst2_y = DY;
4260 int width = i, height = DYSIZE;
4262 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4263 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4266 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4267 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4270 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
4272 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4273 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
4274 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
4275 int dst2_x = DX, dst2_y = DY;
4276 int width = DXSIZE, height = i;
4278 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4279 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4282 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4283 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4286 else if (x <= DXSIZE) /* ANIM_DEFAULT */
4288 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
4290 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4291 BlitBitmapMasked(bitmap, drawto,
4292 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
4293 DX + DXSIZE - i, DY + j);
4294 BlitBitmapMasked(bitmap, drawto,
4295 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4296 DX + DXSIZE - i, DY + 140 + j);
4297 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4298 DY - (DOOR_GFX_PAGEY1 + j));
4299 BlitBitmapMasked(bitmap, drawto,
4300 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4302 BlitBitmapMasked(bitmap, drawto,
4303 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4306 BlitBitmapMasked(bitmap, drawto,
4307 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4309 BlitBitmapMasked(bitmap, drawto,
4310 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4312 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4313 BlitBitmapMasked(bitmap, drawto,
4314 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4315 DX + DXSIZE - i, DY + 77 + j);
4316 BlitBitmapMasked(bitmap, drawto,
4317 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4318 DX + DXSIZE - i, DY + 203 + j);
4321 redraw_mask |= REDRAW_DOOR_1;
4322 door_1_done = (a == end);
4325 if (door_state & DOOR_ACTION_2)
4327 int a = MIN(x * door_2.step_offset, door_size);
4328 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4329 int i = p + door_skip;
4331 if (door_2.anim_mode & ANIM_STATIC_PANEL)
4333 BlitBitmap(bitmap_db_door, drawto,
4334 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4335 VXSIZE, VYSIZE, VX, VY);
4337 else if (x <= VYSIZE)
4339 BlitBitmap(bitmap_db_door, drawto,
4340 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4341 VXSIZE, VYSIZE - p / 2, VX, VY);
4343 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4346 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4348 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4349 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4350 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
4351 int dst2_x = VX, dst2_y = VY;
4352 int width = i, height = VYSIZE;
4354 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4355 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4358 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4359 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4362 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4364 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4365 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
4366 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4367 int dst2_x = VX, dst2_y = VY;
4368 int width = VXSIZE, height = i;
4370 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4371 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4374 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4375 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4378 else if (x <= VXSIZE) /* ANIM_DEFAULT */
4380 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4382 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4383 BlitBitmapMasked(bitmap, drawto,
4384 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4385 VX + VXSIZE - i, VY + j);
4386 SetClipOrigin(bitmap, gc,
4387 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4388 BlitBitmapMasked(bitmap, drawto,
4389 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4392 BlitBitmapMasked(bitmap, drawto,
4393 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4394 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4395 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4396 BlitBitmapMasked(bitmap, drawto,
4397 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4399 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4402 redraw_mask |= REDRAW_DOOR_2;
4403 door_2_done = (a == VXSIZE);
4406 if (!(door_state & DOOR_NO_DELAY))
4410 if (game_status == GAME_MODE_MAIN)
4413 WaitUntilDelayReached(&door_delay, door_delay_value);
4418 if (door_state & DOOR_ACTION_1)
4419 door1 = door_state & DOOR_ACTION_1;
4420 if (door_state & DOOR_ACTION_2)
4421 door2 = door_state & DOOR_ACTION_2;
4423 return (door1 | door2);
4426 void DrawSpecialEditorDoor()
4428 /* draw bigger toolbox window */
4429 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4430 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4432 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4433 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4436 redraw_mask |= REDRAW_ALL;
4439 void UndrawSpecialEditorDoor()
4441 /* draw normal tape recorder window */
4442 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4443 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4446 redraw_mask |= REDRAW_ALL;
4450 /* ---------- new tool button stuff ---------------------------------------- */
4452 /* graphic position values for tool buttons */
4453 #define TOOL_BUTTON_YES_XPOS 2
4454 #define TOOL_BUTTON_YES_YPOS 250
4455 #define TOOL_BUTTON_YES_GFX_YPOS 0
4456 #define TOOL_BUTTON_YES_XSIZE 46
4457 #define TOOL_BUTTON_YES_YSIZE 28
4458 #define TOOL_BUTTON_NO_XPOS 52
4459 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
4460 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
4461 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
4462 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
4463 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
4464 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
4465 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
4466 #define TOOL_BUTTON_CONFIRM_XSIZE 96
4467 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
4468 #define TOOL_BUTTON_PLAYER_XSIZE 30
4469 #define TOOL_BUTTON_PLAYER_YSIZE 30
4470 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
4471 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
4472 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4473 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4474 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4475 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4476 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4477 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4478 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4479 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4480 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4481 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4482 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4483 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4484 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4485 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4486 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4487 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4488 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4489 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4498 } toolbutton_info[NUM_TOOL_BUTTONS] =
4501 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
4502 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
4503 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
4508 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
4509 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
4510 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
4515 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
4516 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
4517 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
4518 TOOL_CTRL_ID_CONFIRM,
4522 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4523 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
4524 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4525 TOOL_CTRL_ID_PLAYER_1,
4529 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4530 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
4531 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4532 TOOL_CTRL_ID_PLAYER_2,
4536 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4537 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
4538 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4539 TOOL_CTRL_ID_PLAYER_3,
4543 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4544 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
4545 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4546 TOOL_CTRL_ID_PLAYER_4,
4551 void CreateToolButtons()
4555 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4557 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4558 Bitmap *deco_bitmap = None;
4559 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4560 struct GadgetInfo *gi;
4561 unsigned long event_mask;
4562 int gd_xoffset, gd_yoffset;
4563 int gd_x1, gd_x2, gd_y;
4566 event_mask = GD_EVENT_RELEASED;
4568 gd_xoffset = toolbutton_info[i].xpos;
4569 gd_yoffset = toolbutton_info[i].ypos;
4570 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4571 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4572 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4574 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4576 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4578 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4579 &deco_bitmap, &deco_x, &deco_y);
4580 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4581 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4584 gi = CreateGadget(GDI_CUSTOM_ID, id,
4585 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4586 GDI_X, DX + toolbutton_info[i].x,
4587 GDI_Y, DY + toolbutton_info[i].y,
4588 GDI_WIDTH, toolbutton_info[i].width,
4589 GDI_HEIGHT, toolbutton_info[i].height,
4590 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4591 GDI_STATE, GD_BUTTON_UNPRESSED,
4592 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4593 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4594 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4595 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4596 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4597 GDI_DECORATION_SHIFTING, 1, 1,
4598 GDI_DIRECT_DRAW, FALSE,
4599 GDI_EVENT_MASK, event_mask,
4600 GDI_CALLBACK_ACTION, HandleToolButtons,
4604 Error(ERR_EXIT, "cannot create gadget");
4606 tool_gadget[id] = gi;
4610 void FreeToolButtons()
4614 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4615 FreeGadget(tool_gadget[i]);
4618 static void UnmapToolButtons()
4622 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4623 UnmapGadget(tool_gadget[i]);
4626 static void HandleToolButtons(struct GadgetInfo *gi)
4628 request_gadget_id = gi->custom_id;
4631 static struct Mapping_EM_to_RND_object
4634 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4635 boolean is_backside; /* backside of moving element */
4641 em_object_mapping_list[] =
4644 Xblank, TRUE, FALSE,
4648 Yacid_splash_eB, FALSE, FALSE,
4649 EL_ACID_SPLASH_RIGHT, -1, -1
4652 Yacid_splash_wB, FALSE, FALSE,
4653 EL_ACID_SPLASH_LEFT, -1, -1
4656 #ifdef EM_ENGINE_BAD_ROLL
4658 Xstone_force_e, FALSE, FALSE,
4659 EL_ROCK, -1, MV_BIT_RIGHT
4662 Xstone_force_w, FALSE, FALSE,
4663 EL_ROCK, -1, MV_BIT_LEFT
4666 Xnut_force_e, FALSE, FALSE,
4667 EL_NUT, -1, MV_BIT_RIGHT
4670 Xnut_force_w, FALSE, FALSE,
4671 EL_NUT, -1, MV_BIT_LEFT
4674 Xspring_force_e, FALSE, FALSE,
4675 EL_SPRING, -1, MV_BIT_RIGHT
4678 Xspring_force_w, FALSE, FALSE,
4679 EL_SPRING, -1, MV_BIT_LEFT
4682 Xemerald_force_e, FALSE, FALSE,
4683 EL_EMERALD, -1, MV_BIT_RIGHT
4686 Xemerald_force_w, FALSE, FALSE,
4687 EL_EMERALD, -1, MV_BIT_LEFT
4690 Xdiamond_force_e, FALSE, FALSE,
4691 EL_DIAMOND, -1, MV_BIT_RIGHT
4694 Xdiamond_force_w, FALSE, FALSE,
4695 EL_DIAMOND, -1, MV_BIT_LEFT
4698 Xbomb_force_e, FALSE, FALSE,
4699 EL_BOMB, -1, MV_BIT_RIGHT
4702 Xbomb_force_w, FALSE, FALSE,
4703 EL_BOMB, -1, MV_BIT_LEFT
4705 #endif /* EM_ENGINE_BAD_ROLL */
4708 Xstone, TRUE, FALSE,
4712 Xstone_pause, FALSE, FALSE,
4716 Xstone_fall, FALSE, FALSE,
4720 Ystone_s, FALSE, FALSE,
4721 EL_ROCK, ACTION_FALLING, -1
4724 Ystone_sB, FALSE, TRUE,
4725 EL_ROCK, ACTION_FALLING, -1
4728 Ystone_e, FALSE, FALSE,
4729 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4732 Ystone_eB, FALSE, TRUE,
4733 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4736 Ystone_w, FALSE, FALSE,
4737 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4740 Ystone_wB, FALSE, TRUE,
4741 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4748 Xnut_pause, FALSE, FALSE,
4752 Xnut_fall, FALSE, FALSE,
4756 Ynut_s, FALSE, FALSE,
4757 EL_NUT, ACTION_FALLING, -1
4760 Ynut_sB, FALSE, TRUE,
4761 EL_NUT, ACTION_FALLING, -1
4764 Ynut_e, FALSE, FALSE,
4765 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4768 Ynut_eB, FALSE, TRUE,
4769 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4772 Ynut_w, FALSE, FALSE,
4773 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4776 Ynut_wB, FALSE, TRUE,
4777 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4780 Xbug_n, TRUE, FALSE,
4784 Xbug_e, TRUE, FALSE,
4785 EL_BUG_RIGHT, -1, -1
4788 Xbug_s, TRUE, FALSE,
4792 Xbug_w, TRUE, FALSE,
4796 Xbug_gon, FALSE, FALSE,
4800 Xbug_goe, FALSE, FALSE,
4801 EL_BUG_RIGHT, -1, -1
4804 Xbug_gos, FALSE, FALSE,
4808 Xbug_gow, FALSE, FALSE,
4812 Ybug_n, FALSE, FALSE,
4813 EL_BUG, ACTION_MOVING, MV_BIT_UP
4816 Ybug_nB, FALSE, TRUE,
4817 EL_BUG, ACTION_MOVING, MV_BIT_UP
4820 Ybug_e, FALSE, FALSE,
4821 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4824 Ybug_eB, FALSE, TRUE,
4825 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4828 Ybug_s, FALSE, FALSE,
4829 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4832 Ybug_sB, FALSE, TRUE,
4833 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4836 Ybug_w, FALSE, FALSE,
4837 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4840 Ybug_wB, FALSE, TRUE,
4841 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4844 Ybug_w_n, FALSE, FALSE,
4845 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4848 Ybug_n_e, FALSE, FALSE,
4849 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4852 Ybug_e_s, FALSE, FALSE,
4853 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4856 Ybug_s_w, FALSE, FALSE,
4857 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4860 Ybug_e_n, FALSE, FALSE,
4861 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4864 Ybug_s_e, FALSE, FALSE,
4865 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4868 Ybug_w_s, FALSE, FALSE,
4869 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4872 Ybug_n_w, FALSE, FALSE,
4873 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4876 Ybug_stone, FALSE, FALSE,
4877 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4880 Ybug_spring, FALSE, FALSE,
4881 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4884 Xtank_n, TRUE, FALSE,
4885 EL_SPACESHIP_UP, -1, -1
4888 Xtank_e, TRUE, FALSE,
4889 EL_SPACESHIP_RIGHT, -1, -1
4892 Xtank_s, TRUE, FALSE,
4893 EL_SPACESHIP_DOWN, -1, -1
4896 Xtank_w, TRUE, FALSE,
4897 EL_SPACESHIP_LEFT, -1, -1
4900 Xtank_gon, FALSE, FALSE,
4901 EL_SPACESHIP_UP, -1, -1
4904 Xtank_goe, FALSE, FALSE,
4905 EL_SPACESHIP_RIGHT, -1, -1
4908 Xtank_gos, FALSE, FALSE,
4909 EL_SPACESHIP_DOWN, -1, -1
4912 Xtank_gow, FALSE, FALSE,
4913 EL_SPACESHIP_LEFT, -1, -1
4916 Ytank_n, FALSE, FALSE,
4917 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4920 Ytank_nB, FALSE, TRUE,
4921 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4924 Ytank_e, FALSE, FALSE,
4925 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4928 Ytank_eB, FALSE, TRUE,
4929 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4932 Ytank_s, FALSE, FALSE,
4933 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4936 Ytank_sB, FALSE, TRUE,
4937 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4940 Ytank_w, FALSE, FALSE,
4941 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4944 Ytank_wB, FALSE, TRUE,
4945 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4948 Ytank_w_n, FALSE, FALSE,
4949 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4952 Ytank_n_e, FALSE, FALSE,
4953 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4956 Ytank_e_s, FALSE, FALSE,
4957 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4960 Ytank_s_w, FALSE, FALSE,
4961 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4964 Ytank_e_n, FALSE, FALSE,
4965 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4968 Ytank_s_e, FALSE, FALSE,
4969 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4972 Ytank_w_s, FALSE, FALSE,
4973 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4976 Ytank_n_w, FALSE, FALSE,
4977 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4980 Ytank_stone, FALSE, FALSE,
4981 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4984 Ytank_spring, FALSE, FALSE,
4985 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4988 Xandroid, TRUE, FALSE,
4989 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4992 Xandroid_1_n, FALSE, FALSE,
4993 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4996 Xandroid_2_n, FALSE, FALSE,
4997 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5000 Xandroid_1_e, FALSE, FALSE,
5001 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5004 Xandroid_2_e, FALSE, FALSE,
5005 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5008 Xandroid_1_w, FALSE, FALSE,
5009 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5012 Xandroid_2_w, FALSE, FALSE,
5013 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5016 Xandroid_1_s, FALSE, FALSE,
5017 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5020 Xandroid_2_s, FALSE, FALSE,
5021 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5024 Yandroid_n, FALSE, FALSE,
5025 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5028 Yandroid_nB, FALSE, TRUE,
5029 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5032 Yandroid_ne, FALSE, FALSE,
5033 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5036 Yandroid_neB, FALSE, TRUE,
5037 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5040 Yandroid_e, FALSE, FALSE,
5041 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5044 Yandroid_eB, FALSE, TRUE,
5045 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5048 Yandroid_se, FALSE, FALSE,
5049 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5052 Yandroid_seB, FALSE, TRUE,
5053 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5056 Yandroid_s, FALSE, FALSE,
5057 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5060 Yandroid_sB, FALSE, TRUE,
5061 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5064 Yandroid_sw, FALSE, FALSE,
5065 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5068 Yandroid_swB, FALSE, TRUE,
5069 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5072 Yandroid_w, FALSE, FALSE,
5073 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5076 Yandroid_wB, FALSE, TRUE,
5077 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5080 Yandroid_nw, FALSE, FALSE,
5081 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5084 Yandroid_nwB, FALSE, TRUE,
5085 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5088 Xspring, TRUE, FALSE,
5092 Xspring_pause, FALSE, FALSE,
5096 Xspring_e, FALSE, FALSE,
5100 Xspring_w, FALSE, FALSE,
5104 Xspring_fall, FALSE, FALSE,
5108 Yspring_s, FALSE, FALSE,
5109 EL_SPRING, ACTION_FALLING, -1
5112 Yspring_sB, FALSE, TRUE,
5113 EL_SPRING, ACTION_FALLING, -1
5116 Yspring_e, FALSE, FALSE,
5117 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5120 Yspring_eB, FALSE, TRUE,
5121 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5124 Yspring_w, FALSE, FALSE,
5125 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5128 Yspring_wB, FALSE, TRUE,
5129 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5132 Yspring_kill_e, FALSE, FALSE,
5133 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5136 Yspring_kill_eB, FALSE, TRUE,
5137 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5140 Yspring_kill_w, FALSE, FALSE,
5141 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5144 Yspring_kill_wB, FALSE, TRUE,
5145 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5148 Xeater_n, TRUE, FALSE,
5149 EL_YAMYAM_UP, -1, -1
5152 Xeater_e, TRUE, FALSE,
5153 EL_YAMYAM_RIGHT, -1, -1
5156 Xeater_w, TRUE, FALSE,
5157 EL_YAMYAM_LEFT, -1, -1
5160 Xeater_s, TRUE, FALSE,
5161 EL_YAMYAM_DOWN, -1, -1
5164 Yeater_n, FALSE, FALSE,
5165 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5168 Yeater_nB, FALSE, TRUE,
5169 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5172 Yeater_e, FALSE, FALSE,
5173 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5176 Yeater_eB, FALSE, TRUE,
5177 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5180 Yeater_s, FALSE, FALSE,
5181 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5184 Yeater_sB, FALSE, TRUE,
5185 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5188 Yeater_w, FALSE, FALSE,
5189 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5192 Yeater_wB, FALSE, TRUE,
5193 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5196 Yeater_stone, FALSE, FALSE,
5197 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5200 Yeater_spring, FALSE, FALSE,
5201 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5204 Xalien, TRUE, FALSE,
5208 Xalien_pause, FALSE, FALSE,
5212 Yalien_n, FALSE, FALSE,
5213 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5216 Yalien_nB, FALSE, TRUE,
5217 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5220 Yalien_e, FALSE, FALSE,
5221 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5224 Yalien_eB, FALSE, TRUE,
5225 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5228 Yalien_s, FALSE, FALSE,
5229 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5232 Yalien_sB, FALSE, TRUE,
5233 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5236 Yalien_w, FALSE, FALSE,
5237 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5240 Yalien_wB, FALSE, TRUE,
5241 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5244 Yalien_stone, FALSE, FALSE,
5245 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5248 Yalien_spring, FALSE, FALSE,
5249 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5252 Xemerald, TRUE, FALSE,
5256 Xemerald_pause, FALSE, FALSE,
5260 Xemerald_fall, FALSE, FALSE,
5264 Xemerald_shine, FALSE, FALSE,
5265 EL_EMERALD, ACTION_TWINKLING, -1
5268 Yemerald_s, FALSE, FALSE,
5269 EL_EMERALD, ACTION_FALLING, -1
5272 Yemerald_sB, FALSE, TRUE,
5273 EL_EMERALD, ACTION_FALLING, -1
5276 Yemerald_e, FALSE, FALSE,
5277 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5280 Yemerald_eB, FALSE, TRUE,
5281 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5284 Yemerald_w, FALSE, FALSE,
5285 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5288 Yemerald_wB, FALSE, TRUE,
5289 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5292 Yemerald_eat, FALSE, FALSE,
5293 EL_EMERALD, ACTION_COLLECTING, -1
5296 Yemerald_stone, FALSE, FALSE,
5297 EL_NUT, ACTION_BREAKING, -1
5300 Xdiamond, TRUE, FALSE,
5304 Xdiamond_pause, FALSE, FALSE,
5308 Xdiamond_fall, FALSE, FALSE,
5312 Xdiamond_shine, FALSE, FALSE,
5313 EL_DIAMOND, ACTION_TWINKLING, -1
5316 Ydiamond_s, FALSE, FALSE,
5317 EL_DIAMOND, ACTION_FALLING, -1
5320 Ydiamond_sB, FALSE, TRUE,
5321 EL_DIAMOND, ACTION_FALLING, -1
5324 Ydiamond_e, FALSE, FALSE,
5325 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5328 Ydiamond_eB, FALSE, TRUE,
5329 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5332 Ydiamond_w, FALSE, FALSE,
5333 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5336 Ydiamond_wB, FALSE, TRUE,
5337 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5340 Ydiamond_eat, FALSE, FALSE,
5341 EL_DIAMOND, ACTION_COLLECTING, -1
5344 Ydiamond_stone, FALSE, FALSE,
5345 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5348 Xdrip_fall, TRUE, FALSE,
5349 EL_AMOEBA_DROP, -1, -1
5352 Xdrip_stretch, FALSE, FALSE,
5353 EL_AMOEBA_DROP, ACTION_FALLING, -1
5356 Xdrip_stretchB, FALSE, TRUE,
5357 EL_AMOEBA_DROP, ACTION_FALLING, -1
5360 Xdrip_eat, FALSE, FALSE,
5361 EL_AMOEBA_DROP, ACTION_GROWING, -1
5364 Ydrip_s1, FALSE, FALSE,
5365 EL_AMOEBA_DROP, ACTION_FALLING, -1
5368 Ydrip_s1B, FALSE, TRUE,
5369 EL_AMOEBA_DROP, ACTION_FALLING, -1
5372 Ydrip_s2, FALSE, FALSE,
5373 EL_AMOEBA_DROP, ACTION_FALLING, -1
5376 Ydrip_s2B, FALSE, TRUE,
5377 EL_AMOEBA_DROP, ACTION_FALLING, -1
5384 Xbomb_pause, FALSE, FALSE,
5388 Xbomb_fall, FALSE, FALSE,
5392 Ybomb_s, FALSE, FALSE,
5393 EL_BOMB, ACTION_FALLING, -1
5396 Ybomb_sB, FALSE, TRUE,
5397 EL_BOMB, ACTION_FALLING, -1
5400 Ybomb_e, FALSE, FALSE,
5401 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5404 Ybomb_eB, FALSE, TRUE,
5405 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5408 Ybomb_w, FALSE, FALSE,
5409 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5412 Ybomb_wB, FALSE, TRUE,
5413 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5416 Ybomb_eat, FALSE, FALSE,
5417 EL_BOMB, ACTION_ACTIVATING, -1
5420 Xballoon, TRUE, FALSE,
5424 Yballoon_n, FALSE, FALSE,
5425 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5428 Yballoon_nB, FALSE, TRUE,
5429 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5432 Yballoon_e, FALSE, FALSE,
5433 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5436 Yballoon_eB, FALSE, TRUE,
5437 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5440 Yballoon_s, FALSE, FALSE,
5441 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5444 Yballoon_sB, FALSE, TRUE,
5445 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5448 Yballoon_w, FALSE, FALSE,
5449 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5452 Yballoon_wB, FALSE, TRUE,
5453 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5456 Xgrass, TRUE, FALSE,
5457 EL_EMC_GRASS, -1, -1
5460 Ygrass_nB, FALSE, FALSE,
5461 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5464 Ygrass_eB, FALSE, FALSE,
5465 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5468 Ygrass_sB, FALSE, FALSE,
5469 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5472 Ygrass_wB, FALSE, FALSE,
5473 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5480 Ydirt_nB, FALSE, FALSE,
5481 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5484 Ydirt_eB, FALSE, FALSE,
5485 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5488 Ydirt_sB, FALSE, FALSE,
5489 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5492 Ydirt_wB, FALSE, FALSE,
5493 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5496 Xacid_ne, TRUE, FALSE,
5497 EL_ACID_POOL_TOPRIGHT, -1, -1
5500 Xacid_se, TRUE, FALSE,
5501 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5504 Xacid_s, TRUE, FALSE,
5505 EL_ACID_POOL_BOTTOM, -1, -1
5508 Xacid_sw, TRUE, FALSE,
5509 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5512 Xacid_nw, TRUE, FALSE,
5513 EL_ACID_POOL_TOPLEFT, -1, -1
5516 Xacid_1, TRUE, FALSE,
5520 Xacid_2, FALSE, FALSE,
5524 Xacid_3, FALSE, FALSE,
5528 Xacid_4, FALSE, FALSE,
5532 Xacid_5, FALSE, FALSE,
5536 Xacid_6, FALSE, FALSE,
5540 Xacid_7, FALSE, FALSE,
5544 Xacid_8, FALSE, FALSE,
5548 Xball_1, TRUE, FALSE,
5549 EL_EMC_MAGIC_BALL, -1, -1
5552 Xball_1B, FALSE, FALSE,
5553 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5556 Xball_2, FALSE, FALSE,
5557 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5560 Xball_2B, FALSE, FALSE,
5561 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5564 Yball_eat, FALSE, FALSE,
5565 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5568 Ykey_1_eat, FALSE, FALSE,
5569 EL_EM_KEY_1, ACTION_COLLECTING, -1
5572 Ykey_2_eat, FALSE, FALSE,
5573 EL_EM_KEY_2, ACTION_COLLECTING, -1
5576 Ykey_3_eat, FALSE, FALSE,
5577 EL_EM_KEY_3, ACTION_COLLECTING, -1
5580 Ykey_4_eat, FALSE, FALSE,
5581 EL_EM_KEY_4, ACTION_COLLECTING, -1
5584 Ykey_5_eat, FALSE, FALSE,
5585 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5588 Ykey_6_eat, FALSE, FALSE,
5589 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5592 Ykey_7_eat, FALSE, FALSE,
5593 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5596 Ykey_8_eat, FALSE, FALSE,
5597 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5600 Ylenses_eat, FALSE, FALSE,
5601 EL_EMC_LENSES, ACTION_COLLECTING, -1
5604 Ymagnify_eat, FALSE, FALSE,
5605 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5608 Ygrass_eat, FALSE, FALSE,
5609 EL_EMC_GRASS, ACTION_SNAPPING, -1
5612 Ydirt_eat, FALSE, FALSE,
5613 EL_SAND, ACTION_SNAPPING, -1
5616 Xgrow_ns, TRUE, FALSE,
5617 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5620 Ygrow_ns_eat, FALSE, FALSE,
5621 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5624 Xgrow_ew, TRUE, FALSE,
5625 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5628 Ygrow_ew_eat, FALSE, FALSE,
5629 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5632 Xwonderwall, TRUE, FALSE,
5633 EL_MAGIC_WALL, -1, -1
5636 XwonderwallB, FALSE, FALSE,
5637 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5640 Xamoeba_1, TRUE, FALSE,
5641 EL_AMOEBA_DRY, ACTION_OTHER, -1
5644 Xamoeba_2, FALSE, FALSE,
5645 EL_AMOEBA_DRY, ACTION_OTHER, -1
5648 Xamoeba_3, FALSE, FALSE,
5649 EL_AMOEBA_DRY, ACTION_OTHER, -1
5652 Xamoeba_4, FALSE, FALSE,
5653 EL_AMOEBA_DRY, ACTION_OTHER, -1
5656 Xamoeba_5, TRUE, FALSE,
5657 EL_AMOEBA_WET, ACTION_OTHER, -1
5660 Xamoeba_6, FALSE, FALSE,
5661 EL_AMOEBA_WET, ACTION_OTHER, -1
5664 Xamoeba_7, FALSE, FALSE,
5665 EL_AMOEBA_WET, ACTION_OTHER, -1
5668 Xamoeba_8, FALSE, FALSE,
5669 EL_AMOEBA_WET, ACTION_OTHER, -1
5672 Xdoor_1, TRUE, FALSE,
5673 EL_EM_GATE_1, -1, -1
5676 Xdoor_2, TRUE, FALSE,
5677 EL_EM_GATE_2, -1, -1
5680 Xdoor_3, TRUE, FALSE,
5681 EL_EM_GATE_3, -1, -1
5684 Xdoor_4, TRUE, FALSE,
5685 EL_EM_GATE_4, -1, -1
5688 Xdoor_5, TRUE, FALSE,
5689 EL_EMC_GATE_5, -1, -1
5692 Xdoor_6, TRUE, FALSE,
5693 EL_EMC_GATE_6, -1, -1
5696 Xdoor_7, TRUE, FALSE,
5697 EL_EMC_GATE_7, -1, -1
5700 Xdoor_8, TRUE, FALSE,
5701 EL_EMC_GATE_8, -1, -1
5704 Xkey_1, TRUE, FALSE,
5708 Xkey_2, TRUE, FALSE,
5712 Xkey_3, TRUE, FALSE,
5716 Xkey_4, TRUE, FALSE,
5720 Xkey_5, TRUE, FALSE,
5721 EL_EMC_KEY_5, -1, -1
5724 Xkey_6, TRUE, FALSE,
5725 EL_EMC_KEY_6, -1, -1
5728 Xkey_7, TRUE, FALSE,
5729 EL_EMC_KEY_7, -1, -1
5732 Xkey_8, TRUE, FALSE,
5733 EL_EMC_KEY_8, -1, -1
5736 Xwind_n, TRUE, FALSE,
5737 EL_BALLOON_SWITCH_UP, -1, -1
5740 Xwind_e, TRUE, FALSE,
5741 EL_BALLOON_SWITCH_RIGHT, -1, -1
5744 Xwind_s, TRUE, FALSE,
5745 EL_BALLOON_SWITCH_DOWN, -1, -1
5748 Xwind_w, TRUE, FALSE,
5749 EL_BALLOON_SWITCH_LEFT, -1, -1
5752 Xwind_nesw, TRUE, FALSE,
5753 EL_BALLOON_SWITCH_ANY, -1, -1
5756 Xwind_stop, TRUE, FALSE,
5757 EL_BALLOON_SWITCH_NONE, -1, -1
5761 EL_EM_EXIT_CLOSED, -1, -1
5764 Xexit_1, TRUE, FALSE,
5765 EL_EM_EXIT_OPEN, -1, -1
5768 Xexit_2, FALSE, FALSE,
5769 EL_EM_EXIT_OPEN, -1, -1
5772 Xexit_3, FALSE, FALSE,
5773 EL_EM_EXIT_OPEN, -1, -1
5776 Xdynamite, TRUE, FALSE,
5777 EL_EM_DYNAMITE, -1, -1
5780 Ydynamite_eat, FALSE, FALSE,
5781 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5784 Xdynamite_1, TRUE, FALSE,
5785 EL_EM_DYNAMITE_ACTIVE, -1, -1
5788 Xdynamite_2, FALSE, FALSE,
5789 EL_EM_DYNAMITE_ACTIVE, -1, -1
5792 Xdynamite_3, FALSE, FALSE,
5793 EL_EM_DYNAMITE_ACTIVE, -1, -1
5796 Xdynamite_4, FALSE, FALSE,
5797 EL_EM_DYNAMITE_ACTIVE, -1, -1
5800 Xbumper, TRUE, FALSE,
5801 EL_EMC_SPRING_BUMPER, -1, -1
5804 XbumperB, FALSE, FALSE,
5805 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5808 Xwheel, TRUE, FALSE,
5809 EL_ROBOT_WHEEL, -1, -1
5812 XwheelB, FALSE, FALSE,
5813 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5816 Xswitch, TRUE, FALSE,
5817 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5820 XswitchB, FALSE, FALSE,
5821 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5825 EL_QUICKSAND_EMPTY, -1, -1
5828 Xsand_stone, TRUE, FALSE,
5829 EL_QUICKSAND_FULL, -1, -1
5832 Xsand_stonein_1, FALSE, TRUE,
5833 EL_ROCK, ACTION_FILLING, -1
5836 Xsand_stonein_2, FALSE, TRUE,
5837 EL_ROCK, ACTION_FILLING, -1
5840 Xsand_stonein_3, FALSE, TRUE,
5841 EL_ROCK, ACTION_FILLING, -1
5844 Xsand_stonein_4, FALSE, TRUE,
5845 EL_ROCK, ACTION_FILLING, -1
5849 Xsand_stonesand_1, FALSE, FALSE,
5850 EL_QUICKSAND_EMPTYING, -1, -1
5853 Xsand_stonesand_2, FALSE, FALSE,
5854 EL_QUICKSAND_EMPTYING, -1, -1
5857 Xsand_stonesand_3, FALSE, FALSE,
5858 EL_QUICKSAND_EMPTYING, -1, -1
5861 Xsand_stonesand_4, FALSE, FALSE,
5862 EL_QUICKSAND_EMPTYING, -1, -1
5865 Xsand_stonesand_quickout_1, FALSE, FALSE,
5866 EL_QUICKSAND_EMPTYING, -1, -1
5869 Xsand_stonesand_quickout_2, FALSE, FALSE,
5870 EL_QUICKSAND_EMPTYING, -1, -1
5874 Xsand_stonesand_1, FALSE, FALSE,
5875 EL_QUICKSAND_FULL, -1, -1
5878 Xsand_stonesand_2, FALSE, FALSE,
5879 EL_QUICKSAND_FULL, -1, -1
5882 Xsand_stonesand_3, FALSE, FALSE,
5883 EL_QUICKSAND_FULL, -1, -1
5886 Xsand_stonesand_4, FALSE, FALSE,
5887 EL_QUICKSAND_FULL, -1, -1
5891 Xsand_stoneout_1, FALSE, FALSE,
5892 EL_ROCK, ACTION_EMPTYING, -1
5895 Xsand_stoneout_2, FALSE, FALSE,
5896 EL_ROCK, ACTION_EMPTYING, -1
5900 Xsand_sandstone_1, FALSE, FALSE,
5901 EL_QUICKSAND_FILLING, -1, -1
5904 Xsand_sandstone_2, FALSE, FALSE,
5905 EL_QUICKSAND_FILLING, -1, -1
5908 Xsand_sandstone_3, FALSE, FALSE,
5909 EL_QUICKSAND_FILLING, -1, -1
5912 Xsand_sandstone_4, FALSE, FALSE,
5913 EL_QUICKSAND_FILLING, -1, -1
5917 Xsand_sandstone_1, FALSE, FALSE,
5918 EL_QUICKSAND_FULL, -1, -1
5921 Xsand_sandstone_2, FALSE, FALSE,
5922 EL_QUICKSAND_FULL, -1, -1
5925 Xsand_sandstone_3, FALSE, FALSE,
5926 EL_QUICKSAND_FULL, -1, -1
5929 Xsand_sandstone_4, FALSE, FALSE,
5930 EL_QUICKSAND_FULL, -1, -1
5934 Xplant, TRUE, FALSE,
5935 EL_EMC_PLANT, -1, -1
5938 Yplant, FALSE, FALSE,
5939 EL_EMC_PLANT, -1, -1
5942 Xlenses, TRUE, FALSE,
5943 EL_EMC_LENSES, -1, -1
5946 Xmagnify, TRUE, FALSE,
5947 EL_EMC_MAGNIFIER, -1, -1
5950 Xdripper, TRUE, FALSE,
5951 EL_EMC_DRIPPER, -1, -1
5954 XdripperB, FALSE, FALSE,
5955 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5958 Xfake_blank, TRUE, FALSE,
5959 EL_INVISIBLE_WALL, -1, -1
5962 Xfake_blankB, FALSE, FALSE,
5963 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5966 Xfake_grass, TRUE, FALSE,
5967 EL_EMC_FAKE_GRASS, -1, -1
5970 Xfake_grassB, FALSE, FALSE,
5971 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5974 Xfake_door_1, TRUE, FALSE,
5975 EL_EM_GATE_1_GRAY, -1, -1
5978 Xfake_door_2, TRUE, FALSE,
5979 EL_EM_GATE_2_GRAY, -1, -1
5982 Xfake_door_3, TRUE, FALSE,
5983 EL_EM_GATE_3_GRAY, -1, -1
5986 Xfake_door_4, TRUE, FALSE,
5987 EL_EM_GATE_4_GRAY, -1, -1
5990 Xfake_door_5, TRUE, FALSE,
5991 EL_EMC_GATE_5_GRAY, -1, -1
5994 Xfake_door_6, TRUE, FALSE,
5995 EL_EMC_GATE_6_GRAY, -1, -1
5998 Xfake_door_7, TRUE, FALSE,
5999 EL_EMC_GATE_7_GRAY, -1, -1
6002 Xfake_door_8, TRUE, FALSE,
6003 EL_EMC_GATE_8_GRAY, -1, -1
6006 Xfake_acid_1, TRUE, FALSE,
6007 EL_EMC_FAKE_ACID, -1, -1
6010 Xfake_acid_2, FALSE, FALSE,
6011 EL_EMC_FAKE_ACID, -1, -1
6014 Xfake_acid_3, FALSE, FALSE,
6015 EL_EMC_FAKE_ACID, -1, -1
6018 Xfake_acid_4, FALSE, FALSE,
6019 EL_EMC_FAKE_ACID, -1, -1
6022 Xfake_acid_5, FALSE, FALSE,
6023 EL_EMC_FAKE_ACID, -1, -1
6026 Xfake_acid_6, FALSE, FALSE,
6027 EL_EMC_FAKE_ACID, -1, -1
6030 Xfake_acid_7, FALSE, FALSE,
6031 EL_EMC_FAKE_ACID, -1, -1
6034 Xfake_acid_8, FALSE, FALSE,
6035 EL_EMC_FAKE_ACID, -1, -1
6038 Xsteel_1, TRUE, FALSE,
6039 EL_STEELWALL, -1, -1
6042 Xsteel_2, TRUE, FALSE,
6043 EL_EMC_STEELWALL_2, -1, -1
6046 Xsteel_3, TRUE, FALSE,
6047 EL_EMC_STEELWALL_3, -1, -1
6050 Xsteel_4, TRUE, FALSE,
6051 EL_EMC_STEELWALL_4, -1, -1
6054 Xwall_1, TRUE, FALSE,
6058 Xwall_2, TRUE, FALSE,
6059 EL_EMC_WALL_14, -1, -1
6062 Xwall_3, TRUE, FALSE,
6063 EL_EMC_WALL_15, -1, -1
6066 Xwall_4, TRUE, FALSE,
6067 EL_EMC_WALL_16, -1, -1
6070 Xround_wall_1, TRUE, FALSE,
6071 EL_WALL_SLIPPERY, -1, -1
6074 Xround_wall_2, TRUE, FALSE,
6075 EL_EMC_WALL_SLIPPERY_2, -1, -1
6078 Xround_wall_3, TRUE, FALSE,
6079 EL_EMC_WALL_SLIPPERY_3, -1, -1
6082 Xround_wall_4, TRUE, FALSE,
6083 EL_EMC_WALL_SLIPPERY_4, -1, -1
6086 Xdecor_1, TRUE, FALSE,
6087 EL_EMC_WALL_8, -1, -1
6090 Xdecor_2, TRUE, FALSE,
6091 EL_EMC_WALL_6, -1, -1
6094 Xdecor_3, TRUE, FALSE,
6095 EL_EMC_WALL_4, -1, -1
6098 Xdecor_4, TRUE, FALSE,
6099 EL_EMC_WALL_7, -1, -1
6102 Xdecor_5, TRUE, FALSE,
6103 EL_EMC_WALL_5, -1, -1
6106 Xdecor_6, TRUE, FALSE,
6107 EL_EMC_WALL_9, -1, -1
6110 Xdecor_7, TRUE, FALSE,
6111 EL_EMC_WALL_10, -1, -1
6114 Xdecor_8, TRUE, FALSE,
6115 EL_EMC_WALL_1, -1, -1
6118 Xdecor_9, TRUE, FALSE,
6119 EL_EMC_WALL_2, -1, -1
6122 Xdecor_10, TRUE, FALSE,
6123 EL_EMC_WALL_3, -1, -1
6126 Xdecor_11, TRUE, FALSE,
6127 EL_EMC_WALL_11, -1, -1
6130 Xdecor_12, TRUE, FALSE,
6131 EL_EMC_WALL_12, -1, -1
6134 Xalpha_0, TRUE, FALSE,
6135 EL_CHAR('0'), -1, -1
6138 Xalpha_1, TRUE, FALSE,
6139 EL_CHAR('1'), -1, -1
6142 Xalpha_2, TRUE, FALSE,
6143 EL_CHAR('2'), -1, -1
6146 Xalpha_3, TRUE, FALSE,
6147 EL_CHAR('3'), -1, -1
6150 Xalpha_4, TRUE, FALSE,
6151 EL_CHAR('4'), -1, -1
6154 Xalpha_5, TRUE, FALSE,
6155 EL_CHAR('5'), -1, -1
6158 Xalpha_6, TRUE, FALSE,
6159 EL_CHAR('6'), -1, -1
6162 Xalpha_7, TRUE, FALSE,
6163 EL_CHAR('7'), -1, -1
6166 Xalpha_8, TRUE, FALSE,
6167 EL_CHAR('8'), -1, -1
6170 Xalpha_9, TRUE, FALSE,
6171 EL_CHAR('9'), -1, -1
6174 Xalpha_excla, TRUE, FALSE,
6175 EL_CHAR('!'), -1, -1
6178 Xalpha_quote, TRUE, FALSE,
6179 EL_CHAR('"'), -1, -1
6182 Xalpha_comma, TRUE, FALSE,
6183 EL_CHAR(','), -1, -1
6186 Xalpha_minus, TRUE, FALSE,
6187 EL_CHAR('-'), -1, -1
6190 Xalpha_perio, TRUE, FALSE,
6191 EL_CHAR('.'), -1, -1
6194 Xalpha_colon, TRUE, FALSE,
6195 EL_CHAR(':'), -1, -1
6198 Xalpha_quest, TRUE, FALSE,
6199 EL_CHAR('?'), -1, -1
6202 Xalpha_a, TRUE, FALSE,
6203 EL_CHAR('A'), -1, -1
6206 Xalpha_b, TRUE, FALSE,
6207 EL_CHAR('B'), -1, -1
6210 Xalpha_c, TRUE, FALSE,
6211 EL_CHAR('C'), -1, -1
6214 Xalpha_d, TRUE, FALSE,
6215 EL_CHAR('D'), -1, -1
6218 Xalpha_e, TRUE, FALSE,
6219 EL_CHAR('E'), -1, -1
6222 Xalpha_f, TRUE, FALSE,
6223 EL_CHAR('F'), -1, -1
6226 Xalpha_g, TRUE, FALSE,
6227 EL_CHAR('G'), -1, -1
6230 Xalpha_h, TRUE, FALSE,
6231 EL_CHAR('H'), -1, -1
6234 Xalpha_i, TRUE, FALSE,
6235 EL_CHAR('I'), -1, -1
6238 Xalpha_j, TRUE, FALSE,
6239 EL_CHAR('J'), -1, -1
6242 Xalpha_k, TRUE, FALSE,
6243 EL_CHAR('K'), -1, -1
6246 Xalpha_l, TRUE, FALSE,
6247 EL_CHAR('L'), -1, -1
6250 Xalpha_m, TRUE, FALSE,
6251 EL_CHAR('M'), -1, -1
6254 Xalpha_n, TRUE, FALSE,
6255 EL_CHAR('N'), -1, -1
6258 Xalpha_o, TRUE, FALSE,
6259 EL_CHAR('O'), -1, -1
6262 Xalpha_p, TRUE, FALSE,
6263 EL_CHAR('P'), -1, -1
6266 Xalpha_q, TRUE, FALSE,
6267 EL_CHAR('Q'), -1, -1
6270 Xalpha_r, TRUE, FALSE,
6271 EL_CHAR('R'), -1, -1
6274 Xalpha_s, TRUE, FALSE,
6275 EL_CHAR('S'), -1, -1
6278 Xalpha_t, TRUE, FALSE,
6279 EL_CHAR('T'), -1, -1
6282 Xalpha_u, TRUE, FALSE,
6283 EL_CHAR('U'), -1, -1
6286 Xalpha_v, TRUE, FALSE,
6287 EL_CHAR('V'), -1, -1
6290 Xalpha_w, TRUE, FALSE,
6291 EL_CHAR('W'), -1, -1
6294 Xalpha_x, TRUE, FALSE,
6295 EL_CHAR('X'), -1, -1
6298 Xalpha_y, TRUE, FALSE,
6299 EL_CHAR('Y'), -1, -1
6302 Xalpha_z, TRUE, FALSE,
6303 EL_CHAR('Z'), -1, -1
6306 Xalpha_arrow_e, TRUE, FALSE,
6307 EL_CHAR('>'), -1, -1
6310 Xalpha_arrow_w, TRUE, FALSE,
6311 EL_CHAR('<'), -1, -1
6314 Xalpha_copyr, TRUE, FALSE,
6315 EL_CHAR('©'), -1, -1
6319 Xboom_bug, FALSE, FALSE,
6320 EL_BUG, ACTION_EXPLODING, -1
6323 Xboom_bomb, FALSE, FALSE,
6324 EL_BOMB, ACTION_EXPLODING, -1
6327 Xboom_android, FALSE, FALSE,
6328 EL_EMC_ANDROID, ACTION_OTHER, -1
6331 Xboom_1, FALSE, FALSE,
6332 EL_DEFAULT, ACTION_EXPLODING, -1
6335 Xboom_2, FALSE, FALSE,
6336 EL_DEFAULT, ACTION_EXPLODING, -1
6339 Znormal, FALSE, FALSE,
6343 Zdynamite, FALSE, FALSE,
6347 Zplayer, FALSE, FALSE,
6351 ZBORDER, FALSE, FALSE,
6361 static struct Mapping_EM_to_RND_player
6370 em_player_mapping_list[] =
6374 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6378 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6382 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6386 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6390 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6394 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6398 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6402 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6406 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6410 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6414 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6418 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6422 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6426 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6430 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6434 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6438 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6442 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6446 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6450 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6454 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6458 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6462 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6466 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6470 EL_PLAYER_1, ACTION_DEFAULT, -1,
6474 EL_PLAYER_2, ACTION_DEFAULT, -1,
6478 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6482 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6486 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6490 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6494 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6498 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6502 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6506 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6510 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6514 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6518 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6522 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6526 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6530 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6534 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6538 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6542 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6546 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6550 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6554 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6558 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6562 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6566 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6570 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6574 EL_PLAYER_3, ACTION_DEFAULT, -1,
6578 EL_PLAYER_4, ACTION_DEFAULT, -1,
6587 int map_element_RND_to_EM(int element_rnd)
6589 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6590 static boolean mapping_initialized = FALSE;
6592 if (!mapping_initialized)
6596 /* return "Xalpha_quest" for all undefined elements in mapping array */
6597 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6598 mapping_RND_to_EM[i] = Xalpha_quest;
6600 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6601 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6602 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6603 em_object_mapping_list[i].element_em;
6605 mapping_initialized = TRUE;
6608 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6609 return mapping_RND_to_EM[element_rnd];
6611 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6616 int map_element_EM_to_RND(int element_em)
6618 static unsigned short mapping_EM_to_RND[TILE_MAX];
6619 static boolean mapping_initialized = FALSE;
6621 if (!mapping_initialized)
6625 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6626 for (i = 0; i < TILE_MAX; i++)
6627 mapping_EM_to_RND[i] = EL_UNKNOWN;
6629 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6630 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6631 em_object_mapping_list[i].element_rnd;
6633 mapping_initialized = TRUE;
6636 if (element_em >= 0 && element_em < TILE_MAX)
6637 return mapping_EM_to_RND[element_em];
6639 Error(ERR_WARN, "invalid EM level element %d", element_em);
6644 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6646 struct LevelInfo_EM *level_em = level->native_em_level;
6647 struct LEVEL *lev = level_em->lev;
6650 for (i = 0; i < TILE_MAX; i++)
6651 lev->android_array[i] = Xblank;
6653 for (i = 0; i < level->num_android_clone_elements; i++)
6655 int element_rnd = level->android_clone_element[i];
6656 int element_em = map_element_RND_to_EM(element_rnd);
6658 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6659 if (em_object_mapping_list[j].element_rnd == element_rnd)
6660 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6664 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6666 struct LevelInfo_EM *level_em = level->native_em_level;
6667 struct LEVEL *lev = level_em->lev;
6670 level->num_android_clone_elements = 0;
6672 for (i = 0; i < TILE_MAX; i++)
6674 int element_em = lev->android_array[i];
6676 boolean element_found = FALSE;
6678 if (element_em == Xblank)
6681 element_rnd = map_element_EM_to_RND(element_em);
6683 for (j = 0; j < level->num_android_clone_elements; j++)
6684 if (level->android_clone_element[j] == element_rnd)
6685 element_found = TRUE;
6689 level->android_clone_element[level->num_android_clone_elements++] =
6692 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6697 if (level->num_android_clone_elements == 0)
6699 level->num_android_clone_elements = 1;
6700 level->android_clone_element[0] = EL_EMPTY;
6704 int map_direction_RND_to_EM(int direction)
6706 return (direction == MV_UP ? 0 :
6707 direction == MV_RIGHT ? 1 :
6708 direction == MV_DOWN ? 2 :
6709 direction == MV_LEFT ? 3 :
6713 int map_direction_EM_to_RND(int direction)
6715 return (direction == 0 ? MV_UP :
6716 direction == 1 ? MV_RIGHT :
6717 direction == 2 ? MV_DOWN :
6718 direction == 3 ? MV_LEFT :
6722 int map_element_RND_to_SP(int element_rnd)
6724 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6726 if (element_rnd >= EL_SP_START &&
6727 element_rnd <= EL_SP_END)
6728 element_sp = element_rnd - EL_SP_START;
6729 else if (element_rnd == EL_EMPTY_SPACE)
6731 else if (element_rnd == EL_INVISIBLE_WALL)
6737 int map_element_SP_to_RND(int element_sp)
6739 int element_rnd = EL_UNKNOWN;
6741 if (element_sp >= 0x00 &&
6743 element_rnd = EL_SP_START + element_sp;
6744 else if (element_sp == 0x28)
6745 element_rnd = EL_INVISIBLE_WALL;
6750 int map_action_SP_to_RND(int action_sp)
6754 case actActive: return ACTION_ACTIVE;
6755 case actImpact: return ACTION_IMPACT;
6756 case actExploding: return ACTION_EXPLODING;
6757 case actDigging: return ACTION_DIGGING;
6758 case actSnapping: return ACTION_SNAPPING;
6759 case actCollecting: return ACTION_COLLECTING;
6760 case actPassing: return ACTION_PASSING;
6761 case actPushing: return ACTION_PUSHING;
6762 case actDropping: return ACTION_DROPPING;
6764 default: return ACTION_DEFAULT;
6768 int get_next_element(int element)
6772 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6773 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6774 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6775 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6776 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6777 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6778 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6779 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6780 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6781 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6782 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6784 default: return element;
6789 int el_act_dir2img(int element, int action, int direction)
6791 element = GFX_ELEMENT(element);
6793 if (direction == MV_NONE)
6794 return element_info[element].graphic[action];
6796 direction = MV_DIR_TO_BIT(direction);
6798 return element_info[element].direction_graphic[action][direction];
6801 int el_act_dir2img(int element, int action, int direction)
6803 element = GFX_ELEMENT(element);
6804 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6806 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6807 return element_info[element].direction_graphic[action][direction];
6812 static int el_act_dir2crm(int element, int action, int direction)
6814 element = GFX_ELEMENT(element);
6816 if (direction == MV_NONE)
6817 return element_info[element].crumbled[action];
6819 direction = MV_DIR_TO_BIT(direction);
6821 return element_info[element].direction_crumbled[action][direction];
6824 static int el_act_dir2crm(int element, int action, int direction)
6826 element = GFX_ELEMENT(element);
6827 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6829 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6830 return element_info[element].direction_crumbled[action][direction];
6834 int el_act2img(int element, int action)
6836 element = GFX_ELEMENT(element);
6838 return element_info[element].graphic[action];
6841 int el_act2crm(int element, int action)
6843 element = GFX_ELEMENT(element);
6845 return element_info[element].crumbled[action];
6848 int el_dir2img(int element, int direction)
6850 element = GFX_ELEMENT(element);
6852 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6855 int el2baseimg(int element)
6857 return element_info[element].graphic[ACTION_DEFAULT];
6860 int el2img(int element)
6862 element = GFX_ELEMENT(element);
6864 return element_info[element].graphic[ACTION_DEFAULT];
6867 int el2edimg(int element)
6869 element = GFX_ELEMENT(element);
6871 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6874 int el2preimg(int element)
6876 element = GFX_ELEMENT(element);
6878 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6881 int el2panelimg(int element)
6883 element = GFX_ELEMENT(element);
6885 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6888 int font2baseimg(int font_nr)
6890 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6893 int getBeltNrFromBeltElement(int element)
6895 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6896 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6897 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6900 int getBeltNrFromBeltActiveElement(int element)
6902 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6903 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6904 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6907 int getBeltNrFromBeltSwitchElement(int element)
6909 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6910 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6911 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6914 int getBeltDirNrFromBeltElement(int element)
6916 static int belt_base_element[4] =
6918 EL_CONVEYOR_BELT_1_LEFT,
6919 EL_CONVEYOR_BELT_2_LEFT,
6920 EL_CONVEYOR_BELT_3_LEFT,
6921 EL_CONVEYOR_BELT_4_LEFT
6924 int belt_nr = getBeltNrFromBeltElement(element);
6925 int belt_dir_nr = element - belt_base_element[belt_nr];
6927 return (belt_dir_nr % 3);
6930 int getBeltDirNrFromBeltSwitchElement(int element)
6932 static int belt_base_element[4] =
6934 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6935 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6936 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6937 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6940 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6941 int belt_dir_nr = element - belt_base_element[belt_nr];
6943 return (belt_dir_nr % 3);
6946 int getBeltDirFromBeltElement(int element)
6948 static int belt_move_dir[3] =
6955 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6957 return belt_move_dir[belt_dir_nr];
6960 int getBeltDirFromBeltSwitchElement(int element)
6962 static int belt_move_dir[3] =
6969 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6971 return belt_move_dir[belt_dir_nr];
6974 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6976 static int belt_base_element[4] =
6978 EL_CONVEYOR_BELT_1_LEFT,
6979 EL_CONVEYOR_BELT_2_LEFT,
6980 EL_CONVEYOR_BELT_3_LEFT,
6981 EL_CONVEYOR_BELT_4_LEFT
6984 return belt_base_element[belt_nr] + belt_dir_nr;
6987 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6989 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6991 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6994 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6996 static int belt_base_element[4] =
6998 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6999 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7000 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7001 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7004 return belt_base_element[belt_nr] + belt_dir_nr;
7007 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7009 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7011 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7014 int getNumActivePlayers_EM()
7016 int num_players = 0;
7022 for (i = 0; i < MAX_PLAYERS; i++)
7023 if (tape.player_participates[i])
7029 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7031 int game_frame_delay_value;
7033 game_frame_delay_value =
7034 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7035 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7038 if (tape.playing && tape.warp_forward && !tape.pausing)
7039 game_frame_delay_value = 0;
7041 return game_frame_delay_value;
7044 unsigned int InitRND(long seed)
7046 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7047 return InitEngineRandom_EM(seed);
7048 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7049 return InitEngineRandom_SP(seed);
7051 return InitEngineRandom_RND(seed);
7055 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7056 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7059 inline static int get_effective_element_EM(int tile, int frame_em)
7061 int element = object_mapping[tile].element_rnd;
7062 int action = object_mapping[tile].action;
7063 boolean is_backside = object_mapping[tile].is_backside;
7064 boolean action_removing = (action == ACTION_DIGGING ||
7065 action == ACTION_SNAPPING ||
7066 action == ACTION_COLLECTING);
7072 case Yacid_splash_eB:
7073 case Yacid_splash_wB:
7074 return (frame_em > 5 ? EL_EMPTY : element);
7077 case Ydiamond_stone:
7078 // if (!game.use_native_emc_graphics_engine)
7086 else /* frame_em == 7 */
7090 case Yacid_splash_eB:
7091 case Yacid_splash_wB:
7094 case Yemerald_stone:
7097 case Ydiamond_stone:
7101 case Xdrip_stretchB:
7120 case Xsand_stonein_1:
7121 case Xsand_stonein_2:
7122 case Xsand_stonein_3:
7123 case Xsand_stonein_4:
7127 return (is_backside || action_removing ? EL_EMPTY : element);
7132 inline static boolean check_linear_animation_EM(int tile)
7136 case Xsand_stonesand_1:
7137 case Xsand_stonesand_quickout_1:
7138 case Xsand_sandstone_1:
7139 case Xsand_stonein_1:
7140 case Xsand_stoneout_1:
7160 case Yacid_splash_eB:
7161 case Yacid_splash_wB:
7162 case Yemerald_stone:
7170 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7171 boolean has_crumbled_graphics,
7172 int crumbled, int sync_frame)
7174 /* if element can be crumbled, but certain action graphics are just empty
7175 space (like instantly snapping sand to empty space in 1 frame), do not
7176 treat these empty space graphics as crumbled graphics in EMC engine */
7177 if (crumbled == IMG_EMPTY_SPACE)
7178 has_crumbled_graphics = FALSE;
7180 if (has_crumbled_graphics)
7182 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7183 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7184 g_crumbled->anim_delay,
7185 g_crumbled->anim_mode,
7186 g_crumbled->anim_start_frame,
7189 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7190 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7192 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7194 g_em->has_crumbled_graphics = TRUE;
7198 g_em->crumbled_bitmap = NULL;
7199 g_em->crumbled_src_x = 0;
7200 g_em->crumbled_src_y = 0;
7201 g_em->crumbled_border_size = 0;
7203 g_em->has_crumbled_graphics = FALSE;
7207 void ResetGfxAnimation_EM(int x, int y, int tile)
7212 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7213 int tile, int frame_em, int x, int y)
7215 int action = object_mapping[tile].action;
7217 int direction = object_mapping[tile].direction;
7218 int effective_element = get_effective_element_EM(tile, frame_em);
7219 int graphic = (direction == MV_NONE ?
7220 el_act2img(effective_element, action) :
7221 el_act_dir2img(effective_element, action, direction));
7222 struct GraphicInfo *g = &graphic_info[graphic];
7225 boolean action_removing = (action == ACTION_DIGGING ||
7226 action == ACTION_SNAPPING ||
7227 action == ACTION_COLLECTING);
7228 boolean action_moving = (action == ACTION_FALLING ||
7229 action == ACTION_MOVING ||
7230 action == ACTION_PUSHING ||
7231 action == ACTION_EATING ||
7232 action == ACTION_FILLING ||
7233 action == ACTION_EMPTYING);
7234 boolean action_falling = (action == ACTION_FALLING ||
7235 action == ACTION_FILLING ||
7236 action == ACTION_EMPTYING);
7238 /* special case: graphic uses "2nd movement tile" and has defined
7239 7 frames for movement animation (or less) => use default graphic
7240 for last (8th) frame which ends the movement animation */
7241 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7243 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7244 graphic = (direction == MV_NONE ?
7245 el_act2img(effective_element, action) :
7246 el_act_dir2img(effective_element, action, direction));
7248 g = &graphic_info[graphic];
7252 if (tile == Xsand_stonesand_1 ||
7253 tile == Xsand_stonesand_2 ||
7254 tile == Xsand_stonesand_3 ||
7255 tile == Xsand_stonesand_4)
7256 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7260 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7264 // printf("::: resetting... [%d]\n", tile);
7267 if (action_removing || check_linear_animation_EM(tile))
7269 GfxFrame[x][y] = frame_em;
7271 // printf("::: resetting... [%d]\n", tile);
7274 else if (action_moving)
7276 boolean is_backside = object_mapping[tile].is_backside;
7280 int direction = object_mapping[tile].direction;
7281 int move_dir = (action_falling ? MV_DOWN : direction);
7286 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7287 if (g->double_movement && frame_em == 0)
7291 // printf("::: resetting... [%d]\n", tile);
7295 if (move_dir == MV_LEFT)
7296 GfxFrame[x - 1][y] = GfxFrame[x][y];
7297 else if (move_dir == MV_RIGHT)
7298 GfxFrame[x + 1][y] = GfxFrame[x][y];
7299 else if (move_dir == MV_UP)
7300 GfxFrame[x][y - 1] = GfxFrame[x][y];
7301 else if (move_dir == MV_DOWN)
7302 GfxFrame[x][y + 1] = GfxFrame[x][y];
7309 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7310 if (tile == Xsand_stonesand_quickout_1 ||
7311 tile == Xsand_stonesand_quickout_2)
7316 if (tile == Xsand_stonesand_1 ||
7317 tile == Xsand_stonesand_2 ||
7318 tile == Xsand_stonesand_3 ||
7319 tile == Xsand_stonesand_4)
7320 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7324 if (graphic_info[graphic].anim_global_sync)
7325 sync_frame = FrameCounter;
7326 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7327 sync_frame = GfxFrame[x][y];
7329 sync_frame = 0; /* playfield border (pseudo steel) */
7331 SetRandomAnimationValue(x, y);
7333 int frame = getAnimationFrame(g->anim_frames,
7336 g->anim_start_frame,
7339 g_em->unique_identifier =
7340 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7344 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7345 int tile, int frame_em, int x, int y)
7347 int action = object_mapping[tile].action;
7348 int direction = object_mapping[tile].direction;
7349 boolean is_backside = object_mapping[tile].is_backside;
7350 int effective_element = get_effective_element_EM(tile, frame_em);
7352 int effective_action = action;
7354 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7356 int graphic = (direction == MV_NONE ?
7357 el_act2img(effective_element, effective_action) :
7358 el_act_dir2img(effective_element, effective_action,
7360 int crumbled = (direction == MV_NONE ?
7361 el_act2crm(effective_element, effective_action) :
7362 el_act_dir2crm(effective_element, effective_action,
7364 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7365 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7366 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7367 struct GraphicInfo *g = &graphic_info[graphic];
7369 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7373 /* special case: graphic uses "2nd movement tile" and has defined
7374 7 frames for movement animation (or less) => use default graphic
7375 for last (8th) frame which ends the movement animation */
7376 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7378 effective_action = ACTION_DEFAULT;
7379 graphic = (direction == MV_NONE ?
7380 el_act2img(effective_element, effective_action) :
7381 el_act_dir2img(effective_element, effective_action,
7383 crumbled = (direction == MV_NONE ?
7384 el_act2crm(effective_element, effective_action) :
7385 el_act_dir2crm(effective_element, effective_action,
7388 g = &graphic_info[graphic];
7398 if (frame_em == 0) /* reset animation frame for certain elements */
7400 if (check_linear_animation_EM(tile))
7405 if (graphic_info[graphic].anim_global_sync)
7406 sync_frame = FrameCounter;
7407 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7408 sync_frame = GfxFrame[x][y];
7410 sync_frame = 0; /* playfield border (pseudo steel) */
7412 SetRandomAnimationValue(x, y);
7417 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7418 i == Xdrip_stretchB ? 7 :
7419 i == Ydrip_s2 ? j + 8 :
7420 i == Ydrip_s2B ? j + 8 :
7429 i == Xfake_acid_1 ? 0 :
7430 i == Xfake_acid_2 ? 10 :
7431 i == Xfake_acid_3 ? 20 :
7432 i == Xfake_acid_4 ? 30 :
7433 i == Xfake_acid_5 ? 40 :
7434 i == Xfake_acid_6 ? 50 :
7435 i == Xfake_acid_7 ? 60 :
7436 i == Xfake_acid_8 ? 70 :
7438 i == Xball_2B ? j + 8 :
7439 i == Yball_eat ? j + 1 :
7440 i == Ykey_1_eat ? j + 1 :
7441 i == Ykey_2_eat ? j + 1 :
7442 i == Ykey_3_eat ? j + 1 :
7443 i == Ykey_4_eat ? j + 1 :
7444 i == Ykey_5_eat ? j + 1 :
7445 i == Ykey_6_eat ? j + 1 :
7446 i == Ykey_7_eat ? j + 1 :
7447 i == Ykey_8_eat ? j + 1 :
7448 i == Ylenses_eat ? j + 1 :
7449 i == Ymagnify_eat ? j + 1 :
7450 i == Ygrass_eat ? j + 1 :
7451 i == Ydirt_eat ? j + 1 :
7452 i == Xamoeba_1 ? 0 :
7453 i == Xamoeba_2 ? 1 :
7454 i == Xamoeba_3 ? 2 :
7455 i == Xamoeba_4 ? 3 :
7456 i == Xamoeba_5 ? 0 :
7457 i == Xamoeba_6 ? 1 :
7458 i == Xamoeba_7 ? 2 :
7459 i == Xamoeba_8 ? 3 :
7460 i == Xexit_2 ? j + 8 :
7461 i == Xexit_3 ? j + 16 :
7462 i == Xdynamite_1 ? 0 :
7463 i == Xdynamite_2 ? 8 :
7464 i == Xdynamite_3 ? 16 :
7465 i == Xdynamite_4 ? 24 :
7466 i == Xsand_stonein_1 ? j + 1 :
7467 i == Xsand_stonein_2 ? j + 9 :
7468 i == Xsand_stonein_3 ? j + 17 :
7469 i == Xsand_stonein_4 ? j + 25 :
7470 i == Xsand_stoneout_1 && j == 0 ? 0 :
7471 i == Xsand_stoneout_1 && j == 1 ? 0 :
7472 i == Xsand_stoneout_1 && j == 2 ? 1 :
7473 i == Xsand_stoneout_1 && j == 3 ? 2 :
7474 i == Xsand_stoneout_1 && j == 4 ? 2 :
7475 i == Xsand_stoneout_1 && j == 5 ? 3 :
7476 i == Xsand_stoneout_1 && j == 6 ? 4 :
7477 i == Xsand_stoneout_1 && j == 7 ? 4 :
7478 i == Xsand_stoneout_2 && j == 0 ? 5 :
7479 i == Xsand_stoneout_2 && j == 1 ? 6 :
7480 i == Xsand_stoneout_2 && j == 2 ? 7 :
7481 i == Xsand_stoneout_2 && j == 3 ? 8 :
7482 i == Xsand_stoneout_2 && j == 4 ? 9 :
7483 i == Xsand_stoneout_2 && j == 5 ? 11 :
7484 i == Xsand_stoneout_2 && j == 6 ? 13 :
7485 i == Xsand_stoneout_2 && j == 7 ? 15 :
7486 i == Xboom_bug && j == 1 ? 2 :
7487 i == Xboom_bug && j == 2 ? 2 :
7488 i == Xboom_bug && j == 3 ? 4 :
7489 i == Xboom_bug && j == 4 ? 4 :
7490 i == Xboom_bug && j == 5 ? 2 :
7491 i == Xboom_bug && j == 6 ? 2 :
7492 i == Xboom_bug && j == 7 ? 0 :
7493 i == Xboom_bomb && j == 1 ? 2 :
7494 i == Xboom_bomb && j == 2 ? 2 :
7495 i == Xboom_bomb && j == 3 ? 4 :
7496 i == Xboom_bomb && j == 4 ? 4 :
7497 i == Xboom_bomb && j == 5 ? 2 :
7498 i == Xboom_bomb && j == 6 ? 2 :
7499 i == Xboom_bomb && j == 7 ? 0 :
7500 i == Xboom_android && j == 7 ? 6 :
7501 i == Xboom_1 && j == 1 ? 2 :
7502 i == Xboom_1 && j == 2 ? 2 :
7503 i == Xboom_1 && j == 3 ? 4 :
7504 i == Xboom_1 && j == 4 ? 4 :
7505 i == Xboom_1 && j == 5 ? 6 :
7506 i == Xboom_1 && j == 6 ? 6 :
7507 i == Xboom_1 && j == 7 ? 8 :
7508 i == Xboom_2 && j == 0 ? 8 :
7509 i == Xboom_2 && j == 1 ? 8 :
7510 i == Xboom_2 && j == 2 ? 10 :
7511 i == Xboom_2 && j == 3 ? 10 :
7512 i == Xboom_2 && j == 4 ? 10 :
7513 i == Xboom_2 && j == 5 ? 12 :
7514 i == Xboom_2 && j == 6 ? 12 :
7515 i == Xboom_2 && j == 7 ? 12 :
7517 special_animation && j == 4 ? 3 :
7518 effective_action != action ? 0 :
7524 int xxx_effective_action;
7525 int xxx_has_action_graphics;
7528 int element = object_mapping[i].element_rnd;
7529 int action = object_mapping[i].action;
7530 int direction = object_mapping[i].direction;
7531 boolean is_backside = object_mapping[i].is_backside;
7533 boolean action_removing = (action == ACTION_DIGGING ||
7534 action == ACTION_SNAPPING ||
7535 action == ACTION_COLLECTING);
7537 boolean action_exploding = ((action == ACTION_EXPLODING ||
7538 action == ACTION_SMASHED_BY_ROCK ||
7539 action == ACTION_SMASHED_BY_SPRING) &&
7540 element != EL_DIAMOND);
7541 boolean action_active = (action == ACTION_ACTIVE);
7542 boolean action_other = (action == ACTION_OTHER);
7546 int effective_element = get_effective_element_EM(i, j);
7548 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7549 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7551 i == Xdrip_stretch ? element :
7552 i == Xdrip_stretchB ? element :
7553 i == Ydrip_s1 ? element :
7554 i == Ydrip_s1B ? element :
7555 i == Xball_1B ? element :
7556 i == Xball_2 ? element :
7557 i == Xball_2B ? element :
7558 i == Yball_eat ? element :
7559 i == Ykey_1_eat ? element :
7560 i == Ykey_2_eat ? element :
7561 i == Ykey_3_eat ? element :
7562 i == Ykey_4_eat ? element :
7563 i == Ykey_5_eat ? element :
7564 i == Ykey_6_eat ? element :
7565 i == Ykey_7_eat ? element :
7566 i == Ykey_8_eat ? element :
7567 i == Ylenses_eat ? element :
7568 i == Ymagnify_eat ? element :
7569 i == Ygrass_eat ? element :
7570 i == Ydirt_eat ? element :
7571 i == Yemerald_stone ? EL_EMERALD :
7572 i == Ydiamond_stone ? EL_ROCK :
7573 i == Xsand_stonein_1 ? element :
7574 i == Xsand_stonein_2 ? element :
7575 i == Xsand_stonein_3 ? element :
7576 i == Xsand_stonein_4 ? element :
7577 is_backside ? EL_EMPTY :
7578 action_removing ? EL_EMPTY :
7581 int effective_action = (j < 7 ? action :
7582 i == Xdrip_stretch ? action :
7583 i == Xdrip_stretchB ? action :
7584 i == Ydrip_s1 ? action :
7585 i == Ydrip_s1B ? action :
7586 i == Xball_1B ? action :
7587 i == Xball_2 ? action :
7588 i == Xball_2B ? action :
7589 i == Yball_eat ? action :
7590 i == Ykey_1_eat ? action :
7591 i == Ykey_2_eat ? action :
7592 i == Ykey_3_eat ? action :
7593 i == Ykey_4_eat ? action :
7594 i == Ykey_5_eat ? action :
7595 i == Ykey_6_eat ? action :
7596 i == Ykey_7_eat ? action :
7597 i == Ykey_8_eat ? action :
7598 i == Ylenses_eat ? action :
7599 i == Ymagnify_eat ? action :
7600 i == Ygrass_eat ? action :
7601 i == Ydirt_eat ? action :
7602 i == Xsand_stonein_1 ? action :
7603 i == Xsand_stonein_2 ? action :
7604 i == Xsand_stonein_3 ? action :
7605 i == Xsand_stonein_4 ? action :
7606 i == Xsand_stoneout_1 ? action :
7607 i == Xsand_stoneout_2 ? action :
7608 i == Xboom_android ? ACTION_EXPLODING :
7609 action_exploding ? ACTION_EXPLODING :
7610 action_active ? action :
7611 action_other ? action :
7613 int graphic = (el_act_dir2img(effective_element, effective_action,
7615 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7617 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7618 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7619 boolean has_action_graphics = (graphic != base_graphic);
7620 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7621 struct GraphicInfo *g = &graphic_info[graphic];
7623 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7625 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7628 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7629 boolean special_animation = (action != ACTION_DEFAULT &&
7630 g->anim_frames == 3 &&
7631 g->anim_delay == 2 &&
7632 g->anim_mode & ANIM_LINEAR);
7633 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7634 i == Xdrip_stretchB ? 7 :
7635 i == Ydrip_s2 ? j + 8 :
7636 i == Ydrip_s2B ? j + 8 :
7645 i == Xfake_acid_1 ? 0 :
7646 i == Xfake_acid_2 ? 10 :
7647 i == Xfake_acid_3 ? 20 :
7648 i == Xfake_acid_4 ? 30 :
7649 i == Xfake_acid_5 ? 40 :
7650 i == Xfake_acid_6 ? 50 :
7651 i == Xfake_acid_7 ? 60 :
7652 i == Xfake_acid_8 ? 70 :
7654 i == Xball_2B ? j + 8 :
7655 i == Yball_eat ? j + 1 :
7656 i == Ykey_1_eat ? j + 1 :
7657 i == Ykey_2_eat ? j + 1 :
7658 i == Ykey_3_eat ? j + 1 :
7659 i == Ykey_4_eat ? j + 1 :
7660 i == Ykey_5_eat ? j + 1 :
7661 i == Ykey_6_eat ? j + 1 :
7662 i == Ykey_7_eat ? j + 1 :
7663 i == Ykey_8_eat ? j + 1 :
7664 i == Ylenses_eat ? j + 1 :
7665 i == Ymagnify_eat ? j + 1 :
7666 i == Ygrass_eat ? j + 1 :
7667 i == Ydirt_eat ? j + 1 :
7668 i == Xamoeba_1 ? 0 :
7669 i == Xamoeba_2 ? 1 :
7670 i == Xamoeba_3 ? 2 :
7671 i == Xamoeba_4 ? 3 :
7672 i == Xamoeba_5 ? 0 :
7673 i == Xamoeba_6 ? 1 :
7674 i == Xamoeba_7 ? 2 :
7675 i == Xamoeba_8 ? 3 :
7676 i == Xexit_2 ? j + 8 :
7677 i == Xexit_3 ? j + 16 :
7678 i == Xdynamite_1 ? 0 :
7679 i == Xdynamite_2 ? 8 :
7680 i == Xdynamite_3 ? 16 :
7681 i == Xdynamite_4 ? 24 :
7682 i == Xsand_stonein_1 ? j + 1 :
7683 i == Xsand_stonein_2 ? j + 9 :
7684 i == Xsand_stonein_3 ? j + 17 :
7685 i == Xsand_stonein_4 ? j + 25 :
7686 i == Xsand_stoneout_1 && j == 0 ? 0 :
7687 i == Xsand_stoneout_1 && j == 1 ? 0 :
7688 i == Xsand_stoneout_1 && j == 2 ? 1 :
7689 i == Xsand_stoneout_1 && j == 3 ? 2 :
7690 i == Xsand_stoneout_1 && j == 4 ? 2 :
7691 i == Xsand_stoneout_1 && j == 5 ? 3 :
7692 i == Xsand_stoneout_1 && j == 6 ? 4 :
7693 i == Xsand_stoneout_1 && j == 7 ? 4 :
7694 i == Xsand_stoneout_2 && j == 0 ? 5 :
7695 i == Xsand_stoneout_2 && j == 1 ? 6 :
7696 i == Xsand_stoneout_2 && j == 2 ? 7 :
7697 i == Xsand_stoneout_2 && j == 3 ? 8 :
7698 i == Xsand_stoneout_2 && j == 4 ? 9 :
7699 i == Xsand_stoneout_2 && j == 5 ? 11 :
7700 i == Xsand_stoneout_2 && j == 6 ? 13 :
7701 i == Xsand_stoneout_2 && j == 7 ? 15 :
7702 i == Xboom_bug && j == 1 ? 2 :
7703 i == Xboom_bug && j == 2 ? 2 :
7704 i == Xboom_bug && j == 3 ? 4 :
7705 i == Xboom_bug && j == 4 ? 4 :
7706 i == Xboom_bug && j == 5 ? 2 :
7707 i == Xboom_bug && j == 6 ? 2 :
7708 i == Xboom_bug && j == 7 ? 0 :
7709 i == Xboom_bomb && j == 1 ? 2 :
7710 i == Xboom_bomb && j == 2 ? 2 :
7711 i == Xboom_bomb && j == 3 ? 4 :
7712 i == Xboom_bomb && j == 4 ? 4 :
7713 i == Xboom_bomb && j == 5 ? 2 :
7714 i == Xboom_bomb && j == 6 ? 2 :
7715 i == Xboom_bomb && j == 7 ? 0 :
7716 i == Xboom_android && j == 7 ? 6 :
7717 i == Xboom_1 && j == 1 ? 2 :
7718 i == Xboom_1 && j == 2 ? 2 :
7719 i == Xboom_1 && j == 3 ? 4 :
7720 i == Xboom_1 && j == 4 ? 4 :
7721 i == Xboom_1 && j == 5 ? 6 :
7722 i == Xboom_1 && j == 6 ? 6 :
7723 i == Xboom_1 && j == 7 ? 8 :
7724 i == Xboom_2 && j == 0 ? 8 :
7725 i == Xboom_2 && j == 1 ? 8 :
7726 i == Xboom_2 && j == 2 ? 10 :
7727 i == Xboom_2 && j == 3 ? 10 :
7728 i == Xboom_2 && j == 4 ? 10 :
7729 i == Xboom_2 && j == 5 ? 12 :
7730 i == Xboom_2 && j == 6 ? 12 :
7731 i == Xboom_2 && j == 7 ? 12 :
7732 special_animation && j == 4 ? 3 :
7733 effective_action != action ? 0 :
7736 xxx_effective_action = effective_action;
7737 xxx_has_action_graphics = has_action_graphics;
7742 int frame = getAnimationFrame(g->anim_frames,
7745 g->anim_start_frame,
7759 int old_src_x = g_em->src_x;
7760 int old_src_y = g_em->src_y;
7764 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7765 g->double_movement && is_backside);
7767 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7768 &g_em->src_x, &g_em->src_y, FALSE);
7773 if (tile == Ydiamond_stone)
7774 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
7779 g->anim_start_frame,
7782 g_em->src_x, g_em->src_y,
7783 g_em->src_offset_x, g_em->src_offset_y,
7784 g_em->dst_offset_x, g_em->dst_offset_y,
7796 if (graphic == IMG_BUG_MOVING_RIGHT)
7797 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7798 g->double_movement, is_backside,
7799 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7807 g_em->src_offset_x = 0;
7808 g_em->src_offset_y = 0;
7809 g_em->dst_offset_x = 0;
7810 g_em->dst_offset_y = 0;
7811 g_em->width = TILEX;
7812 g_em->height = TILEY;
7814 g_em->preserve_background = FALSE;
7817 /* (updating the "crumbled" graphic definitions is probably not really needed,
7818 as animations for crumbled graphics can't be longer than one EMC cycle) */
7820 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7825 g_em->crumbled_bitmap = NULL;
7826 g_em->crumbled_src_x = 0;
7827 g_em->crumbled_src_y = 0;
7829 g_em->has_crumbled_graphics = FALSE;
7831 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7833 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7834 g_crumbled->anim_delay,
7835 g_crumbled->anim_mode,
7836 g_crumbled->anim_start_frame,
7839 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7840 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7842 g_em->has_crumbled_graphics = TRUE;
7848 int effective_action = xxx_effective_action;
7849 int has_action_graphics = xxx_has_action_graphics;
7851 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7852 effective_action == ACTION_MOVING ||
7853 effective_action == ACTION_PUSHING ||
7854 effective_action == ACTION_EATING)) ||
7855 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7856 effective_action == ACTION_EMPTYING)))
7859 (effective_action == ACTION_FALLING ||
7860 effective_action == ACTION_FILLING ||
7861 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7862 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7863 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7864 int num_steps = (i == Ydrip_s1 ? 16 :
7865 i == Ydrip_s1B ? 16 :
7866 i == Ydrip_s2 ? 16 :
7867 i == Ydrip_s2B ? 16 :
7868 i == Xsand_stonein_1 ? 32 :
7869 i == Xsand_stonein_2 ? 32 :
7870 i == Xsand_stonein_3 ? 32 :
7871 i == Xsand_stonein_4 ? 32 :
7872 i == Xsand_stoneout_1 ? 16 :
7873 i == Xsand_stoneout_2 ? 16 : 8);
7874 int cx = ABS(dx) * (TILEX / num_steps);
7875 int cy = ABS(dy) * (TILEY / num_steps);
7876 int step_frame = (i == Ydrip_s2 ? j + 8 :
7877 i == Ydrip_s2B ? j + 8 :
7878 i == Xsand_stonein_2 ? j + 8 :
7879 i == Xsand_stonein_3 ? j + 16 :
7880 i == Xsand_stonein_4 ? j + 24 :
7881 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7882 int step = (is_backside ? step_frame : num_steps - step_frame);
7884 if (is_backside) /* tile where movement starts */
7886 if (dx < 0 || dy < 0)
7888 g_em->src_offset_x = cx * step;
7889 g_em->src_offset_y = cy * step;
7893 g_em->dst_offset_x = cx * step;
7894 g_em->dst_offset_y = cy * step;
7897 else /* tile where movement ends */
7899 if (dx < 0 || dy < 0)
7901 g_em->dst_offset_x = cx * step;
7902 g_em->dst_offset_y = cy * step;
7906 g_em->src_offset_x = cx * step;
7907 g_em->src_offset_y = cy * step;
7911 g_em->width = TILEX - cx * step;
7912 g_em->height = TILEY - cy * step;
7915 /* create unique graphic identifier to decide if tile must be redrawn */
7916 /* bit 31 - 16 (16 bit): EM style graphic
7917 bit 15 - 12 ( 4 bit): EM style frame
7918 bit 11 - 6 ( 6 bit): graphic width
7919 bit 5 - 0 ( 6 bit): graphic height */
7920 g_em->unique_identifier =
7921 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7927 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7928 int player_nr, int anim, int frame_em)
7930 int element = player_mapping[player_nr][anim].element_rnd;
7931 int action = player_mapping[player_nr][anim].action;
7932 int direction = player_mapping[player_nr][anim].direction;
7933 int graphic = (direction == MV_NONE ?
7934 el_act2img(element, action) :
7935 el_act_dir2img(element, action, direction));
7936 struct GraphicInfo *g = &graphic_info[graphic];
7939 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7941 stored_player[player_nr].StepFrame = frame_em;
7943 sync_frame = stored_player[player_nr].Frame;
7945 int frame = getAnimationFrame(g->anim_frames,
7948 g->anim_start_frame,
7951 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7952 &g_em->src_x, &g_em->src_y, FALSE);
7955 printf("::: %d: %d, %d [%d]\n",
7957 stored_player[player_nr].Frame,
7958 stored_player[player_nr].StepFrame,
7963 void InitGraphicInfo_EM(void)
7966 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7967 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7972 int num_em_gfx_errors = 0;
7974 if (graphic_info_em_object[0][0].bitmap == NULL)
7976 /* EM graphics not yet initialized in em_open_all() */
7981 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7984 /* always start with reliable default values */
7985 for (i = 0; i < TILE_MAX; i++)
7987 object_mapping[i].element_rnd = EL_UNKNOWN;
7988 object_mapping[i].is_backside = FALSE;
7989 object_mapping[i].action = ACTION_DEFAULT;
7990 object_mapping[i].direction = MV_NONE;
7993 /* always start with reliable default values */
7994 for (p = 0; p < MAX_PLAYERS; p++)
7996 for (i = 0; i < SPR_MAX; i++)
7998 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7999 player_mapping[p][i].action = ACTION_DEFAULT;
8000 player_mapping[p][i].direction = MV_NONE;
8004 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8006 int e = em_object_mapping_list[i].element_em;
8008 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8009 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8011 if (em_object_mapping_list[i].action != -1)
8012 object_mapping[e].action = em_object_mapping_list[i].action;
8014 if (em_object_mapping_list[i].direction != -1)
8015 object_mapping[e].direction =
8016 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8019 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8021 int a = em_player_mapping_list[i].action_em;
8022 int p = em_player_mapping_list[i].player_nr;
8024 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8026 if (em_player_mapping_list[i].action != -1)
8027 player_mapping[p][a].action = em_player_mapping_list[i].action;
8029 if (em_player_mapping_list[i].direction != -1)
8030 player_mapping[p][a].direction =
8031 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8034 for (i = 0; i < TILE_MAX; i++)
8036 int element = object_mapping[i].element_rnd;
8037 int action = object_mapping[i].action;
8038 int direction = object_mapping[i].direction;
8039 boolean is_backside = object_mapping[i].is_backside;
8041 boolean action_removing = (action == ACTION_DIGGING ||
8042 action == ACTION_SNAPPING ||
8043 action == ACTION_COLLECTING);
8045 boolean action_exploding = ((action == ACTION_EXPLODING ||
8046 action == ACTION_SMASHED_BY_ROCK ||
8047 action == ACTION_SMASHED_BY_SPRING) &&
8048 element != EL_DIAMOND);
8049 boolean action_active = (action == ACTION_ACTIVE);
8050 boolean action_other = (action == ACTION_OTHER);
8052 for (j = 0; j < 8; j++)
8055 int effective_element = get_effective_element_EM(i, j);
8057 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
8058 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
8060 i == Xdrip_stretch ? element :
8061 i == Xdrip_stretchB ? element :
8062 i == Ydrip_s1 ? element :
8063 i == Ydrip_s1B ? element :
8064 i == Xball_1B ? element :
8065 i == Xball_2 ? element :
8066 i == Xball_2B ? element :
8067 i == Yball_eat ? element :
8068 i == Ykey_1_eat ? element :
8069 i == Ykey_2_eat ? element :
8070 i == Ykey_3_eat ? element :
8071 i == Ykey_4_eat ? element :
8072 i == Ykey_5_eat ? element :
8073 i == Ykey_6_eat ? element :
8074 i == Ykey_7_eat ? element :
8075 i == Ykey_8_eat ? element :
8076 i == Ylenses_eat ? element :
8077 i == Ymagnify_eat ? element :
8078 i == Ygrass_eat ? element :
8079 i == Ydirt_eat ? element :
8080 i == Yemerald_stone ? EL_EMERALD :
8081 i == Ydiamond_stone ? EL_ROCK :
8082 i == Xsand_stonein_1 ? element :
8083 i == Xsand_stonein_2 ? element :
8084 i == Xsand_stonein_3 ? element :
8085 i == Xsand_stonein_4 ? element :
8086 is_backside ? EL_EMPTY :
8087 action_removing ? EL_EMPTY :
8090 int effective_action = (j < 7 ? action :
8091 i == Xdrip_stretch ? action :
8092 i == Xdrip_stretchB ? action :
8093 i == Ydrip_s1 ? action :
8094 i == Ydrip_s1B ? action :
8095 i == Xball_1B ? action :
8096 i == Xball_2 ? action :
8097 i == Xball_2B ? action :
8098 i == Yball_eat ? action :
8099 i == Ykey_1_eat ? action :
8100 i == Ykey_2_eat ? action :
8101 i == Ykey_3_eat ? action :
8102 i == Ykey_4_eat ? action :
8103 i == Ykey_5_eat ? action :
8104 i == Ykey_6_eat ? action :
8105 i == Ykey_7_eat ? action :
8106 i == Ykey_8_eat ? action :
8107 i == Ylenses_eat ? action :
8108 i == Ymagnify_eat ? action :
8109 i == Ygrass_eat ? action :
8110 i == Ydirt_eat ? action :
8111 i == Xsand_stonein_1 ? action :
8112 i == Xsand_stonein_2 ? action :
8113 i == Xsand_stonein_3 ? action :
8114 i == Xsand_stonein_4 ? action :
8115 i == Xsand_stoneout_1 ? action :
8116 i == Xsand_stoneout_2 ? action :
8117 i == Xboom_android ? ACTION_EXPLODING :
8118 action_exploding ? ACTION_EXPLODING :
8119 action_active ? action :
8120 action_other ? action :
8122 int graphic = (el_act_dir2img(effective_element, effective_action,
8124 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8126 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8127 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8128 boolean has_action_graphics = (graphic != base_graphic);
8129 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8130 struct GraphicInfo *g = &graphic_info[graphic];
8132 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8134 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8137 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8138 boolean special_animation = (action != ACTION_DEFAULT &&
8139 g->anim_frames == 3 &&
8140 g->anim_delay == 2 &&
8141 g->anim_mode & ANIM_LINEAR);
8142 int sync_frame = (i == Xdrip_stretch ? 7 :
8143 i == Xdrip_stretchB ? 7 :
8144 i == Ydrip_s2 ? j + 8 :
8145 i == Ydrip_s2B ? j + 8 :
8154 i == Xfake_acid_1 ? 0 :
8155 i == Xfake_acid_2 ? 10 :
8156 i == Xfake_acid_3 ? 20 :
8157 i == Xfake_acid_4 ? 30 :
8158 i == Xfake_acid_5 ? 40 :
8159 i == Xfake_acid_6 ? 50 :
8160 i == Xfake_acid_7 ? 60 :
8161 i == Xfake_acid_8 ? 70 :
8163 i == Xball_2B ? j + 8 :
8164 i == Yball_eat ? j + 1 :
8165 i == Ykey_1_eat ? j + 1 :
8166 i == Ykey_2_eat ? j + 1 :
8167 i == Ykey_3_eat ? j + 1 :
8168 i == Ykey_4_eat ? j + 1 :
8169 i == Ykey_5_eat ? j + 1 :
8170 i == Ykey_6_eat ? j + 1 :
8171 i == Ykey_7_eat ? j + 1 :
8172 i == Ykey_8_eat ? j + 1 :
8173 i == Ylenses_eat ? j + 1 :
8174 i == Ymagnify_eat ? j + 1 :
8175 i == Ygrass_eat ? j + 1 :
8176 i == Ydirt_eat ? j + 1 :
8177 i == Xamoeba_1 ? 0 :
8178 i == Xamoeba_2 ? 1 :
8179 i == Xamoeba_3 ? 2 :
8180 i == Xamoeba_4 ? 3 :
8181 i == Xamoeba_5 ? 0 :
8182 i == Xamoeba_6 ? 1 :
8183 i == Xamoeba_7 ? 2 :
8184 i == Xamoeba_8 ? 3 :
8185 i == Xexit_2 ? j + 8 :
8186 i == Xexit_3 ? j + 16 :
8187 i == Xdynamite_1 ? 0 :
8188 i == Xdynamite_2 ? 8 :
8189 i == Xdynamite_3 ? 16 :
8190 i == Xdynamite_4 ? 24 :
8191 i == Xsand_stonein_1 ? j + 1 :
8192 i == Xsand_stonein_2 ? j + 9 :
8193 i == Xsand_stonein_3 ? j + 17 :
8194 i == Xsand_stonein_4 ? j + 25 :
8195 i == Xsand_stoneout_1 && j == 0 ? 0 :
8196 i == Xsand_stoneout_1 && j == 1 ? 0 :
8197 i == Xsand_stoneout_1 && j == 2 ? 1 :
8198 i == Xsand_stoneout_1 && j == 3 ? 2 :
8199 i == Xsand_stoneout_1 && j == 4 ? 2 :
8200 i == Xsand_stoneout_1 && j == 5 ? 3 :
8201 i == Xsand_stoneout_1 && j == 6 ? 4 :
8202 i == Xsand_stoneout_1 && j == 7 ? 4 :
8203 i == Xsand_stoneout_2 && j == 0 ? 5 :
8204 i == Xsand_stoneout_2 && j == 1 ? 6 :
8205 i == Xsand_stoneout_2 && j == 2 ? 7 :
8206 i == Xsand_stoneout_2 && j == 3 ? 8 :
8207 i == Xsand_stoneout_2 && j == 4 ? 9 :
8208 i == Xsand_stoneout_2 && j == 5 ? 11 :
8209 i == Xsand_stoneout_2 && j == 6 ? 13 :
8210 i == Xsand_stoneout_2 && j == 7 ? 15 :
8211 i == Xboom_bug && j == 1 ? 2 :
8212 i == Xboom_bug && j == 2 ? 2 :
8213 i == Xboom_bug && j == 3 ? 4 :
8214 i == Xboom_bug && j == 4 ? 4 :
8215 i == Xboom_bug && j == 5 ? 2 :
8216 i == Xboom_bug && j == 6 ? 2 :
8217 i == Xboom_bug && j == 7 ? 0 :
8218 i == Xboom_bomb && j == 1 ? 2 :
8219 i == Xboom_bomb && j == 2 ? 2 :
8220 i == Xboom_bomb && j == 3 ? 4 :
8221 i == Xboom_bomb && j == 4 ? 4 :
8222 i == Xboom_bomb && j == 5 ? 2 :
8223 i == Xboom_bomb && j == 6 ? 2 :
8224 i == Xboom_bomb && j == 7 ? 0 :
8225 i == Xboom_android && j == 7 ? 6 :
8226 i == Xboom_1 && j == 1 ? 2 :
8227 i == Xboom_1 && j == 2 ? 2 :
8228 i == Xboom_1 && j == 3 ? 4 :
8229 i == Xboom_1 && j == 4 ? 4 :
8230 i == Xboom_1 && j == 5 ? 6 :
8231 i == Xboom_1 && j == 6 ? 6 :
8232 i == Xboom_1 && j == 7 ? 8 :
8233 i == Xboom_2 && j == 0 ? 8 :
8234 i == Xboom_2 && j == 1 ? 8 :
8235 i == Xboom_2 && j == 2 ? 10 :
8236 i == Xboom_2 && j == 3 ? 10 :
8237 i == Xboom_2 && j == 4 ? 10 :
8238 i == Xboom_2 && j == 5 ? 12 :
8239 i == Xboom_2 && j == 6 ? 12 :
8240 i == Xboom_2 && j == 7 ? 12 :
8241 special_animation && j == 4 ? 3 :
8242 effective_action != action ? 0 :
8246 Bitmap *debug_bitmap = g_em->bitmap;
8247 int debug_src_x = g_em->src_x;
8248 int debug_src_y = g_em->src_y;
8251 int frame = getAnimationFrame(g->anim_frames,
8254 g->anim_start_frame,
8257 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8258 g->double_movement && is_backside);
8260 g_em->bitmap = src_bitmap;
8261 g_em->src_x = src_x;
8262 g_em->src_y = src_y;
8263 g_em->src_offset_x = 0;
8264 g_em->src_offset_y = 0;
8265 g_em->dst_offset_x = 0;
8266 g_em->dst_offset_y = 0;
8267 g_em->width = TILEX;
8268 g_em->height = TILEY;
8270 g_em->preserve_background = FALSE;
8273 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8278 g_em->crumbled_bitmap = NULL;
8279 g_em->crumbled_src_x = 0;
8280 g_em->crumbled_src_y = 0;
8281 g_em->crumbled_border_size = 0;
8283 g_em->has_crumbled_graphics = FALSE;
8286 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
8287 printf("::: empty crumbled: %d [%s], %d, %d\n",
8288 effective_element, element_info[effective_element].token_name,
8289 effective_action, direction);
8292 /* if element can be crumbled, but certain action graphics are just empty
8293 space (like instantly snapping sand to empty space in 1 frame), do not
8294 treat these empty space graphics as crumbled graphics in EMC engine */
8295 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8297 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8298 g_crumbled->anim_delay,
8299 g_crumbled->anim_mode,
8300 g_crumbled->anim_start_frame,
8303 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8305 g_em->has_crumbled_graphics = TRUE;
8306 g_em->crumbled_bitmap = src_bitmap;
8307 g_em->crumbled_src_x = src_x;
8308 g_em->crumbled_src_y = src_y;
8309 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8313 if (g_em == &graphic_info_em_object[207][0])
8314 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8315 graphic_info_em_object[207][0].crumbled_src_x,
8316 graphic_info_em_object[207][0].crumbled_src_y,
8318 crumbled, frame, src_x, src_y,
8323 g->anim_start_frame,
8325 gfx.anim_random_frame,
8330 printf("::: EMC tile %d is crumbled\n", i);
8336 if (element == EL_ROCK &&
8337 effective_action == ACTION_FILLING)
8338 printf("::: has_action_graphics == %d\n", has_action_graphics);
8341 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8342 effective_action == ACTION_MOVING ||
8343 effective_action == ACTION_PUSHING ||
8344 effective_action == ACTION_EATING)) ||
8345 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8346 effective_action == ACTION_EMPTYING)))
8349 (effective_action == ACTION_FALLING ||
8350 effective_action == ACTION_FILLING ||
8351 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8352 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8353 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8354 int num_steps = (i == Ydrip_s1 ? 16 :
8355 i == Ydrip_s1B ? 16 :
8356 i == Ydrip_s2 ? 16 :
8357 i == Ydrip_s2B ? 16 :
8358 i == Xsand_stonein_1 ? 32 :
8359 i == Xsand_stonein_2 ? 32 :
8360 i == Xsand_stonein_3 ? 32 :
8361 i == Xsand_stonein_4 ? 32 :
8362 i == Xsand_stoneout_1 ? 16 :
8363 i == Xsand_stoneout_2 ? 16 : 8);
8364 int cx = ABS(dx) * (TILEX / num_steps);
8365 int cy = ABS(dy) * (TILEY / num_steps);
8366 int step_frame = (i == Ydrip_s2 ? j + 8 :
8367 i == Ydrip_s2B ? j + 8 :
8368 i == Xsand_stonein_2 ? j + 8 :
8369 i == Xsand_stonein_3 ? j + 16 :
8370 i == Xsand_stonein_4 ? j + 24 :
8371 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8372 int step = (is_backside ? step_frame : num_steps - step_frame);
8374 if (is_backside) /* tile where movement starts */
8376 if (dx < 0 || dy < 0)
8378 g_em->src_offset_x = cx * step;
8379 g_em->src_offset_y = cy * step;
8383 g_em->dst_offset_x = cx * step;
8384 g_em->dst_offset_y = cy * step;
8387 else /* tile where movement ends */
8389 if (dx < 0 || dy < 0)
8391 g_em->dst_offset_x = cx * step;
8392 g_em->dst_offset_y = cy * step;
8396 g_em->src_offset_x = cx * step;
8397 g_em->src_offset_y = cy * step;
8401 g_em->width = TILEX - cx * step;
8402 g_em->height = TILEY - cy * step;
8405 /* create unique graphic identifier to decide if tile must be redrawn */
8406 /* bit 31 - 16 (16 bit): EM style graphic
8407 bit 15 - 12 ( 4 bit): EM style frame
8408 bit 11 - 6 ( 6 bit): graphic width
8409 bit 5 - 0 ( 6 bit): graphic height */
8410 g_em->unique_identifier =
8411 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8415 /* skip check for EMC elements not contained in original EMC artwork */
8416 if (element == EL_EMC_FAKE_ACID)
8419 if (g_em->bitmap != debug_bitmap ||
8420 g_em->src_x != debug_src_x ||
8421 g_em->src_y != debug_src_y ||
8422 g_em->src_offset_x != 0 ||
8423 g_em->src_offset_y != 0 ||
8424 g_em->dst_offset_x != 0 ||
8425 g_em->dst_offset_y != 0 ||
8426 g_em->width != TILEX ||
8427 g_em->height != TILEY)
8429 static int last_i = -1;
8437 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8438 i, element, element_info[element].token_name,
8439 element_action_info[effective_action].suffix, direction);
8441 if (element != effective_element)
8442 printf(" [%d ('%s')]",
8444 element_info[effective_element].token_name);
8448 if (g_em->bitmap != debug_bitmap)
8449 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8450 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8452 if (g_em->src_x != debug_src_x ||
8453 g_em->src_y != debug_src_y)
8454 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8455 j, (is_backside ? 'B' : 'F'),
8456 g_em->src_x, g_em->src_y,
8457 g_em->src_x / 32, g_em->src_y / 32,
8458 debug_src_x, debug_src_y,
8459 debug_src_x / 32, debug_src_y / 32);
8461 if (g_em->src_offset_x != 0 ||
8462 g_em->src_offset_y != 0 ||
8463 g_em->dst_offset_x != 0 ||
8464 g_em->dst_offset_y != 0)
8465 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8467 g_em->src_offset_x, g_em->src_offset_y,
8468 g_em->dst_offset_x, g_em->dst_offset_y);
8470 if (g_em->width != TILEX ||
8471 g_em->height != TILEY)
8472 printf(" %d (%d): size %d,%d should be %d,%d\n",
8474 g_em->width, g_em->height, TILEX, TILEY);
8476 num_em_gfx_errors++;
8483 for (i = 0; i < TILE_MAX; i++)
8485 for (j = 0; j < 8; j++)
8487 int element = object_mapping[i].element_rnd;
8488 int action = object_mapping[i].action;
8489 int direction = object_mapping[i].direction;
8490 boolean is_backside = object_mapping[i].is_backside;
8491 int graphic_action = el_act_dir2img(element, action, direction);
8492 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8494 if ((action == ACTION_SMASHED_BY_ROCK ||
8495 action == ACTION_SMASHED_BY_SPRING ||
8496 action == ACTION_EATING) &&
8497 graphic_action == graphic_default)
8499 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8500 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8501 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8502 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8505 /* no separate animation for "smashed by rock" -- use rock instead */
8506 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8507 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8509 g_em->bitmap = g_xx->bitmap;
8510 g_em->src_x = g_xx->src_x;
8511 g_em->src_y = g_xx->src_y;
8512 g_em->src_offset_x = g_xx->src_offset_x;
8513 g_em->src_offset_y = g_xx->src_offset_y;
8514 g_em->dst_offset_x = g_xx->dst_offset_x;
8515 g_em->dst_offset_y = g_xx->dst_offset_y;
8516 g_em->width = g_xx->width;
8517 g_em->height = g_xx->height;
8518 g_em->unique_identifier = g_xx->unique_identifier;
8521 g_em->preserve_background = TRUE;
8526 for (p = 0; p < MAX_PLAYERS; p++)
8528 for (i = 0; i < SPR_MAX; i++)
8530 int element = player_mapping[p][i].element_rnd;
8531 int action = player_mapping[p][i].action;
8532 int direction = player_mapping[p][i].direction;
8534 for (j = 0; j < 8; j++)
8536 int effective_element = element;
8537 int effective_action = action;
8538 int graphic = (direction == MV_NONE ?
8539 el_act2img(effective_element, effective_action) :
8540 el_act_dir2img(effective_element, effective_action,
8542 struct GraphicInfo *g = &graphic_info[graphic];
8543 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8549 Bitmap *debug_bitmap = g_em->bitmap;
8550 int debug_src_x = g_em->src_x;
8551 int debug_src_y = g_em->src_y;
8554 int frame = getAnimationFrame(g->anim_frames,
8557 g->anim_start_frame,
8560 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8562 g_em->bitmap = src_bitmap;
8563 g_em->src_x = src_x;
8564 g_em->src_y = src_y;
8565 g_em->src_offset_x = 0;
8566 g_em->src_offset_y = 0;
8567 g_em->dst_offset_x = 0;
8568 g_em->dst_offset_y = 0;
8569 g_em->width = TILEX;
8570 g_em->height = TILEY;
8574 /* skip check for EMC elements not contained in original EMC artwork */
8575 if (element == EL_PLAYER_3 ||
8576 element == EL_PLAYER_4)
8579 if (g_em->bitmap != debug_bitmap ||
8580 g_em->src_x != debug_src_x ||
8581 g_em->src_y != debug_src_y)
8583 static int last_i = -1;
8591 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8592 p, i, element, element_info[element].token_name,
8593 element_action_info[effective_action].suffix, direction);
8595 if (element != effective_element)
8596 printf(" [%d ('%s')]",
8598 element_info[effective_element].token_name);
8602 if (g_em->bitmap != debug_bitmap)
8603 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8604 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8606 if (g_em->src_x != debug_src_x ||
8607 g_em->src_y != debug_src_y)
8608 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8610 g_em->src_x, g_em->src_y,
8611 g_em->src_x / 32, g_em->src_y / 32,
8612 debug_src_x, debug_src_y,
8613 debug_src_x / 32, debug_src_y / 32);
8615 num_em_gfx_errors++;
8625 printf("::: [%d errors found]\n", num_em_gfx_errors);
8631 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8632 boolean any_player_moving,
8633 boolean player_is_dropping)
8637 if (tape.single_step && tape.recording && !tape.pausing)
8639 boolean active_players = FALSE;
8641 for (i = 0; i < MAX_PLAYERS; i++)
8642 if (action[i] != JOY_NO_ACTION)
8643 active_players = TRUE;
8646 if (frame == 0 && !player_is_dropping)
8647 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8651 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8652 boolean murphy_is_dropping)
8655 printf("::: waiting: %d, dropping: %d\n",
8656 murphy_is_waiting, murphy_is_dropping);
8659 if (tape.single_step && tape.recording && !tape.pausing)
8661 // if (murphy_is_waiting || murphy_is_dropping)
8662 if (murphy_is_waiting)
8665 printf("::: murphy is waiting -> pause mode\n");
8668 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8673 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8674 int graphic, int sync_frame, int x, int y)
8676 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8678 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8681 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8683 return (IS_NEXT_FRAME(sync_frame, graphic));
8686 int getGraphicInfo_Delay(int graphic)
8688 return graphic_info[graphic].anim_delay;
8691 void PlayMenuSoundExt(int sound)
8693 if (sound == SND_UNDEFINED)
8696 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8697 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8700 if (IS_LOOP_SOUND(sound))
8701 PlaySoundLoop(sound);
8706 void PlayMenuSound()
8708 PlayMenuSoundExt(menu.sound[game_status]);
8711 void PlayMenuSoundStereo(int sound, int stereo_position)
8713 if (sound == SND_UNDEFINED)
8716 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8717 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8720 if (IS_LOOP_SOUND(sound))
8721 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8723 PlaySoundStereo(sound, stereo_position);
8726 void PlayMenuSoundIfLoopExt(int sound)
8728 if (sound == SND_UNDEFINED)
8731 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8732 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8735 if (IS_LOOP_SOUND(sound))
8736 PlaySoundLoop(sound);
8739 void PlayMenuSoundIfLoop()
8741 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8744 void PlayMenuMusicExt(int music)
8746 if (music == MUS_UNDEFINED)
8749 if (!setup.sound_music)
8755 void PlayMenuMusic()
8757 PlayMenuMusicExt(menu.music[game_status]);
8760 void PlaySoundActivating()
8763 PlaySound(SND_MENU_ITEM_ACTIVATING);
8767 void PlaySoundSelecting()
8770 PlaySound(SND_MENU_ITEM_SELECTING);
8774 void ToggleFullscreenIfNeeded()
8776 boolean change_fullscreen = (setup.fullscreen !=
8777 video.fullscreen_enabled);
8778 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8779 !strEqual(setup.fullscreen_mode,
8780 video.fullscreen_mode_current));
8782 if (!video.fullscreen_available)
8785 if (change_fullscreen || change_fullscreen_mode)
8787 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8789 /* save backbuffer content which gets lost when toggling fullscreen mode */
8790 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8792 if (change_fullscreen_mode)
8794 /* keep fullscreen, but change fullscreen mode (screen resolution) */
8795 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
8798 /* toggle fullscreen */
8799 ChangeVideoModeIfNeeded(setup.fullscreen);
8801 setup.fullscreen = video.fullscreen_enabled;
8803 /* restore backbuffer content from temporary backbuffer backup bitmap */
8804 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8806 FreeBitmap(tmp_backbuffer);
8809 /* update visible window/screen */
8810 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8812 redraw_mask = REDRAW_ALL;
8817 void ChangeViewportPropertiesIfNeeded()
8819 int *door_1_x = &DX;
8820 int *door_1_y = &DY;
8821 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
8822 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
8823 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
8824 game_status == GAME_MODE_EDITOR ? game_status :
8826 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8827 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8828 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
8829 int border_size = vp_playfield->border_size;
8830 int new_sx = vp_playfield->x + border_size;
8831 int new_sy = vp_playfield->y + border_size;
8832 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? TILESIZE_VAR :
8833 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8834 int new_sxsize = vp_playfield->width - 2 * border_size;
8835 int new_sysize = vp_playfield->height - 2 * border_size;
8837 int new_scr_fieldx = new_sxsize / tilesize;
8838 int new_scr_fieldy = new_sysize / tilesize;
8840 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
8841 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
8845 /* !!! TEST ONLY !!! */
8846 // InitGfxBuffers();
8850 if (viewport.window.width != WIN_XSIZE ||
8851 viewport.window.height != WIN_YSIZE)
8853 WIN_XSIZE = viewport.window.width;
8854 WIN_YSIZE = viewport.window.height;
8856 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8860 SetDrawDeactivationMask(REDRAW_NONE);
8861 SetDrawBackgroundMask(REDRAW_FIELD);
8863 // RedrawBackground();
8867 if (new_scr_fieldx != SCR_FIELDX ||
8868 new_scr_fieldy != SCR_FIELDY ||
8871 vp_playfield->x != REAL_SX ||
8872 vp_playfield->y != REAL_SY ||
8873 vp_door_1->x != *door_1_x ||
8874 vp_door_1->y != *door_1_y ||
8875 vp_door_2->x != *door_2_x ||
8876 vp_door_2->y != *door_2_y)
8878 SCR_FIELDX = new_scr_fieldx;
8879 SCR_FIELDY = new_scr_fieldy;
8882 REAL_SX = vp_playfield->x;
8883 REAL_SY = vp_playfield->y;
8885 SXSIZE = new_sxsize;
8886 SYSIZE = new_sysize;
8887 FULL_SXSIZE = vp_playfield->width;
8888 FULL_SYSIZE = vp_playfield->width;
8890 *door_1_x = vp_door_1->x;
8891 *door_1_y = vp_door_1->y;
8892 *door_2_x = vp_door_2->x;
8893 *door_2_y = vp_door_2->y;
8897 if (gfx_game_mode == GAME_MODE_MAIN)
8905 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);