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;
3667 global.use_envelope_request = 0;
3671 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3673 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3674 font_nr = FONT_TEXT_1;
3677 for (text_ptr = text; *text_ptr; text_ptr++)
3679 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3681 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3683 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3685 font_nr = FONT_TEXT_1;
3687 font_nr = FONT_LEVEL_NUMBER;
3695 if (game_status == GAME_MODE_PLAYING)
3697 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3698 BlitScreenToBitmap_EM(backbuffer);
3699 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3700 BlitScreenToBitmap_SP(backbuffer);
3703 /* disable deactivated drawing when quick-loading level tape recording */
3704 if (tape.playing && tape.deactivate_display)
3705 TapeDeactivateDisplayOff(TRUE);
3707 SetMouseCursor(CURSOR_DEFAULT);
3709 #if defined(NETWORK_AVALIABLE)
3710 /* pause network game while waiting for request to answer */
3711 if (options.network &&
3712 game_status == GAME_MODE_PLAYING &&
3713 req_state & REQUEST_WAIT_FOR_INPUT)
3714 SendToServer_PausePlaying();
3717 old_door_state = GetDoorState();
3719 /* simulate releasing mouse button over last gadget, if still pressed */
3721 HandleGadgets(-1, -1, 0);
3725 /* draw released gadget before proceeding */
3729 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
3731 if (old_door_state & DOOR_OPEN_1)
3735 if (!global.use_envelope_request)
3736 CloseDoor(DOOR_CLOSE_1);
3738 CloseDoor(DOOR_CLOSE_1);
3741 /* save old door content */
3742 BlitBitmap(bitmap_db_door, bitmap_db_door,
3743 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3744 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3748 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3751 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3753 /* clear door drawing field */
3754 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3756 /* force DOOR font inside door area */
3757 game_status = GAME_MODE_PSEUDO_DOOR;
3759 /* write text for request */
3760 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3762 char text_line[max_request_line_len + 1];
3768 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3770 tc = *(text_ptr + tx);
3771 if (!tc || tc == ' ')
3782 strncpy(text_line, text_ptr, tl);
3785 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3786 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3787 text_line, font_nr);
3789 text_ptr += tl + (tc == ' ' ? 1 : 0);
3792 game_status = last_game_status; /* restore current game status */
3795 if (global.use_envelope_request)
3799 CreateToolButtons();
3803 if (req_state & REQ_ASK)
3805 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3806 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3808 else if (req_state & REQ_CONFIRM)
3810 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3812 else if (req_state & REQ_PLAYER)
3814 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3815 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3816 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3817 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3820 /* copy request gadgets to door backbuffer */
3821 BlitBitmap(drawto, bitmap_db_door,
3822 DX, DY, DXSIZE, DYSIZE,
3823 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3826 if (global.use_envelope_request)
3828 ShowEnvelopeDoor(text, ACTION_OPENING);
3830 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3832 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
3833 i == TOOL_CTRL_ID_NO)) ||
3834 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
3835 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
3836 i == TOOL_CTRL_ID_PLAYER_2 &&
3837 i == TOOL_CTRL_ID_PLAYER_3 &&
3838 i == TOOL_CTRL_ID_PLAYER_4)))
3840 int x = tool_gadget[i]->x + dDX;
3841 int y = tool_gadget[i]->y + dDY;
3843 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
3850 if (!global.use_envelope_request)
3851 OpenDoor(DOOR_OPEN_1);
3853 OpenDoor(DOOR_OPEN_1);
3856 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3858 if (game_status == GAME_MODE_PLAYING)
3860 SetPanelBackground();
3861 SetDrawBackgroundMask(REDRAW_DOOR_1);
3865 SetDrawBackgroundMask(REDRAW_FIELD);
3872 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
3875 if (game_status != GAME_MODE_MAIN)
3879 button_status = MB_RELEASED;
3881 request_gadget_id = -1;
3883 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3895 case EVENT_BUTTONPRESS:
3896 case EVENT_BUTTONRELEASE:
3897 case EVENT_MOTIONNOTIFY:
3899 if (event.type == EVENT_MOTIONNOTIFY)
3901 if (!PointerInWindow(window))
3902 continue; /* window and pointer are on different screens */
3907 motion_status = TRUE;
3908 mx = ((MotionEvent *) &event)->x;
3909 my = ((MotionEvent *) &event)->y;
3913 motion_status = FALSE;
3914 mx = ((ButtonEvent *) &event)->x;
3915 my = ((ButtonEvent *) &event)->y;
3916 if (event.type == EVENT_BUTTONPRESS)
3917 button_status = ((ButtonEvent *) &event)->button;
3919 button_status = MB_RELEASED;
3922 /* this sets 'request_gadget_id' */
3923 HandleGadgets(mx, my, button_status);
3925 switch (request_gadget_id)
3927 case TOOL_CTRL_ID_YES:
3930 case TOOL_CTRL_ID_NO:
3933 case TOOL_CTRL_ID_CONFIRM:
3934 result = TRUE | FALSE;
3937 case TOOL_CTRL_ID_PLAYER_1:
3940 case TOOL_CTRL_ID_PLAYER_2:
3943 case TOOL_CTRL_ID_PLAYER_3:
3946 case TOOL_CTRL_ID_PLAYER_4:
3957 case EVENT_KEYPRESS:
3958 switch (GetEventKey((KeyEvent *)&event, TRUE))
3961 if (req_state & REQ_CONFIRM)
3977 if (req_state & REQ_PLAYER)
3981 case EVENT_KEYRELEASE:
3982 ClearPlayerAction();
3986 HandleOtherEvents(&event);
3990 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3992 int joy = AnyJoystick();
3994 if (joy & JOY_BUTTON_1)
3996 else if (joy & JOY_BUTTON_2)
4002 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4004 HandleGameActions();
4010 if (!PendingEvent()) /* delay only if no pending events */
4015 game_status = GAME_MODE_PSEUDO_DOOR;
4021 game_status = last_game_status; /* restore current game status */
4029 if (!PendingEvent()) /* delay only if no pending events */
4032 /* don't eat all CPU time */
4039 if (game_status != GAME_MODE_MAIN)
4045 if (global.use_envelope_request)
4046 ShowEnvelopeDoor(text, ACTION_CLOSING);
4050 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
4052 if (!(req_state & REQ_STAY_OPEN))
4055 CloseDoor(DOOR_CLOSE_1);
4057 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4058 (req_state & REQ_REOPEN))
4059 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4064 if (game_status == GAME_MODE_PLAYING)
4066 SetPanelBackground();
4067 SetDrawBackgroundMask(REDRAW_DOOR_1);
4071 SetDrawBackgroundMask(REDRAW_FIELD);
4074 #if defined(NETWORK_AVALIABLE)
4075 /* continue network game after request */
4076 if (options.network &&
4077 game_status == GAME_MODE_PLAYING &&
4078 req_state & REQUEST_WAIT_FOR_INPUT)
4079 SendToServer_ContinuePlaying();
4082 /* restore deactivated drawing when quick-loading level tape recording */
4083 if (tape.playing && tape.deactivate_display)
4084 TapeDeactivateDisplayOn();
4089 unsigned int OpenDoor(unsigned int door_state)
4091 if (door_state & DOOR_COPY_BACK)
4093 if (door_state & DOOR_OPEN_1)
4094 BlitBitmap(bitmap_db_door, bitmap_db_door,
4095 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4096 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4098 if (door_state & DOOR_OPEN_2)
4099 BlitBitmap(bitmap_db_door, bitmap_db_door,
4100 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
4101 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4103 door_state &= ~DOOR_COPY_BACK;
4106 return MoveDoor(door_state);
4109 unsigned int CloseDoor(unsigned int door_state)
4111 unsigned int old_door_state = GetDoorState();
4113 if (!(door_state & DOOR_NO_COPY_BACK))
4115 if (old_door_state & DOOR_OPEN_1)
4116 BlitBitmap(backbuffer, bitmap_db_door,
4117 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4119 if (old_door_state & DOOR_OPEN_2)
4120 BlitBitmap(backbuffer, bitmap_db_door,
4121 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4123 door_state &= ~DOOR_NO_COPY_BACK;
4126 return MoveDoor(door_state);
4129 unsigned int GetDoorState()
4131 return MoveDoor(DOOR_GET_STATE);
4134 unsigned int SetDoorState(unsigned int door_state)
4136 return MoveDoor(door_state | DOOR_SET_STATE);
4139 unsigned int MoveDoor(unsigned int door_state)
4141 static int door1 = DOOR_OPEN_1;
4142 static int door2 = DOOR_CLOSE_2;
4143 unsigned long door_delay = 0;
4144 unsigned long door_delay_value;
4147 if (door_1.width < 0 || door_1.width > DXSIZE)
4148 door_1.width = DXSIZE;
4149 if (door_1.height < 0 || door_1.height > DYSIZE)
4150 door_1.height = DYSIZE;
4151 if (door_2.width < 0 || door_2.width > VXSIZE)
4152 door_2.width = VXSIZE;
4153 if (door_2.height < 0 || door_2.height > VYSIZE)
4154 door_2.height = VYSIZE;
4156 if (door_state == DOOR_GET_STATE)
4157 return (door1 | door2);
4159 if (door_state & DOOR_SET_STATE)
4161 if (door_state & DOOR_ACTION_1)
4162 door1 = door_state & DOOR_ACTION_1;
4163 if (door_state & DOOR_ACTION_2)
4164 door2 = door_state & DOOR_ACTION_2;
4166 return (door1 | door2);
4169 if (!(door_state & DOOR_FORCE_REDRAW))
4171 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4172 door_state &= ~DOOR_OPEN_1;
4173 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4174 door_state &= ~DOOR_CLOSE_1;
4175 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4176 door_state &= ~DOOR_OPEN_2;
4177 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4178 door_state &= ~DOOR_CLOSE_2;
4181 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
4184 if (setup.quick_doors)
4186 stepsize = 20; /* must be chosen to always draw last frame */
4187 door_delay_value = 0;
4190 if (global.autoplay_leveldir)
4192 door_state |= DOOR_NO_DELAY;
4193 door_state &= ~DOOR_CLOSE_ALL;
4197 if (game_status == GAME_MODE_EDITOR)
4198 door_state |= DOOR_NO_DELAY;
4201 if (door_state & DOOR_ACTION)
4203 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
4204 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
4205 boolean door_1_done = (!handle_door_1);
4206 boolean door_2_done = (!handle_door_2);
4207 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
4208 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
4209 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
4210 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
4211 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
4212 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
4213 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
4214 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
4215 int door_skip = max_door_size - door_size;
4216 int end = door_size;
4217 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
4220 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
4222 /* opening door sound has priority over simultaneously closing door */
4223 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4224 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4225 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4226 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4229 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
4232 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4233 GC gc = bitmap->stored_clip_gc;
4235 if (door_state & DOOR_ACTION_1)
4237 int a = MIN(x * door_1.step_offset, end);
4238 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
4239 int i = p + door_skip;
4241 if (door_1.anim_mode & ANIM_STATIC_PANEL)
4243 BlitBitmap(bitmap_db_door, drawto,
4244 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
4245 DXSIZE, DYSIZE, DX, DY);
4249 BlitBitmap(bitmap_db_door, drawto,
4250 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
4251 DXSIZE, DYSIZE - p / 2, DX, DY);
4253 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
4256 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
4258 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4259 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
4260 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
4261 int dst2_x = DX, dst2_y = DY;
4262 int width = i, height = DYSIZE;
4264 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4265 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4268 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4269 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4272 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
4274 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
4275 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
4276 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
4277 int dst2_x = DX, dst2_y = DY;
4278 int width = DXSIZE, height = i;
4280 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4281 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4284 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4285 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4288 else if (x <= DXSIZE) /* ANIM_DEFAULT */
4290 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
4292 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4293 BlitBitmapMasked(bitmap, drawto,
4294 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
4295 DX + DXSIZE - i, DY + j);
4296 BlitBitmapMasked(bitmap, drawto,
4297 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4298 DX + DXSIZE - i, DY + 140 + j);
4299 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4300 DY - (DOOR_GFX_PAGEY1 + j));
4301 BlitBitmapMasked(bitmap, drawto,
4302 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4304 BlitBitmapMasked(bitmap, drawto,
4305 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4308 BlitBitmapMasked(bitmap, drawto,
4309 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4311 BlitBitmapMasked(bitmap, drawto,
4312 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4314 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4315 BlitBitmapMasked(bitmap, drawto,
4316 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4317 DX + DXSIZE - i, DY + 77 + j);
4318 BlitBitmapMasked(bitmap, drawto,
4319 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4320 DX + DXSIZE - i, DY + 203 + j);
4323 redraw_mask |= REDRAW_DOOR_1;
4324 door_1_done = (a == end);
4327 if (door_state & DOOR_ACTION_2)
4329 int a = MIN(x * door_2.step_offset, door_size);
4330 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4331 int i = p + door_skip;
4333 if (door_2.anim_mode & ANIM_STATIC_PANEL)
4335 BlitBitmap(bitmap_db_door, drawto,
4336 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4337 VXSIZE, VYSIZE, VX, VY);
4339 else if (x <= VYSIZE)
4341 BlitBitmap(bitmap_db_door, drawto,
4342 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4343 VXSIZE, VYSIZE - p / 2, VX, VY);
4345 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4348 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4350 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4351 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4352 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
4353 int dst2_x = VX, dst2_y = VY;
4354 int width = i, height = VYSIZE;
4356 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4357 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4360 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4361 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4364 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4366 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
4367 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
4368 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4369 int dst2_x = VX, dst2_y = VY;
4370 int width = VXSIZE, height = i;
4372 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4373 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4376 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4377 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4380 else if (x <= VXSIZE) /* ANIM_DEFAULT */
4382 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4384 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4385 BlitBitmapMasked(bitmap, drawto,
4386 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4387 VX + VXSIZE - i, VY + j);
4388 SetClipOrigin(bitmap, gc,
4389 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4390 BlitBitmapMasked(bitmap, drawto,
4391 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4394 BlitBitmapMasked(bitmap, drawto,
4395 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4396 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4397 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4398 BlitBitmapMasked(bitmap, drawto,
4399 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4401 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4404 redraw_mask |= REDRAW_DOOR_2;
4405 door_2_done = (a == VXSIZE);
4408 if (!(door_state & DOOR_NO_DELAY))
4412 if (game_status == GAME_MODE_MAIN)
4415 WaitUntilDelayReached(&door_delay, door_delay_value);
4420 if (door_state & DOOR_ACTION_1)
4421 door1 = door_state & DOOR_ACTION_1;
4422 if (door_state & DOOR_ACTION_2)
4423 door2 = door_state & DOOR_ACTION_2;
4425 return (door1 | door2);
4428 void DrawSpecialEditorDoor()
4430 /* draw bigger toolbox window */
4431 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4432 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4434 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4435 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4438 redraw_mask |= REDRAW_ALL;
4441 void UndrawSpecialEditorDoor()
4443 /* draw normal tape recorder window */
4444 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4445 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4448 redraw_mask |= REDRAW_ALL;
4452 /* ---------- new tool button stuff ---------------------------------------- */
4454 /* graphic position values for tool buttons */
4455 #define TOOL_BUTTON_YES_XPOS 2
4456 #define TOOL_BUTTON_YES_YPOS 250
4457 #define TOOL_BUTTON_YES_GFX_YPOS 0
4458 #define TOOL_BUTTON_YES_XSIZE 46
4459 #define TOOL_BUTTON_YES_YSIZE 28
4460 #define TOOL_BUTTON_NO_XPOS 52
4461 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
4462 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
4463 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
4464 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
4465 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
4466 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
4467 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
4468 #define TOOL_BUTTON_CONFIRM_XSIZE 96
4469 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
4470 #define TOOL_BUTTON_PLAYER_XSIZE 30
4471 #define TOOL_BUTTON_PLAYER_YSIZE 30
4472 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
4473 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
4474 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4475 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4476 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4477 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4478 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4479 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4480 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4481 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4482 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4483 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4484 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4485 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4486 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4487 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4488 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4489 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4490 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4491 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4500 } toolbutton_info[NUM_TOOL_BUTTONS] =
4503 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
4504 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
4505 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
4510 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
4511 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
4512 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
4517 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
4518 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
4519 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
4520 TOOL_CTRL_ID_CONFIRM,
4524 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4525 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
4526 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4527 TOOL_CTRL_ID_PLAYER_1,
4531 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4532 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
4533 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4534 TOOL_CTRL_ID_PLAYER_2,
4538 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4539 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
4540 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4541 TOOL_CTRL_ID_PLAYER_3,
4545 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4546 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
4547 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4548 TOOL_CTRL_ID_PLAYER_4,
4553 void CreateToolButtons()
4557 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4559 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4560 Bitmap *deco_bitmap = None;
4561 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4562 struct GadgetInfo *gi;
4563 unsigned long event_mask;
4564 int gd_xoffset, gd_yoffset;
4565 int gd_x1, gd_x2, gd_y;
4568 event_mask = GD_EVENT_RELEASED;
4570 gd_xoffset = toolbutton_info[i].xpos;
4571 gd_yoffset = toolbutton_info[i].ypos;
4572 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4573 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4574 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4576 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4578 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4580 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4581 &deco_bitmap, &deco_x, &deco_y);
4582 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4583 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4586 gi = CreateGadget(GDI_CUSTOM_ID, id,
4587 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4588 GDI_X, DX + toolbutton_info[i].x,
4589 GDI_Y, DY + toolbutton_info[i].y,
4590 GDI_WIDTH, toolbutton_info[i].width,
4591 GDI_HEIGHT, toolbutton_info[i].height,
4592 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4593 GDI_STATE, GD_BUTTON_UNPRESSED,
4594 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4595 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4596 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4597 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4598 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4599 GDI_DECORATION_SHIFTING, 1, 1,
4600 GDI_DIRECT_DRAW, FALSE,
4601 GDI_EVENT_MASK, event_mask,
4602 GDI_CALLBACK_ACTION, HandleToolButtons,
4606 Error(ERR_EXIT, "cannot create gadget");
4608 tool_gadget[id] = gi;
4612 void FreeToolButtons()
4616 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4617 FreeGadget(tool_gadget[i]);
4620 static void UnmapToolButtons()
4624 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4625 UnmapGadget(tool_gadget[i]);
4628 static void HandleToolButtons(struct GadgetInfo *gi)
4630 request_gadget_id = gi->custom_id;
4633 static struct Mapping_EM_to_RND_object
4636 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4637 boolean is_backside; /* backside of moving element */
4643 em_object_mapping_list[] =
4646 Xblank, TRUE, FALSE,
4650 Yacid_splash_eB, FALSE, FALSE,
4651 EL_ACID_SPLASH_RIGHT, -1, -1
4654 Yacid_splash_wB, FALSE, FALSE,
4655 EL_ACID_SPLASH_LEFT, -1, -1
4658 #ifdef EM_ENGINE_BAD_ROLL
4660 Xstone_force_e, FALSE, FALSE,
4661 EL_ROCK, -1, MV_BIT_RIGHT
4664 Xstone_force_w, FALSE, FALSE,
4665 EL_ROCK, -1, MV_BIT_LEFT
4668 Xnut_force_e, FALSE, FALSE,
4669 EL_NUT, -1, MV_BIT_RIGHT
4672 Xnut_force_w, FALSE, FALSE,
4673 EL_NUT, -1, MV_BIT_LEFT
4676 Xspring_force_e, FALSE, FALSE,
4677 EL_SPRING, -1, MV_BIT_RIGHT
4680 Xspring_force_w, FALSE, FALSE,
4681 EL_SPRING, -1, MV_BIT_LEFT
4684 Xemerald_force_e, FALSE, FALSE,
4685 EL_EMERALD, -1, MV_BIT_RIGHT
4688 Xemerald_force_w, FALSE, FALSE,
4689 EL_EMERALD, -1, MV_BIT_LEFT
4692 Xdiamond_force_e, FALSE, FALSE,
4693 EL_DIAMOND, -1, MV_BIT_RIGHT
4696 Xdiamond_force_w, FALSE, FALSE,
4697 EL_DIAMOND, -1, MV_BIT_LEFT
4700 Xbomb_force_e, FALSE, FALSE,
4701 EL_BOMB, -1, MV_BIT_RIGHT
4704 Xbomb_force_w, FALSE, FALSE,
4705 EL_BOMB, -1, MV_BIT_LEFT
4707 #endif /* EM_ENGINE_BAD_ROLL */
4710 Xstone, TRUE, FALSE,
4714 Xstone_pause, FALSE, FALSE,
4718 Xstone_fall, FALSE, FALSE,
4722 Ystone_s, FALSE, FALSE,
4723 EL_ROCK, ACTION_FALLING, -1
4726 Ystone_sB, FALSE, TRUE,
4727 EL_ROCK, ACTION_FALLING, -1
4730 Ystone_e, FALSE, FALSE,
4731 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4734 Ystone_eB, FALSE, TRUE,
4735 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4738 Ystone_w, FALSE, FALSE,
4739 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4742 Ystone_wB, FALSE, TRUE,
4743 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4750 Xnut_pause, FALSE, FALSE,
4754 Xnut_fall, FALSE, FALSE,
4758 Ynut_s, FALSE, FALSE,
4759 EL_NUT, ACTION_FALLING, -1
4762 Ynut_sB, FALSE, TRUE,
4763 EL_NUT, ACTION_FALLING, -1
4766 Ynut_e, FALSE, FALSE,
4767 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4770 Ynut_eB, FALSE, TRUE,
4771 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4774 Ynut_w, FALSE, FALSE,
4775 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4778 Ynut_wB, FALSE, TRUE,
4779 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4782 Xbug_n, TRUE, FALSE,
4786 Xbug_e, TRUE, FALSE,
4787 EL_BUG_RIGHT, -1, -1
4790 Xbug_s, TRUE, FALSE,
4794 Xbug_w, TRUE, FALSE,
4798 Xbug_gon, FALSE, FALSE,
4802 Xbug_goe, FALSE, FALSE,
4803 EL_BUG_RIGHT, -1, -1
4806 Xbug_gos, FALSE, FALSE,
4810 Xbug_gow, FALSE, FALSE,
4814 Ybug_n, FALSE, FALSE,
4815 EL_BUG, ACTION_MOVING, MV_BIT_UP
4818 Ybug_nB, FALSE, TRUE,
4819 EL_BUG, ACTION_MOVING, MV_BIT_UP
4822 Ybug_e, FALSE, FALSE,
4823 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4826 Ybug_eB, FALSE, TRUE,
4827 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4830 Ybug_s, FALSE, FALSE,
4831 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4834 Ybug_sB, FALSE, TRUE,
4835 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4838 Ybug_w, FALSE, FALSE,
4839 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4842 Ybug_wB, FALSE, TRUE,
4843 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4846 Ybug_w_n, FALSE, FALSE,
4847 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4850 Ybug_n_e, FALSE, FALSE,
4851 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4854 Ybug_e_s, FALSE, FALSE,
4855 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4858 Ybug_s_w, FALSE, FALSE,
4859 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4862 Ybug_e_n, FALSE, FALSE,
4863 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4866 Ybug_s_e, FALSE, FALSE,
4867 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4870 Ybug_w_s, FALSE, FALSE,
4871 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4874 Ybug_n_w, FALSE, FALSE,
4875 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4878 Ybug_stone, FALSE, FALSE,
4879 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4882 Ybug_spring, FALSE, FALSE,
4883 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4886 Xtank_n, TRUE, FALSE,
4887 EL_SPACESHIP_UP, -1, -1
4890 Xtank_e, TRUE, FALSE,
4891 EL_SPACESHIP_RIGHT, -1, -1
4894 Xtank_s, TRUE, FALSE,
4895 EL_SPACESHIP_DOWN, -1, -1
4898 Xtank_w, TRUE, FALSE,
4899 EL_SPACESHIP_LEFT, -1, -1
4902 Xtank_gon, FALSE, FALSE,
4903 EL_SPACESHIP_UP, -1, -1
4906 Xtank_goe, FALSE, FALSE,
4907 EL_SPACESHIP_RIGHT, -1, -1
4910 Xtank_gos, FALSE, FALSE,
4911 EL_SPACESHIP_DOWN, -1, -1
4914 Xtank_gow, FALSE, FALSE,
4915 EL_SPACESHIP_LEFT, -1, -1
4918 Ytank_n, FALSE, FALSE,
4919 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4922 Ytank_nB, FALSE, TRUE,
4923 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4926 Ytank_e, FALSE, FALSE,
4927 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4930 Ytank_eB, FALSE, TRUE,
4931 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4934 Ytank_s, FALSE, FALSE,
4935 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4938 Ytank_sB, FALSE, TRUE,
4939 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4942 Ytank_w, FALSE, FALSE,
4943 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4946 Ytank_wB, FALSE, TRUE,
4947 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4950 Ytank_w_n, FALSE, FALSE,
4951 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4954 Ytank_n_e, FALSE, FALSE,
4955 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4958 Ytank_e_s, FALSE, FALSE,
4959 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4962 Ytank_s_w, FALSE, FALSE,
4963 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4966 Ytank_e_n, FALSE, FALSE,
4967 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4970 Ytank_s_e, FALSE, FALSE,
4971 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4974 Ytank_w_s, FALSE, FALSE,
4975 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4978 Ytank_n_w, FALSE, FALSE,
4979 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4982 Ytank_stone, FALSE, FALSE,
4983 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4986 Ytank_spring, FALSE, FALSE,
4987 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4990 Xandroid, TRUE, FALSE,
4991 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4994 Xandroid_1_n, FALSE, FALSE,
4995 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4998 Xandroid_2_n, FALSE, FALSE,
4999 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
5002 Xandroid_1_e, FALSE, FALSE,
5003 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5006 Xandroid_2_e, FALSE, FALSE,
5007 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
5010 Xandroid_1_w, FALSE, FALSE,
5011 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5014 Xandroid_2_w, FALSE, FALSE,
5015 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
5018 Xandroid_1_s, FALSE, FALSE,
5019 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5022 Xandroid_2_s, FALSE, FALSE,
5023 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
5026 Yandroid_n, FALSE, FALSE,
5027 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5030 Yandroid_nB, FALSE, TRUE,
5031 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
5034 Yandroid_ne, FALSE, FALSE,
5035 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
5038 Yandroid_neB, FALSE, TRUE,
5039 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
5042 Yandroid_e, FALSE, FALSE,
5043 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5046 Yandroid_eB, FALSE, TRUE,
5047 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
5050 Yandroid_se, FALSE, FALSE,
5051 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
5054 Yandroid_seB, FALSE, TRUE,
5055 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5058 Yandroid_s, FALSE, FALSE,
5059 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5062 Yandroid_sB, FALSE, TRUE,
5063 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
5066 Yandroid_sw, FALSE, FALSE,
5067 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
5070 Yandroid_swB, FALSE, TRUE,
5071 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
5074 Yandroid_w, FALSE, FALSE,
5075 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5078 Yandroid_wB, FALSE, TRUE,
5079 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
5082 Yandroid_nw, FALSE, FALSE,
5083 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
5086 Yandroid_nwB, FALSE, TRUE,
5087 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
5090 Xspring, TRUE, FALSE,
5094 Xspring_pause, FALSE, FALSE,
5098 Xspring_e, FALSE, FALSE,
5102 Xspring_w, FALSE, FALSE,
5106 Xspring_fall, FALSE, FALSE,
5110 Yspring_s, FALSE, FALSE,
5111 EL_SPRING, ACTION_FALLING, -1
5114 Yspring_sB, FALSE, TRUE,
5115 EL_SPRING, ACTION_FALLING, -1
5118 Yspring_e, FALSE, FALSE,
5119 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5122 Yspring_eB, FALSE, TRUE,
5123 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
5126 Yspring_w, FALSE, FALSE,
5127 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5130 Yspring_wB, FALSE, TRUE,
5131 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
5134 Yspring_kill_e, FALSE, FALSE,
5135 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5138 Yspring_kill_eB, FALSE, TRUE,
5139 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
5142 Yspring_kill_w, FALSE, FALSE,
5143 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5146 Yspring_kill_wB, FALSE, TRUE,
5147 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
5150 Xeater_n, TRUE, FALSE,
5151 EL_YAMYAM_UP, -1, -1
5154 Xeater_e, TRUE, FALSE,
5155 EL_YAMYAM_RIGHT, -1, -1
5158 Xeater_w, TRUE, FALSE,
5159 EL_YAMYAM_LEFT, -1, -1
5162 Xeater_s, TRUE, FALSE,
5163 EL_YAMYAM_DOWN, -1, -1
5166 Yeater_n, FALSE, FALSE,
5167 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5170 Yeater_nB, FALSE, TRUE,
5171 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5174 Yeater_e, FALSE, FALSE,
5175 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5178 Yeater_eB, FALSE, TRUE,
5179 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5182 Yeater_s, FALSE, FALSE,
5183 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5186 Yeater_sB, FALSE, TRUE,
5187 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5190 Yeater_w, FALSE, FALSE,
5191 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5194 Yeater_wB, FALSE, TRUE,
5195 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5198 Yeater_stone, FALSE, FALSE,
5199 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5202 Yeater_spring, FALSE, FALSE,
5203 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5206 Xalien, TRUE, FALSE,
5210 Xalien_pause, FALSE, FALSE,
5214 Yalien_n, FALSE, FALSE,
5215 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5218 Yalien_nB, FALSE, TRUE,
5219 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5222 Yalien_e, FALSE, FALSE,
5223 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5226 Yalien_eB, FALSE, TRUE,
5227 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5230 Yalien_s, FALSE, FALSE,
5231 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5234 Yalien_sB, FALSE, TRUE,
5235 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5238 Yalien_w, FALSE, FALSE,
5239 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5242 Yalien_wB, FALSE, TRUE,
5243 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5246 Yalien_stone, FALSE, FALSE,
5247 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5250 Yalien_spring, FALSE, FALSE,
5251 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5254 Xemerald, TRUE, FALSE,
5258 Xemerald_pause, FALSE, FALSE,
5262 Xemerald_fall, FALSE, FALSE,
5266 Xemerald_shine, FALSE, FALSE,
5267 EL_EMERALD, ACTION_TWINKLING, -1
5270 Yemerald_s, FALSE, FALSE,
5271 EL_EMERALD, ACTION_FALLING, -1
5274 Yemerald_sB, FALSE, TRUE,
5275 EL_EMERALD, ACTION_FALLING, -1
5278 Yemerald_e, FALSE, FALSE,
5279 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5282 Yemerald_eB, FALSE, TRUE,
5283 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5286 Yemerald_w, FALSE, FALSE,
5287 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5290 Yemerald_wB, FALSE, TRUE,
5291 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5294 Yemerald_eat, FALSE, FALSE,
5295 EL_EMERALD, ACTION_COLLECTING, -1
5298 Yemerald_stone, FALSE, FALSE,
5299 EL_NUT, ACTION_BREAKING, -1
5302 Xdiamond, TRUE, FALSE,
5306 Xdiamond_pause, FALSE, FALSE,
5310 Xdiamond_fall, FALSE, FALSE,
5314 Xdiamond_shine, FALSE, FALSE,
5315 EL_DIAMOND, ACTION_TWINKLING, -1
5318 Ydiamond_s, FALSE, FALSE,
5319 EL_DIAMOND, ACTION_FALLING, -1
5322 Ydiamond_sB, FALSE, TRUE,
5323 EL_DIAMOND, ACTION_FALLING, -1
5326 Ydiamond_e, FALSE, FALSE,
5327 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5330 Ydiamond_eB, FALSE, TRUE,
5331 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5334 Ydiamond_w, FALSE, FALSE,
5335 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5338 Ydiamond_wB, FALSE, TRUE,
5339 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5342 Ydiamond_eat, FALSE, FALSE,
5343 EL_DIAMOND, ACTION_COLLECTING, -1
5346 Ydiamond_stone, FALSE, FALSE,
5347 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5350 Xdrip_fall, TRUE, FALSE,
5351 EL_AMOEBA_DROP, -1, -1
5354 Xdrip_stretch, FALSE, FALSE,
5355 EL_AMOEBA_DROP, ACTION_FALLING, -1
5358 Xdrip_stretchB, FALSE, TRUE,
5359 EL_AMOEBA_DROP, ACTION_FALLING, -1
5362 Xdrip_eat, FALSE, FALSE,
5363 EL_AMOEBA_DROP, ACTION_GROWING, -1
5366 Ydrip_s1, FALSE, FALSE,
5367 EL_AMOEBA_DROP, ACTION_FALLING, -1
5370 Ydrip_s1B, FALSE, TRUE,
5371 EL_AMOEBA_DROP, ACTION_FALLING, -1
5374 Ydrip_s2, FALSE, FALSE,
5375 EL_AMOEBA_DROP, ACTION_FALLING, -1
5378 Ydrip_s2B, FALSE, TRUE,
5379 EL_AMOEBA_DROP, ACTION_FALLING, -1
5386 Xbomb_pause, FALSE, FALSE,
5390 Xbomb_fall, FALSE, FALSE,
5394 Ybomb_s, FALSE, FALSE,
5395 EL_BOMB, ACTION_FALLING, -1
5398 Ybomb_sB, FALSE, TRUE,
5399 EL_BOMB, ACTION_FALLING, -1
5402 Ybomb_e, FALSE, FALSE,
5403 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5406 Ybomb_eB, FALSE, TRUE,
5407 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5410 Ybomb_w, FALSE, FALSE,
5411 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5414 Ybomb_wB, FALSE, TRUE,
5415 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5418 Ybomb_eat, FALSE, FALSE,
5419 EL_BOMB, ACTION_ACTIVATING, -1
5422 Xballoon, TRUE, FALSE,
5426 Yballoon_n, FALSE, FALSE,
5427 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5430 Yballoon_nB, FALSE, TRUE,
5431 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5434 Yballoon_e, FALSE, FALSE,
5435 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5438 Yballoon_eB, FALSE, TRUE,
5439 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5442 Yballoon_s, FALSE, FALSE,
5443 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5446 Yballoon_sB, FALSE, TRUE,
5447 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5450 Yballoon_w, FALSE, FALSE,
5451 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5454 Yballoon_wB, FALSE, TRUE,
5455 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5458 Xgrass, TRUE, FALSE,
5459 EL_EMC_GRASS, -1, -1
5462 Ygrass_nB, FALSE, FALSE,
5463 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5466 Ygrass_eB, FALSE, FALSE,
5467 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5470 Ygrass_sB, FALSE, FALSE,
5471 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5474 Ygrass_wB, FALSE, FALSE,
5475 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5482 Ydirt_nB, FALSE, FALSE,
5483 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5486 Ydirt_eB, FALSE, FALSE,
5487 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5490 Ydirt_sB, FALSE, FALSE,
5491 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5494 Ydirt_wB, FALSE, FALSE,
5495 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5498 Xacid_ne, TRUE, FALSE,
5499 EL_ACID_POOL_TOPRIGHT, -1, -1
5502 Xacid_se, TRUE, FALSE,
5503 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5506 Xacid_s, TRUE, FALSE,
5507 EL_ACID_POOL_BOTTOM, -1, -1
5510 Xacid_sw, TRUE, FALSE,
5511 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5514 Xacid_nw, TRUE, FALSE,
5515 EL_ACID_POOL_TOPLEFT, -1, -1
5518 Xacid_1, TRUE, FALSE,
5522 Xacid_2, FALSE, FALSE,
5526 Xacid_3, FALSE, FALSE,
5530 Xacid_4, FALSE, FALSE,
5534 Xacid_5, FALSE, FALSE,
5538 Xacid_6, FALSE, FALSE,
5542 Xacid_7, FALSE, FALSE,
5546 Xacid_8, FALSE, FALSE,
5550 Xball_1, TRUE, FALSE,
5551 EL_EMC_MAGIC_BALL, -1, -1
5554 Xball_1B, FALSE, FALSE,
5555 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5558 Xball_2, FALSE, FALSE,
5559 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5562 Xball_2B, FALSE, FALSE,
5563 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5566 Yball_eat, FALSE, FALSE,
5567 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5570 Ykey_1_eat, FALSE, FALSE,
5571 EL_EM_KEY_1, ACTION_COLLECTING, -1
5574 Ykey_2_eat, FALSE, FALSE,
5575 EL_EM_KEY_2, ACTION_COLLECTING, -1
5578 Ykey_3_eat, FALSE, FALSE,
5579 EL_EM_KEY_3, ACTION_COLLECTING, -1
5582 Ykey_4_eat, FALSE, FALSE,
5583 EL_EM_KEY_4, ACTION_COLLECTING, -1
5586 Ykey_5_eat, FALSE, FALSE,
5587 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5590 Ykey_6_eat, FALSE, FALSE,
5591 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5594 Ykey_7_eat, FALSE, FALSE,
5595 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5598 Ykey_8_eat, FALSE, FALSE,
5599 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5602 Ylenses_eat, FALSE, FALSE,
5603 EL_EMC_LENSES, ACTION_COLLECTING, -1
5606 Ymagnify_eat, FALSE, FALSE,
5607 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5610 Ygrass_eat, FALSE, FALSE,
5611 EL_EMC_GRASS, ACTION_SNAPPING, -1
5614 Ydirt_eat, FALSE, FALSE,
5615 EL_SAND, ACTION_SNAPPING, -1
5618 Xgrow_ns, TRUE, FALSE,
5619 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5622 Ygrow_ns_eat, FALSE, FALSE,
5623 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5626 Xgrow_ew, TRUE, FALSE,
5627 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5630 Ygrow_ew_eat, FALSE, FALSE,
5631 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5634 Xwonderwall, TRUE, FALSE,
5635 EL_MAGIC_WALL, -1, -1
5638 XwonderwallB, FALSE, FALSE,
5639 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5642 Xamoeba_1, TRUE, FALSE,
5643 EL_AMOEBA_DRY, ACTION_OTHER, -1
5646 Xamoeba_2, FALSE, FALSE,
5647 EL_AMOEBA_DRY, ACTION_OTHER, -1
5650 Xamoeba_3, FALSE, FALSE,
5651 EL_AMOEBA_DRY, ACTION_OTHER, -1
5654 Xamoeba_4, FALSE, FALSE,
5655 EL_AMOEBA_DRY, ACTION_OTHER, -1
5658 Xamoeba_5, TRUE, FALSE,
5659 EL_AMOEBA_WET, ACTION_OTHER, -1
5662 Xamoeba_6, FALSE, FALSE,
5663 EL_AMOEBA_WET, ACTION_OTHER, -1
5666 Xamoeba_7, FALSE, FALSE,
5667 EL_AMOEBA_WET, ACTION_OTHER, -1
5670 Xamoeba_8, FALSE, FALSE,
5671 EL_AMOEBA_WET, ACTION_OTHER, -1
5674 Xdoor_1, TRUE, FALSE,
5675 EL_EM_GATE_1, -1, -1
5678 Xdoor_2, TRUE, FALSE,
5679 EL_EM_GATE_2, -1, -1
5682 Xdoor_3, TRUE, FALSE,
5683 EL_EM_GATE_3, -1, -1
5686 Xdoor_4, TRUE, FALSE,
5687 EL_EM_GATE_4, -1, -1
5690 Xdoor_5, TRUE, FALSE,
5691 EL_EMC_GATE_5, -1, -1
5694 Xdoor_6, TRUE, FALSE,
5695 EL_EMC_GATE_6, -1, -1
5698 Xdoor_7, TRUE, FALSE,
5699 EL_EMC_GATE_7, -1, -1
5702 Xdoor_8, TRUE, FALSE,
5703 EL_EMC_GATE_8, -1, -1
5706 Xkey_1, TRUE, FALSE,
5710 Xkey_2, TRUE, FALSE,
5714 Xkey_3, TRUE, FALSE,
5718 Xkey_4, TRUE, FALSE,
5722 Xkey_5, TRUE, FALSE,
5723 EL_EMC_KEY_5, -1, -1
5726 Xkey_6, TRUE, FALSE,
5727 EL_EMC_KEY_6, -1, -1
5730 Xkey_7, TRUE, FALSE,
5731 EL_EMC_KEY_7, -1, -1
5734 Xkey_8, TRUE, FALSE,
5735 EL_EMC_KEY_8, -1, -1
5738 Xwind_n, TRUE, FALSE,
5739 EL_BALLOON_SWITCH_UP, -1, -1
5742 Xwind_e, TRUE, FALSE,
5743 EL_BALLOON_SWITCH_RIGHT, -1, -1
5746 Xwind_s, TRUE, FALSE,
5747 EL_BALLOON_SWITCH_DOWN, -1, -1
5750 Xwind_w, TRUE, FALSE,
5751 EL_BALLOON_SWITCH_LEFT, -1, -1
5754 Xwind_nesw, TRUE, FALSE,
5755 EL_BALLOON_SWITCH_ANY, -1, -1
5758 Xwind_stop, TRUE, FALSE,
5759 EL_BALLOON_SWITCH_NONE, -1, -1
5763 EL_EM_EXIT_CLOSED, -1, -1
5766 Xexit_1, TRUE, FALSE,
5767 EL_EM_EXIT_OPEN, -1, -1
5770 Xexit_2, FALSE, FALSE,
5771 EL_EM_EXIT_OPEN, -1, -1
5774 Xexit_3, FALSE, FALSE,
5775 EL_EM_EXIT_OPEN, -1, -1
5778 Xdynamite, TRUE, FALSE,
5779 EL_EM_DYNAMITE, -1, -1
5782 Ydynamite_eat, FALSE, FALSE,
5783 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5786 Xdynamite_1, TRUE, FALSE,
5787 EL_EM_DYNAMITE_ACTIVE, -1, -1
5790 Xdynamite_2, FALSE, FALSE,
5791 EL_EM_DYNAMITE_ACTIVE, -1, -1
5794 Xdynamite_3, FALSE, FALSE,
5795 EL_EM_DYNAMITE_ACTIVE, -1, -1
5798 Xdynamite_4, FALSE, FALSE,
5799 EL_EM_DYNAMITE_ACTIVE, -1, -1
5802 Xbumper, TRUE, FALSE,
5803 EL_EMC_SPRING_BUMPER, -1, -1
5806 XbumperB, FALSE, FALSE,
5807 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5810 Xwheel, TRUE, FALSE,
5811 EL_ROBOT_WHEEL, -1, -1
5814 XwheelB, FALSE, FALSE,
5815 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5818 Xswitch, TRUE, FALSE,
5819 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5822 XswitchB, FALSE, FALSE,
5823 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5827 EL_QUICKSAND_EMPTY, -1, -1
5830 Xsand_stone, TRUE, FALSE,
5831 EL_QUICKSAND_FULL, -1, -1
5834 Xsand_stonein_1, FALSE, TRUE,
5835 EL_ROCK, ACTION_FILLING, -1
5838 Xsand_stonein_2, FALSE, TRUE,
5839 EL_ROCK, ACTION_FILLING, -1
5842 Xsand_stonein_3, FALSE, TRUE,
5843 EL_ROCK, ACTION_FILLING, -1
5846 Xsand_stonein_4, FALSE, TRUE,
5847 EL_ROCK, ACTION_FILLING, -1
5851 Xsand_stonesand_1, FALSE, FALSE,
5852 EL_QUICKSAND_EMPTYING, -1, -1
5855 Xsand_stonesand_2, FALSE, FALSE,
5856 EL_QUICKSAND_EMPTYING, -1, -1
5859 Xsand_stonesand_3, FALSE, FALSE,
5860 EL_QUICKSAND_EMPTYING, -1, -1
5863 Xsand_stonesand_4, FALSE, FALSE,
5864 EL_QUICKSAND_EMPTYING, -1, -1
5867 Xsand_stonesand_quickout_1, FALSE, FALSE,
5868 EL_QUICKSAND_EMPTYING, -1, -1
5871 Xsand_stonesand_quickout_2, FALSE, FALSE,
5872 EL_QUICKSAND_EMPTYING, -1, -1
5876 Xsand_stonesand_1, FALSE, FALSE,
5877 EL_QUICKSAND_FULL, -1, -1
5880 Xsand_stonesand_2, FALSE, FALSE,
5881 EL_QUICKSAND_FULL, -1, -1
5884 Xsand_stonesand_3, FALSE, FALSE,
5885 EL_QUICKSAND_FULL, -1, -1
5888 Xsand_stonesand_4, FALSE, FALSE,
5889 EL_QUICKSAND_FULL, -1, -1
5893 Xsand_stoneout_1, FALSE, FALSE,
5894 EL_ROCK, ACTION_EMPTYING, -1
5897 Xsand_stoneout_2, FALSE, FALSE,
5898 EL_ROCK, ACTION_EMPTYING, -1
5902 Xsand_sandstone_1, FALSE, FALSE,
5903 EL_QUICKSAND_FILLING, -1, -1
5906 Xsand_sandstone_2, FALSE, FALSE,
5907 EL_QUICKSAND_FILLING, -1, -1
5910 Xsand_sandstone_3, FALSE, FALSE,
5911 EL_QUICKSAND_FILLING, -1, -1
5914 Xsand_sandstone_4, FALSE, FALSE,
5915 EL_QUICKSAND_FILLING, -1, -1
5919 Xsand_sandstone_1, FALSE, FALSE,
5920 EL_QUICKSAND_FULL, -1, -1
5923 Xsand_sandstone_2, FALSE, FALSE,
5924 EL_QUICKSAND_FULL, -1, -1
5927 Xsand_sandstone_3, FALSE, FALSE,
5928 EL_QUICKSAND_FULL, -1, -1
5931 Xsand_sandstone_4, FALSE, FALSE,
5932 EL_QUICKSAND_FULL, -1, -1
5936 Xplant, TRUE, FALSE,
5937 EL_EMC_PLANT, -1, -1
5940 Yplant, FALSE, FALSE,
5941 EL_EMC_PLANT, -1, -1
5944 Xlenses, TRUE, FALSE,
5945 EL_EMC_LENSES, -1, -1
5948 Xmagnify, TRUE, FALSE,
5949 EL_EMC_MAGNIFIER, -1, -1
5952 Xdripper, TRUE, FALSE,
5953 EL_EMC_DRIPPER, -1, -1
5956 XdripperB, FALSE, FALSE,
5957 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5960 Xfake_blank, TRUE, FALSE,
5961 EL_INVISIBLE_WALL, -1, -1
5964 Xfake_blankB, FALSE, FALSE,
5965 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5968 Xfake_grass, TRUE, FALSE,
5969 EL_EMC_FAKE_GRASS, -1, -1
5972 Xfake_grassB, FALSE, FALSE,
5973 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5976 Xfake_door_1, TRUE, FALSE,
5977 EL_EM_GATE_1_GRAY, -1, -1
5980 Xfake_door_2, TRUE, FALSE,
5981 EL_EM_GATE_2_GRAY, -1, -1
5984 Xfake_door_3, TRUE, FALSE,
5985 EL_EM_GATE_3_GRAY, -1, -1
5988 Xfake_door_4, TRUE, FALSE,
5989 EL_EM_GATE_4_GRAY, -1, -1
5992 Xfake_door_5, TRUE, FALSE,
5993 EL_EMC_GATE_5_GRAY, -1, -1
5996 Xfake_door_6, TRUE, FALSE,
5997 EL_EMC_GATE_6_GRAY, -1, -1
6000 Xfake_door_7, TRUE, FALSE,
6001 EL_EMC_GATE_7_GRAY, -1, -1
6004 Xfake_door_8, TRUE, FALSE,
6005 EL_EMC_GATE_8_GRAY, -1, -1
6008 Xfake_acid_1, TRUE, FALSE,
6009 EL_EMC_FAKE_ACID, -1, -1
6012 Xfake_acid_2, FALSE, FALSE,
6013 EL_EMC_FAKE_ACID, -1, -1
6016 Xfake_acid_3, FALSE, FALSE,
6017 EL_EMC_FAKE_ACID, -1, -1
6020 Xfake_acid_4, FALSE, FALSE,
6021 EL_EMC_FAKE_ACID, -1, -1
6024 Xfake_acid_5, FALSE, FALSE,
6025 EL_EMC_FAKE_ACID, -1, -1
6028 Xfake_acid_6, FALSE, FALSE,
6029 EL_EMC_FAKE_ACID, -1, -1
6032 Xfake_acid_7, FALSE, FALSE,
6033 EL_EMC_FAKE_ACID, -1, -1
6036 Xfake_acid_8, FALSE, FALSE,
6037 EL_EMC_FAKE_ACID, -1, -1
6040 Xsteel_1, TRUE, FALSE,
6041 EL_STEELWALL, -1, -1
6044 Xsteel_2, TRUE, FALSE,
6045 EL_EMC_STEELWALL_2, -1, -1
6048 Xsteel_3, TRUE, FALSE,
6049 EL_EMC_STEELWALL_3, -1, -1
6052 Xsteel_4, TRUE, FALSE,
6053 EL_EMC_STEELWALL_4, -1, -1
6056 Xwall_1, TRUE, FALSE,
6060 Xwall_2, TRUE, FALSE,
6061 EL_EMC_WALL_14, -1, -1
6064 Xwall_3, TRUE, FALSE,
6065 EL_EMC_WALL_15, -1, -1
6068 Xwall_4, TRUE, FALSE,
6069 EL_EMC_WALL_16, -1, -1
6072 Xround_wall_1, TRUE, FALSE,
6073 EL_WALL_SLIPPERY, -1, -1
6076 Xround_wall_2, TRUE, FALSE,
6077 EL_EMC_WALL_SLIPPERY_2, -1, -1
6080 Xround_wall_3, TRUE, FALSE,
6081 EL_EMC_WALL_SLIPPERY_3, -1, -1
6084 Xround_wall_4, TRUE, FALSE,
6085 EL_EMC_WALL_SLIPPERY_4, -1, -1
6088 Xdecor_1, TRUE, FALSE,
6089 EL_EMC_WALL_8, -1, -1
6092 Xdecor_2, TRUE, FALSE,
6093 EL_EMC_WALL_6, -1, -1
6096 Xdecor_3, TRUE, FALSE,
6097 EL_EMC_WALL_4, -1, -1
6100 Xdecor_4, TRUE, FALSE,
6101 EL_EMC_WALL_7, -1, -1
6104 Xdecor_5, TRUE, FALSE,
6105 EL_EMC_WALL_5, -1, -1
6108 Xdecor_6, TRUE, FALSE,
6109 EL_EMC_WALL_9, -1, -1
6112 Xdecor_7, TRUE, FALSE,
6113 EL_EMC_WALL_10, -1, -1
6116 Xdecor_8, TRUE, FALSE,
6117 EL_EMC_WALL_1, -1, -1
6120 Xdecor_9, TRUE, FALSE,
6121 EL_EMC_WALL_2, -1, -1
6124 Xdecor_10, TRUE, FALSE,
6125 EL_EMC_WALL_3, -1, -1
6128 Xdecor_11, TRUE, FALSE,
6129 EL_EMC_WALL_11, -1, -1
6132 Xdecor_12, TRUE, FALSE,
6133 EL_EMC_WALL_12, -1, -1
6136 Xalpha_0, TRUE, FALSE,
6137 EL_CHAR('0'), -1, -1
6140 Xalpha_1, TRUE, FALSE,
6141 EL_CHAR('1'), -1, -1
6144 Xalpha_2, TRUE, FALSE,
6145 EL_CHAR('2'), -1, -1
6148 Xalpha_3, TRUE, FALSE,
6149 EL_CHAR('3'), -1, -1
6152 Xalpha_4, TRUE, FALSE,
6153 EL_CHAR('4'), -1, -1
6156 Xalpha_5, TRUE, FALSE,
6157 EL_CHAR('5'), -1, -1
6160 Xalpha_6, TRUE, FALSE,
6161 EL_CHAR('6'), -1, -1
6164 Xalpha_7, TRUE, FALSE,
6165 EL_CHAR('7'), -1, -1
6168 Xalpha_8, TRUE, FALSE,
6169 EL_CHAR('8'), -1, -1
6172 Xalpha_9, TRUE, FALSE,
6173 EL_CHAR('9'), -1, -1
6176 Xalpha_excla, TRUE, FALSE,
6177 EL_CHAR('!'), -1, -1
6180 Xalpha_quote, TRUE, FALSE,
6181 EL_CHAR('"'), -1, -1
6184 Xalpha_comma, TRUE, FALSE,
6185 EL_CHAR(','), -1, -1
6188 Xalpha_minus, TRUE, FALSE,
6189 EL_CHAR('-'), -1, -1
6192 Xalpha_perio, TRUE, FALSE,
6193 EL_CHAR('.'), -1, -1
6196 Xalpha_colon, TRUE, FALSE,
6197 EL_CHAR(':'), -1, -1
6200 Xalpha_quest, TRUE, FALSE,
6201 EL_CHAR('?'), -1, -1
6204 Xalpha_a, TRUE, FALSE,
6205 EL_CHAR('A'), -1, -1
6208 Xalpha_b, TRUE, FALSE,
6209 EL_CHAR('B'), -1, -1
6212 Xalpha_c, TRUE, FALSE,
6213 EL_CHAR('C'), -1, -1
6216 Xalpha_d, TRUE, FALSE,
6217 EL_CHAR('D'), -1, -1
6220 Xalpha_e, TRUE, FALSE,
6221 EL_CHAR('E'), -1, -1
6224 Xalpha_f, TRUE, FALSE,
6225 EL_CHAR('F'), -1, -1
6228 Xalpha_g, TRUE, FALSE,
6229 EL_CHAR('G'), -1, -1
6232 Xalpha_h, TRUE, FALSE,
6233 EL_CHAR('H'), -1, -1
6236 Xalpha_i, TRUE, FALSE,
6237 EL_CHAR('I'), -1, -1
6240 Xalpha_j, TRUE, FALSE,
6241 EL_CHAR('J'), -1, -1
6244 Xalpha_k, TRUE, FALSE,
6245 EL_CHAR('K'), -1, -1
6248 Xalpha_l, TRUE, FALSE,
6249 EL_CHAR('L'), -1, -1
6252 Xalpha_m, TRUE, FALSE,
6253 EL_CHAR('M'), -1, -1
6256 Xalpha_n, TRUE, FALSE,
6257 EL_CHAR('N'), -1, -1
6260 Xalpha_o, TRUE, FALSE,
6261 EL_CHAR('O'), -1, -1
6264 Xalpha_p, TRUE, FALSE,
6265 EL_CHAR('P'), -1, -1
6268 Xalpha_q, TRUE, FALSE,
6269 EL_CHAR('Q'), -1, -1
6272 Xalpha_r, TRUE, FALSE,
6273 EL_CHAR('R'), -1, -1
6276 Xalpha_s, TRUE, FALSE,
6277 EL_CHAR('S'), -1, -1
6280 Xalpha_t, TRUE, FALSE,
6281 EL_CHAR('T'), -1, -1
6284 Xalpha_u, TRUE, FALSE,
6285 EL_CHAR('U'), -1, -1
6288 Xalpha_v, TRUE, FALSE,
6289 EL_CHAR('V'), -1, -1
6292 Xalpha_w, TRUE, FALSE,
6293 EL_CHAR('W'), -1, -1
6296 Xalpha_x, TRUE, FALSE,
6297 EL_CHAR('X'), -1, -1
6300 Xalpha_y, TRUE, FALSE,
6301 EL_CHAR('Y'), -1, -1
6304 Xalpha_z, TRUE, FALSE,
6305 EL_CHAR('Z'), -1, -1
6308 Xalpha_arrow_e, TRUE, FALSE,
6309 EL_CHAR('>'), -1, -1
6312 Xalpha_arrow_w, TRUE, FALSE,
6313 EL_CHAR('<'), -1, -1
6316 Xalpha_copyr, TRUE, FALSE,
6317 EL_CHAR('©'), -1, -1
6321 Xboom_bug, FALSE, FALSE,
6322 EL_BUG, ACTION_EXPLODING, -1
6325 Xboom_bomb, FALSE, FALSE,
6326 EL_BOMB, ACTION_EXPLODING, -1
6329 Xboom_android, FALSE, FALSE,
6330 EL_EMC_ANDROID, ACTION_OTHER, -1
6333 Xboom_1, FALSE, FALSE,
6334 EL_DEFAULT, ACTION_EXPLODING, -1
6337 Xboom_2, FALSE, FALSE,
6338 EL_DEFAULT, ACTION_EXPLODING, -1
6341 Znormal, FALSE, FALSE,
6345 Zdynamite, FALSE, FALSE,
6349 Zplayer, FALSE, FALSE,
6353 ZBORDER, FALSE, FALSE,
6363 static struct Mapping_EM_to_RND_player
6372 em_player_mapping_list[] =
6376 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6380 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6384 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6388 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6392 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6396 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6400 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6404 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6408 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6412 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6416 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6420 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6424 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6428 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6432 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6436 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6440 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6444 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6448 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6452 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6456 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6460 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6464 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6468 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6472 EL_PLAYER_1, ACTION_DEFAULT, -1,
6476 EL_PLAYER_2, ACTION_DEFAULT, -1,
6480 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6484 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6488 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6492 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6496 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6500 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6504 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6508 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6512 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6516 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6520 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6524 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6528 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6532 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6536 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6540 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6544 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6548 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6552 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6556 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6560 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6564 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6568 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6572 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6576 EL_PLAYER_3, ACTION_DEFAULT, -1,
6580 EL_PLAYER_4, ACTION_DEFAULT, -1,
6589 int map_element_RND_to_EM(int element_rnd)
6591 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6592 static boolean mapping_initialized = FALSE;
6594 if (!mapping_initialized)
6598 /* return "Xalpha_quest" for all undefined elements in mapping array */
6599 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6600 mapping_RND_to_EM[i] = Xalpha_quest;
6602 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6603 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6604 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6605 em_object_mapping_list[i].element_em;
6607 mapping_initialized = TRUE;
6610 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6611 return mapping_RND_to_EM[element_rnd];
6613 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6618 int map_element_EM_to_RND(int element_em)
6620 static unsigned short mapping_EM_to_RND[TILE_MAX];
6621 static boolean mapping_initialized = FALSE;
6623 if (!mapping_initialized)
6627 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6628 for (i = 0; i < TILE_MAX; i++)
6629 mapping_EM_to_RND[i] = EL_UNKNOWN;
6631 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6632 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6633 em_object_mapping_list[i].element_rnd;
6635 mapping_initialized = TRUE;
6638 if (element_em >= 0 && element_em < TILE_MAX)
6639 return mapping_EM_to_RND[element_em];
6641 Error(ERR_WARN, "invalid EM level element %d", element_em);
6646 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6648 struct LevelInfo_EM *level_em = level->native_em_level;
6649 struct LEVEL *lev = level_em->lev;
6652 for (i = 0; i < TILE_MAX; i++)
6653 lev->android_array[i] = Xblank;
6655 for (i = 0; i < level->num_android_clone_elements; i++)
6657 int element_rnd = level->android_clone_element[i];
6658 int element_em = map_element_RND_to_EM(element_rnd);
6660 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6661 if (em_object_mapping_list[j].element_rnd == element_rnd)
6662 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6666 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6668 struct LevelInfo_EM *level_em = level->native_em_level;
6669 struct LEVEL *lev = level_em->lev;
6672 level->num_android_clone_elements = 0;
6674 for (i = 0; i < TILE_MAX; i++)
6676 int element_em = lev->android_array[i];
6678 boolean element_found = FALSE;
6680 if (element_em == Xblank)
6683 element_rnd = map_element_EM_to_RND(element_em);
6685 for (j = 0; j < level->num_android_clone_elements; j++)
6686 if (level->android_clone_element[j] == element_rnd)
6687 element_found = TRUE;
6691 level->android_clone_element[level->num_android_clone_elements++] =
6694 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6699 if (level->num_android_clone_elements == 0)
6701 level->num_android_clone_elements = 1;
6702 level->android_clone_element[0] = EL_EMPTY;
6706 int map_direction_RND_to_EM(int direction)
6708 return (direction == MV_UP ? 0 :
6709 direction == MV_RIGHT ? 1 :
6710 direction == MV_DOWN ? 2 :
6711 direction == MV_LEFT ? 3 :
6715 int map_direction_EM_to_RND(int direction)
6717 return (direction == 0 ? MV_UP :
6718 direction == 1 ? MV_RIGHT :
6719 direction == 2 ? MV_DOWN :
6720 direction == 3 ? MV_LEFT :
6724 int map_element_RND_to_SP(int element_rnd)
6726 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6728 if (element_rnd >= EL_SP_START &&
6729 element_rnd <= EL_SP_END)
6730 element_sp = element_rnd - EL_SP_START;
6731 else if (element_rnd == EL_EMPTY_SPACE)
6733 else if (element_rnd == EL_INVISIBLE_WALL)
6739 int map_element_SP_to_RND(int element_sp)
6741 int element_rnd = EL_UNKNOWN;
6743 if (element_sp >= 0x00 &&
6745 element_rnd = EL_SP_START + element_sp;
6746 else if (element_sp == 0x28)
6747 element_rnd = EL_INVISIBLE_WALL;
6752 int map_action_SP_to_RND(int action_sp)
6756 case actActive: return ACTION_ACTIVE;
6757 case actImpact: return ACTION_IMPACT;
6758 case actExploding: return ACTION_EXPLODING;
6759 case actDigging: return ACTION_DIGGING;
6760 case actSnapping: return ACTION_SNAPPING;
6761 case actCollecting: return ACTION_COLLECTING;
6762 case actPassing: return ACTION_PASSING;
6763 case actPushing: return ACTION_PUSHING;
6764 case actDropping: return ACTION_DROPPING;
6766 default: return ACTION_DEFAULT;
6770 int get_next_element(int element)
6774 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6775 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6776 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6777 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6778 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6779 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6780 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6781 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6782 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6783 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6784 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6786 default: return element;
6791 int el_act_dir2img(int element, int action, int direction)
6793 element = GFX_ELEMENT(element);
6795 if (direction == MV_NONE)
6796 return element_info[element].graphic[action];
6798 direction = MV_DIR_TO_BIT(direction);
6800 return element_info[element].direction_graphic[action][direction];
6803 int el_act_dir2img(int element, int action, int direction)
6805 element = GFX_ELEMENT(element);
6806 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6808 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6809 return element_info[element].direction_graphic[action][direction];
6814 static int el_act_dir2crm(int element, int action, int direction)
6816 element = GFX_ELEMENT(element);
6818 if (direction == MV_NONE)
6819 return element_info[element].crumbled[action];
6821 direction = MV_DIR_TO_BIT(direction);
6823 return element_info[element].direction_crumbled[action][direction];
6826 static int el_act_dir2crm(int element, int action, int direction)
6828 element = GFX_ELEMENT(element);
6829 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6831 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6832 return element_info[element].direction_crumbled[action][direction];
6836 int el_act2img(int element, int action)
6838 element = GFX_ELEMENT(element);
6840 return element_info[element].graphic[action];
6843 int el_act2crm(int element, int action)
6845 element = GFX_ELEMENT(element);
6847 return element_info[element].crumbled[action];
6850 int el_dir2img(int element, int direction)
6852 element = GFX_ELEMENT(element);
6854 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6857 int el2baseimg(int element)
6859 return element_info[element].graphic[ACTION_DEFAULT];
6862 int el2img(int element)
6864 element = GFX_ELEMENT(element);
6866 return element_info[element].graphic[ACTION_DEFAULT];
6869 int el2edimg(int element)
6871 element = GFX_ELEMENT(element);
6873 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6876 int el2preimg(int element)
6878 element = GFX_ELEMENT(element);
6880 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6883 int el2panelimg(int element)
6885 element = GFX_ELEMENT(element);
6887 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6890 int font2baseimg(int font_nr)
6892 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6895 int getBeltNrFromBeltElement(int element)
6897 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6898 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6899 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6902 int getBeltNrFromBeltActiveElement(int element)
6904 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6905 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6906 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6909 int getBeltNrFromBeltSwitchElement(int element)
6911 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6912 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6913 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6916 int getBeltDirNrFromBeltElement(int element)
6918 static int belt_base_element[4] =
6920 EL_CONVEYOR_BELT_1_LEFT,
6921 EL_CONVEYOR_BELT_2_LEFT,
6922 EL_CONVEYOR_BELT_3_LEFT,
6923 EL_CONVEYOR_BELT_4_LEFT
6926 int belt_nr = getBeltNrFromBeltElement(element);
6927 int belt_dir_nr = element - belt_base_element[belt_nr];
6929 return (belt_dir_nr % 3);
6932 int getBeltDirNrFromBeltSwitchElement(int element)
6934 static int belt_base_element[4] =
6936 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6937 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6938 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6939 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6942 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6943 int belt_dir_nr = element - belt_base_element[belt_nr];
6945 return (belt_dir_nr % 3);
6948 int getBeltDirFromBeltElement(int element)
6950 static int belt_move_dir[3] =
6957 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6959 return belt_move_dir[belt_dir_nr];
6962 int getBeltDirFromBeltSwitchElement(int element)
6964 static int belt_move_dir[3] =
6971 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6973 return belt_move_dir[belt_dir_nr];
6976 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6978 static int belt_base_element[4] =
6980 EL_CONVEYOR_BELT_1_LEFT,
6981 EL_CONVEYOR_BELT_2_LEFT,
6982 EL_CONVEYOR_BELT_3_LEFT,
6983 EL_CONVEYOR_BELT_4_LEFT
6986 return belt_base_element[belt_nr] + belt_dir_nr;
6989 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6991 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6993 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6996 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6998 static int belt_base_element[4] =
7000 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7001 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7002 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7003 EL_CONVEYOR_BELT_4_SWITCH_LEFT
7006 return belt_base_element[belt_nr] + belt_dir_nr;
7009 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7011 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7013 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7016 int getNumActivePlayers_EM()
7018 int num_players = 0;
7024 for (i = 0; i < MAX_PLAYERS; i++)
7025 if (tape.player_participates[i])
7031 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7033 int game_frame_delay_value;
7035 game_frame_delay_value =
7036 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7037 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7040 if (tape.playing && tape.warp_forward && !tape.pausing)
7041 game_frame_delay_value = 0;
7043 return game_frame_delay_value;
7046 unsigned int InitRND(long seed)
7048 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7049 return InitEngineRandom_EM(seed);
7050 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7051 return InitEngineRandom_SP(seed);
7053 return InitEngineRandom_RND(seed);
7057 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7058 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7061 inline static int get_effective_element_EM(int tile, int frame_em)
7063 int element = object_mapping[tile].element_rnd;
7064 int action = object_mapping[tile].action;
7065 boolean is_backside = object_mapping[tile].is_backside;
7066 boolean action_removing = (action == ACTION_DIGGING ||
7067 action == ACTION_SNAPPING ||
7068 action == ACTION_COLLECTING);
7074 case Yacid_splash_eB:
7075 case Yacid_splash_wB:
7076 return (frame_em > 5 ? EL_EMPTY : element);
7079 case Ydiamond_stone:
7080 // if (!game.use_native_emc_graphics_engine)
7088 else /* frame_em == 7 */
7092 case Yacid_splash_eB:
7093 case Yacid_splash_wB:
7096 case Yemerald_stone:
7099 case Ydiamond_stone:
7103 case Xdrip_stretchB:
7122 case Xsand_stonein_1:
7123 case Xsand_stonein_2:
7124 case Xsand_stonein_3:
7125 case Xsand_stonein_4:
7129 return (is_backside || action_removing ? EL_EMPTY : element);
7134 inline static boolean check_linear_animation_EM(int tile)
7138 case Xsand_stonesand_1:
7139 case Xsand_stonesand_quickout_1:
7140 case Xsand_sandstone_1:
7141 case Xsand_stonein_1:
7142 case Xsand_stoneout_1:
7162 case Yacid_splash_eB:
7163 case Yacid_splash_wB:
7164 case Yemerald_stone:
7172 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7173 boolean has_crumbled_graphics,
7174 int crumbled, int sync_frame)
7176 /* if element can be crumbled, but certain action graphics are just empty
7177 space (like instantly snapping sand to empty space in 1 frame), do not
7178 treat these empty space graphics as crumbled graphics in EMC engine */
7179 if (crumbled == IMG_EMPTY_SPACE)
7180 has_crumbled_graphics = FALSE;
7182 if (has_crumbled_graphics)
7184 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7185 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7186 g_crumbled->anim_delay,
7187 g_crumbled->anim_mode,
7188 g_crumbled->anim_start_frame,
7191 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7192 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7194 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7196 g_em->has_crumbled_graphics = TRUE;
7200 g_em->crumbled_bitmap = NULL;
7201 g_em->crumbled_src_x = 0;
7202 g_em->crumbled_src_y = 0;
7203 g_em->crumbled_border_size = 0;
7205 g_em->has_crumbled_graphics = FALSE;
7209 void ResetGfxAnimation_EM(int x, int y, int tile)
7214 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7215 int tile, int frame_em, int x, int y)
7217 int action = object_mapping[tile].action;
7219 int direction = object_mapping[tile].direction;
7220 int effective_element = get_effective_element_EM(tile, frame_em);
7221 int graphic = (direction == MV_NONE ?
7222 el_act2img(effective_element, action) :
7223 el_act_dir2img(effective_element, action, direction));
7224 struct GraphicInfo *g = &graphic_info[graphic];
7227 boolean action_removing = (action == ACTION_DIGGING ||
7228 action == ACTION_SNAPPING ||
7229 action == ACTION_COLLECTING);
7230 boolean action_moving = (action == ACTION_FALLING ||
7231 action == ACTION_MOVING ||
7232 action == ACTION_PUSHING ||
7233 action == ACTION_EATING ||
7234 action == ACTION_FILLING ||
7235 action == ACTION_EMPTYING);
7236 boolean action_falling = (action == ACTION_FALLING ||
7237 action == ACTION_FILLING ||
7238 action == ACTION_EMPTYING);
7240 /* special case: graphic uses "2nd movement tile" and has defined
7241 7 frames for movement animation (or less) => use default graphic
7242 for last (8th) frame which ends the movement animation */
7243 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7245 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
7246 graphic = (direction == MV_NONE ?
7247 el_act2img(effective_element, action) :
7248 el_act_dir2img(effective_element, action, direction));
7250 g = &graphic_info[graphic];
7254 if (tile == Xsand_stonesand_1 ||
7255 tile == Xsand_stonesand_2 ||
7256 tile == Xsand_stonesand_3 ||
7257 tile == Xsand_stonesand_4)
7258 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7262 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7266 // printf("::: resetting... [%d]\n", tile);
7269 if (action_removing || check_linear_animation_EM(tile))
7271 GfxFrame[x][y] = frame_em;
7273 // printf("::: resetting... [%d]\n", tile);
7276 else if (action_moving)
7278 boolean is_backside = object_mapping[tile].is_backside;
7282 int direction = object_mapping[tile].direction;
7283 int move_dir = (action_falling ? MV_DOWN : direction);
7288 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7289 if (g->double_movement && frame_em == 0)
7293 // printf("::: resetting... [%d]\n", tile);
7297 if (move_dir == MV_LEFT)
7298 GfxFrame[x - 1][y] = GfxFrame[x][y];
7299 else if (move_dir == MV_RIGHT)
7300 GfxFrame[x + 1][y] = GfxFrame[x][y];
7301 else if (move_dir == MV_UP)
7302 GfxFrame[x][y - 1] = GfxFrame[x][y];
7303 else if (move_dir == MV_DOWN)
7304 GfxFrame[x][y + 1] = GfxFrame[x][y];
7311 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7312 if (tile == Xsand_stonesand_quickout_1 ||
7313 tile == Xsand_stonesand_quickout_2)
7318 if (tile == Xsand_stonesand_1 ||
7319 tile == Xsand_stonesand_2 ||
7320 tile == Xsand_stonesand_3 ||
7321 tile == Xsand_stonesand_4)
7322 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7326 if (graphic_info[graphic].anim_global_sync)
7327 sync_frame = FrameCounter;
7328 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7329 sync_frame = GfxFrame[x][y];
7331 sync_frame = 0; /* playfield border (pseudo steel) */
7333 SetRandomAnimationValue(x, y);
7335 int frame = getAnimationFrame(g->anim_frames,
7338 g->anim_start_frame,
7341 g_em->unique_identifier =
7342 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7346 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7347 int tile, int frame_em, int x, int y)
7349 int action = object_mapping[tile].action;
7350 int direction = object_mapping[tile].direction;
7351 boolean is_backside = object_mapping[tile].is_backside;
7352 int effective_element = get_effective_element_EM(tile, frame_em);
7354 int effective_action = action;
7356 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7358 int graphic = (direction == MV_NONE ?
7359 el_act2img(effective_element, effective_action) :
7360 el_act_dir2img(effective_element, effective_action,
7362 int crumbled = (direction == MV_NONE ?
7363 el_act2crm(effective_element, effective_action) :
7364 el_act_dir2crm(effective_element, effective_action,
7366 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7367 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7368 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7369 struct GraphicInfo *g = &graphic_info[graphic];
7371 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7375 /* special case: graphic uses "2nd movement tile" and has defined
7376 7 frames for movement animation (or less) => use default graphic
7377 for last (8th) frame which ends the movement animation */
7378 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7380 effective_action = ACTION_DEFAULT;
7381 graphic = (direction == MV_NONE ?
7382 el_act2img(effective_element, effective_action) :
7383 el_act_dir2img(effective_element, effective_action,
7385 crumbled = (direction == MV_NONE ?
7386 el_act2crm(effective_element, effective_action) :
7387 el_act_dir2crm(effective_element, effective_action,
7390 g = &graphic_info[graphic];
7400 if (frame_em == 0) /* reset animation frame for certain elements */
7402 if (check_linear_animation_EM(tile))
7407 if (graphic_info[graphic].anim_global_sync)
7408 sync_frame = FrameCounter;
7409 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7410 sync_frame = GfxFrame[x][y];
7412 sync_frame = 0; /* playfield border (pseudo steel) */
7414 SetRandomAnimationValue(x, y);
7419 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7420 i == Xdrip_stretchB ? 7 :
7421 i == Ydrip_s2 ? j + 8 :
7422 i == Ydrip_s2B ? j + 8 :
7431 i == Xfake_acid_1 ? 0 :
7432 i == Xfake_acid_2 ? 10 :
7433 i == Xfake_acid_3 ? 20 :
7434 i == Xfake_acid_4 ? 30 :
7435 i == Xfake_acid_5 ? 40 :
7436 i == Xfake_acid_6 ? 50 :
7437 i == Xfake_acid_7 ? 60 :
7438 i == Xfake_acid_8 ? 70 :
7440 i == Xball_2B ? j + 8 :
7441 i == Yball_eat ? j + 1 :
7442 i == Ykey_1_eat ? j + 1 :
7443 i == Ykey_2_eat ? j + 1 :
7444 i == Ykey_3_eat ? j + 1 :
7445 i == Ykey_4_eat ? j + 1 :
7446 i == Ykey_5_eat ? j + 1 :
7447 i == Ykey_6_eat ? j + 1 :
7448 i == Ykey_7_eat ? j + 1 :
7449 i == Ykey_8_eat ? j + 1 :
7450 i == Ylenses_eat ? j + 1 :
7451 i == Ymagnify_eat ? j + 1 :
7452 i == Ygrass_eat ? j + 1 :
7453 i == Ydirt_eat ? j + 1 :
7454 i == Xamoeba_1 ? 0 :
7455 i == Xamoeba_2 ? 1 :
7456 i == Xamoeba_3 ? 2 :
7457 i == Xamoeba_4 ? 3 :
7458 i == Xamoeba_5 ? 0 :
7459 i == Xamoeba_6 ? 1 :
7460 i == Xamoeba_7 ? 2 :
7461 i == Xamoeba_8 ? 3 :
7462 i == Xexit_2 ? j + 8 :
7463 i == Xexit_3 ? j + 16 :
7464 i == Xdynamite_1 ? 0 :
7465 i == Xdynamite_2 ? 8 :
7466 i == Xdynamite_3 ? 16 :
7467 i == Xdynamite_4 ? 24 :
7468 i == Xsand_stonein_1 ? j + 1 :
7469 i == Xsand_stonein_2 ? j + 9 :
7470 i == Xsand_stonein_3 ? j + 17 :
7471 i == Xsand_stonein_4 ? j + 25 :
7472 i == Xsand_stoneout_1 && j == 0 ? 0 :
7473 i == Xsand_stoneout_1 && j == 1 ? 0 :
7474 i == Xsand_stoneout_1 && j == 2 ? 1 :
7475 i == Xsand_stoneout_1 && j == 3 ? 2 :
7476 i == Xsand_stoneout_1 && j == 4 ? 2 :
7477 i == Xsand_stoneout_1 && j == 5 ? 3 :
7478 i == Xsand_stoneout_1 && j == 6 ? 4 :
7479 i == Xsand_stoneout_1 && j == 7 ? 4 :
7480 i == Xsand_stoneout_2 && j == 0 ? 5 :
7481 i == Xsand_stoneout_2 && j == 1 ? 6 :
7482 i == Xsand_stoneout_2 && j == 2 ? 7 :
7483 i == Xsand_stoneout_2 && j == 3 ? 8 :
7484 i == Xsand_stoneout_2 && j == 4 ? 9 :
7485 i == Xsand_stoneout_2 && j == 5 ? 11 :
7486 i == Xsand_stoneout_2 && j == 6 ? 13 :
7487 i == Xsand_stoneout_2 && j == 7 ? 15 :
7488 i == Xboom_bug && j == 1 ? 2 :
7489 i == Xboom_bug && j == 2 ? 2 :
7490 i == Xboom_bug && j == 3 ? 4 :
7491 i == Xboom_bug && j == 4 ? 4 :
7492 i == Xboom_bug && j == 5 ? 2 :
7493 i == Xboom_bug && j == 6 ? 2 :
7494 i == Xboom_bug && j == 7 ? 0 :
7495 i == Xboom_bomb && j == 1 ? 2 :
7496 i == Xboom_bomb && j == 2 ? 2 :
7497 i == Xboom_bomb && j == 3 ? 4 :
7498 i == Xboom_bomb && j == 4 ? 4 :
7499 i == Xboom_bomb && j == 5 ? 2 :
7500 i == Xboom_bomb && j == 6 ? 2 :
7501 i == Xboom_bomb && j == 7 ? 0 :
7502 i == Xboom_android && j == 7 ? 6 :
7503 i == Xboom_1 && j == 1 ? 2 :
7504 i == Xboom_1 && j == 2 ? 2 :
7505 i == Xboom_1 && j == 3 ? 4 :
7506 i == Xboom_1 && j == 4 ? 4 :
7507 i == Xboom_1 && j == 5 ? 6 :
7508 i == Xboom_1 && j == 6 ? 6 :
7509 i == Xboom_1 && j == 7 ? 8 :
7510 i == Xboom_2 && j == 0 ? 8 :
7511 i == Xboom_2 && j == 1 ? 8 :
7512 i == Xboom_2 && j == 2 ? 10 :
7513 i == Xboom_2 && j == 3 ? 10 :
7514 i == Xboom_2 && j == 4 ? 10 :
7515 i == Xboom_2 && j == 5 ? 12 :
7516 i == Xboom_2 && j == 6 ? 12 :
7517 i == Xboom_2 && j == 7 ? 12 :
7519 special_animation && j == 4 ? 3 :
7520 effective_action != action ? 0 :
7526 int xxx_effective_action;
7527 int xxx_has_action_graphics;
7530 int element = object_mapping[i].element_rnd;
7531 int action = object_mapping[i].action;
7532 int direction = object_mapping[i].direction;
7533 boolean is_backside = object_mapping[i].is_backside;
7535 boolean action_removing = (action == ACTION_DIGGING ||
7536 action == ACTION_SNAPPING ||
7537 action == ACTION_COLLECTING);
7539 boolean action_exploding = ((action == ACTION_EXPLODING ||
7540 action == ACTION_SMASHED_BY_ROCK ||
7541 action == ACTION_SMASHED_BY_SPRING) &&
7542 element != EL_DIAMOND);
7543 boolean action_active = (action == ACTION_ACTIVE);
7544 boolean action_other = (action == ACTION_OTHER);
7548 int effective_element = get_effective_element_EM(i, j);
7550 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7551 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7553 i == Xdrip_stretch ? element :
7554 i == Xdrip_stretchB ? element :
7555 i == Ydrip_s1 ? element :
7556 i == Ydrip_s1B ? element :
7557 i == Xball_1B ? element :
7558 i == Xball_2 ? element :
7559 i == Xball_2B ? element :
7560 i == Yball_eat ? element :
7561 i == Ykey_1_eat ? element :
7562 i == Ykey_2_eat ? element :
7563 i == Ykey_3_eat ? element :
7564 i == Ykey_4_eat ? element :
7565 i == Ykey_5_eat ? element :
7566 i == Ykey_6_eat ? element :
7567 i == Ykey_7_eat ? element :
7568 i == Ykey_8_eat ? element :
7569 i == Ylenses_eat ? element :
7570 i == Ymagnify_eat ? element :
7571 i == Ygrass_eat ? element :
7572 i == Ydirt_eat ? element :
7573 i == Yemerald_stone ? EL_EMERALD :
7574 i == Ydiamond_stone ? EL_ROCK :
7575 i == Xsand_stonein_1 ? element :
7576 i == Xsand_stonein_2 ? element :
7577 i == Xsand_stonein_3 ? element :
7578 i == Xsand_stonein_4 ? element :
7579 is_backside ? EL_EMPTY :
7580 action_removing ? EL_EMPTY :
7583 int effective_action = (j < 7 ? action :
7584 i == Xdrip_stretch ? action :
7585 i == Xdrip_stretchB ? action :
7586 i == Ydrip_s1 ? action :
7587 i == Ydrip_s1B ? action :
7588 i == Xball_1B ? action :
7589 i == Xball_2 ? action :
7590 i == Xball_2B ? action :
7591 i == Yball_eat ? action :
7592 i == Ykey_1_eat ? action :
7593 i == Ykey_2_eat ? action :
7594 i == Ykey_3_eat ? action :
7595 i == Ykey_4_eat ? action :
7596 i == Ykey_5_eat ? action :
7597 i == Ykey_6_eat ? action :
7598 i == Ykey_7_eat ? action :
7599 i == Ykey_8_eat ? action :
7600 i == Ylenses_eat ? action :
7601 i == Ymagnify_eat ? action :
7602 i == Ygrass_eat ? action :
7603 i == Ydirt_eat ? action :
7604 i == Xsand_stonein_1 ? action :
7605 i == Xsand_stonein_2 ? action :
7606 i == Xsand_stonein_3 ? action :
7607 i == Xsand_stonein_4 ? action :
7608 i == Xsand_stoneout_1 ? action :
7609 i == Xsand_stoneout_2 ? action :
7610 i == Xboom_android ? ACTION_EXPLODING :
7611 action_exploding ? ACTION_EXPLODING :
7612 action_active ? action :
7613 action_other ? action :
7615 int graphic = (el_act_dir2img(effective_element, effective_action,
7617 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7619 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7620 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7621 boolean has_action_graphics = (graphic != base_graphic);
7622 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7623 struct GraphicInfo *g = &graphic_info[graphic];
7625 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7627 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7630 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7631 boolean special_animation = (action != ACTION_DEFAULT &&
7632 g->anim_frames == 3 &&
7633 g->anim_delay == 2 &&
7634 g->anim_mode & ANIM_LINEAR);
7635 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7636 i == Xdrip_stretchB ? 7 :
7637 i == Ydrip_s2 ? j + 8 :
7638 i == Ydrip_s2B ? j + 8 :
7647 i == Xfake_acid_1 ? 0 :
7648 i == Xfake_acid_2 ? 10 :
7649 i == Xfake_acid_3 ? 20 :
7650 i == Xfake_acid_4 ? 30 :
7651 i == Xfake_acid_5 ? 40 :
7652 i == Xfake_acid_6 ? 50 :
7653 i == Xfake_acid_7 ? 60 :
7654 i == Xfake_acid_8 ? 70 :
7656 i == Xball_2B ? j + 8 :
7657 i == Yball_eat ? j + 1 :
7658 i == Ykey_1_eat ? j + 1 :
7659 i == Ykey_2_eat ? j + 1 :
7660 i == Ykey_3_eat ? j + 1 :
7661 i == Ykey_4_eat ? j + 1 :
7662 i == Ykey_5_eat ? j + 1 :
7663 i == Ykey_6_eat ? j + 1 :
7664 i == Ykey_7_eat ? j + 1 :
7665 i == Ykey_8_eat ? j + 1 :
7666 i == Ylenses_eat ? j + 1 :
7667 i == Ymagnify_eat ? j + 1 :
7668 i == Ygrass_eat ? j + 1 :
7669 i == Ydirt_eat ? j + 1 :
7670 i == Xamoeba_1 ? 0 :
7671 i == Xamoeba_2 ? 1 :
7672 i == Xamoeba_3 ? 2 :
7673 i == Xamoeba_4 ? 3 :
7674 i == Xamoeba_5 ? 0 :
7675 i == Xamoeba_6 ? 1 :
7676 i == Xamoeba_7 ? 2 :
7677 i == Xamoeba_8 ? 3 :
7678 i == Xexit_2 ? j + 8 :
7679 i == Xexit_3 ? j + 16 :
7680 i == Xdynamite_1 ? 0 :
7681 i == Xdynamite_2 ? 8 :
7682 i == Xdynamite_3 ? 16 :
7683 i == Xdynamite_4 ? 24 :
7684 i == Xsand_stonein_1 ? j + 1 :
7685 i == Xsand_stonein_2 ? j + 9 :
7686 i == Xsand_stonein_3 ? j + 17 :
7687 i == Xsand_stonein_4 ? j + 25 :
7688 i == Xsand_stoneout_1 && j == 0 ? 0 :
7689 i == Xsand_stoneout_1 && j == 1 ? 0 :
7690 i == Xsand_stoneout_1 && j == 2 ? 1 :
7691 i == Xsand_stoneout_1 && j == 3 ? 2 :
7692 i == Xsand_stoneout_1 && j == 4 ? 2 :
7693 i == Xsand_stoneout_1 && j == 5 ? 3 :
7694 i == Xsand_stoneout_1 && j == 6 ? 4 :
7695 i == Xsand_stoneout_1 && j == 7 ? 4 :
7696 i == Xsand_stoneout_2 && j == 0 ? 5 :
7697 i == Xsand_stoneout_2 && j == 1 ? 6 :
7698 i == Xsand_stoneout_2 && j == 2 ? 7 :
7699 i == Xsand_stoneout_2 && j == 3 ? 8 :
7700 i == Xsand_stoneout_2 && j == 4 ? 9 :
7701 i == Xsand_stoneout_2 && j == 5 ? 11 :
7702 i == Xsand_stoneout_2 && j == 6 ? 13 :
7703 i == Xsand_stoneout_2 && j == 7 ? 15 :
7704 i == Xboom_bug && j == 1 ? 2 :
7705 i == Xboom_bug && j == 2 ? 2 :
7706 i == Xboom_bug && j == 3 ? 4 :
7707 i == Xboom_bug && j == 4 ? 4 :
7708 i == Xboom_bug && j == 5 ? 2 :
7709 i == Xboom_bug && j == 6 ? 2 :
7710 i == Xboom_bug && j == 7 ? 0 :
7711 i == Xboom_bomb && j == 1 ? 2 :
7712 i == Xboom_bomb && j == 2 ? 2 :
7713 i == Xboom_bomb && j == 3 ? 4 :
7714 i == Xboom_bomb && j == 4 ? 4 :
7715 i == Xboom_bomb && j == 5 ? 2 :
7716 i == Xboom_bomb && j == 6 ? 2 :
7717 i == Xboom_bomb && j == 7 ? 0 :
7718 i == Xboom_android && j == 7 ? 6 :
7719 i == Xboom_1 && j == 1 ? 2 :
7720 i == Xboom_1 && j == 2 ? 2 :
7721 i == Xboom_1 && j == 3 ? 4 :
7722 i == Xboom_1 && j == 4 ? 4 :
7723 i == Xboom_1 && j == 5 ? 6 :
7724 i == Xboom_1 && j == 6 ? 6 :
7725 i == Xboom_1 && j == 7 ? 8 :
7726 i == Xboom_2 && j == 0 ? 8 :
7727 i == Xboom_2 && j == 1 ? 8 :
7728 i == Xboom_2 && j == 2 ? 10 :
7729 i == Xboom_2 && j == 3 ? 10 :
7730 i == Xboom_2 && j == 4 ? 10 :
7731 i == Xboom_2 && j == 5 ? 12 :
7732 i == Xboom_2 && j == 6 ? 12 :
7733 i == Xboom_2 && j == 7 ? 12 :
7734 special_animation && j == 4 ? 3 :
7735 effective_action != action ? 0 :
7738 xxx_effective_action = effective_action;
7739 xxx_has_action_graphics = has_action_graphics;
7744 int frame = getAnimationFrame(g->anim_frames,
7747 g->anim_start_frame,
7761 int old_src_x = g_em->src_x;
7762 int old_src_y = g_em->src_y;
7766 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7767 g->double_movement && is_backside);
7769 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7770 &g_em->src_x, &g_em->src_y, FALSE);
7775 if (tile == Ydiamond_stone)
7776 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
7781 g->anim_start_frame,
7784 g_em->src_x, g_em->src_y,
7785 g_em->src_offset_x, g_em->src_offset_y,
7786 g_em->dst_offset_x, g_em->dst_offset_y,
7798 if (graphic == IMG_BUG_MOVING_RIGHT)
7799 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7800 g->double_movement, is_backside,
7801 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7809 g_em->src_offset_x = 0;
7810 g_em->src_offset_y = 0;
7811 g_em->dst_offset_x = 0;
7812 g_em->dst_offset_y = 0;
7813 g_em->width = TILEX;
7814 g_em->height = TILEY;
7816 g_em->preserve_background = FALSE;
7819 /* (updating the "crumbled" graphic definitions is probably not really needed,
7820 as animations for crumbled graphics can't be longer than one EMC cycle) */
7822 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7827 g_em->crumbled_bitmap = NULL;
7828 g_em->crumbled_src_x = 0;
7829 g_em->crumbled_src_y = 0;
7831 g_em->has_crumbled_graphics = FALSE;
7833 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7835 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7836 g_crumbled->anim_delay,
7837 g_crumbled->anim_mode,
7838 g_crumbled->anim_start_frame,
7841 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7842 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7844 g_em->has_crumbled_graphics = TRUE;
7850 int effective_action = xxx_effective_action;
7851 int has_action_graphics = xxx_has_action_graphics;
7853 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7854 effective_action == ACTION_MOVING ||
7855 effective_action == ACTION_PUSHING ||
7856 effective_action == ACTION_EATING)) ||
7857 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7858 effective_action == ACTION_EMPTYING)))
7861 (effective_action == ACTION_FALLING ||
7862 effective_action == ACTION_FILLING ||
7863 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7864 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7865 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7866 int num_steps = (i == Ydrip_s1 ? 16 :
7867 i == Ydrip_s1B ? 16 :
7868 i == Ydrip_s2 ? 16 :
7869 i == Ydrip_s2B ? 16 :
7870 i == Xsand_stonein_1 ? 32 :
7871 i == Xsand_stonein_2 ? 32 :
7872 i == Xsand_stonein_3 ? 32 :
7873 i == Xsand_stonein_4 ? 32 :
7874 i == Xsand_stoneout_1 ? 16 :
7875 i == Xsand_stoneout_2 ? 16 : 8);
7876 int cx = ABS(dx) * (TILEX / num_steps);
7877 int cy = ABS(dy) * (TILEY / num_steps);
7878 int step_frame = (i == Ydrip_s2 ? j + 8 :
7879 i == Ydrip_s2B ? j + 8 :
7880 i == Xsand_stonein_2 ? j + 8 :
7881 i == Xsand_stonein_3 ? j + 16 :
7882 i == Xsand_stonein_4 ? j + 24 :
7883 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7884 int step = (is_backside ? step_frame : num_steps - step_frame);
7886 if (is_backside) /* tile where movement starts */
7888 if (dx < 0 || dy < 0)
7890 g_em->src_offset_x = cx * step;
7891 g_em->src_offset_y = cy * step;
7895 g_em->dst_offset_x = cx * step;
7896 g_em->dst_offset_y = cy * step;
7899 else /* tile where movement ends */
7901 if (dx < 0 || dy < 0)
7903 g_em->dst_offset_x = cx * step;
7904 g_em->dst_offset_y = cy * step;
7908 g_em->src_offset_x = cx * step;
7909 g_em->src_offset_y = cy * step;
7913 g_em->width = TILEX - cx * step;
7914 g_em->height = TILEY - cy * step;
7917 /* create unique graphic identifier to decide if tile must be redrawn */
7918 /* bit 31 - 16 (16 bit): EM style graphic
7919 bit 15 - 12 ( 4 bit): EM style frame
7920 bit 11 - 6 ( 6 bit): graphic width
7921 bit 5 - 0 ( 6 bit): graphic height */
7922 g_em->unique_identifier =
7923 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7929 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7930 int player_nr, int anim, int frame_em)
7932 int element = player_mapping[player_nr][anim].element_rnd;
7933 int action = player_mapping[player_nr][anim].action;
7934 int direction = player_mapping[player_nr][anim].direction;
7935 int graphic = (direction == MV_NONE ?
7936 el_act2img(element, action) :
7937 el_act_dir2img(element, action, direction));
7938 struct GraphicInfo *g = &graphic_info[graphic];
7941 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7943 stored_player[player_nr].StepFrame = frame_em;
7945 sync_frame = stored_player[player_nr].Frame;
7947 int frame = getAnimationFrame(g->anim_frames,
7950 g->anim_start_frame,
7953 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7954 &g_em->src_x, &g_em->src_y, FALSE);
7957 printf("::: %d: %d, %d [%d]\n",
7959 stored_player[player_nr].Frame,
7960 stored_player[player_nr].StepFrame,
7965 void InitGraphicInfo_EM(void)
7968 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7969 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7974 int num_em_gfx_errors = 0;
7976 if (graphic_info_em_object[0][0].bitmap == NULL)
7978 /* EM graphics not yet initialized in em_open_all() */
7983 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7986 /* always start with reliable default values */
7987 for (i = 0; i < TILE_MAX; i++)
7989 object_mapping[i].element_rnd = EL_UNKNOWN;
7990 object_mapping[i].is_backside = FALSE;
7991 object_mapping[i].action = ACTION_DEFAULT;
7992 object_mapping[i].direction = MV_NONE;
7995 /* always start with reliable default values */
7996 for (p = 0; p < MAX_PLAYERS; p++)
7998 for (i = 0; i < SPR_MAX; i++)
8000 player_mapping[p][i].element_rnd = EL_UNKNOWN;
8001 player_mapping[p][i].action = ACTION_DEFAULT;
8002 player_mapping[p][i].direction = MV_NONE;
8006 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8008 int e = em_object_mapping_list[i].element_em;
8010 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8011 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8013 if (em_object_mapping_list[i].action != -1)
8014 object_mapping[e].action = em_object_mapping_list[i].action;
8016 if (em_object_mapping_list[i].direction != -1)
8017 object_mapping[e].direction =
8018 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8021 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8023 int a = em_player_mapping_list[i].action_em;
8024 int p = em_player_mapping_list[i].player_nr;
8026 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8028 if (em_player_mapping_list[i].action != -1)
8029 player_mapping[p][a].action = em_player_mapping_list[i].action;
8031 if (em_player_mapping_list[i].direction != -1)
8032 player_mapping[p][a].direction =
8033 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8036 for (i = 0; i < TILE_MAX; i++)
8038 int element = object_mapping[i].element_rnd;
8039 int action = object_mapping[i].action;
8040 int direction = object_mapping[i].direction;
8041 boolean is_backside = object_mapping[i].is_backside;
8043 boolean action_removing = (action == ACTION_DIGGING ||
8044 action == ACTION_SNAPPING ||
8045 action == ACTION_COLLECTING);
8047 boolean action_exploding = ((action == ACTION_EXPLODING ||
8048 action == ACTION_SMASHED_BY_ROCK ||
8049 action == ACTION_SMASHED_BY_SPRING) &&
8050 element != EL_DIAMOND);
8051 boolean action_active = (action == ACTION_ACTIVE);
8052 boolean action_other = (action == ACTION_OTHER);
8054 for (j = 0; j < 8; j++)
8057 int effective_element = get_effective_element_EM(i, j);
8059 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
8060 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
8062 i == Xdrip_stretch ? element :
8063 i == Xdrip_stretchB ? element :
8064 i == Ydrip_s1 ? element :
8065 i == Ydrip_s1B ? element :
8066 i == Xball_1B ? element :
8067 i == Xball_2 ? element :
8068 i == Xball_2B ? element :
8069 i == Yball_eat ? element :
8070 i == Ykey_1_eat ? element :
8071 i == Ykey_2_eat ? element :
8072 i == Ykey_3_eat ? element :
8073 i == Ykey_4_eat ? element :
8074 i == Ykey_5_eat ? element :
8075 i == Ykey_6_eat ? element :
8076 i == Ykey_7_eat ? element :
8077 i == Ykey_8_eat ? element :
8078 i == Ylenses_eat ? element :
8079 i == Ymagnify_eat ? element :
8080 i == Ygrass_eat ? element :
8081 i == Ydirt_eat ? element :
8082 i == Yemerald_stone ? EL_EMERALD :
8083 i == Ydiamond_stone ? EL_ROCK :
8084 i == Xsand_stonein_1 ? element :
8085 i == Xsand_stonein_2 ? element :
8086 i == Xsand_stonein_3 ? element :
8087 i == Xsand_stonein_4 ? element :
8088 is_backside ? EL_EMPTY :
8089 action_removing ? EL_EMPTY :
8092 int effective_action = (j < 7 ? action :
8093 i == Xdrip_stretch ? action :
8094 i == Xdrip_stretchB ? action :
8095 i == Ydrip_s1 ? action :
8096 i == Ydrip_s1B ? action :
8097 i == Xball_1B ? action :
8098 i == Xball_2 ? action :
8099 i == Xball_2B ? action :
8100 i == Yball_eat ? action :
8101 i == Ykey_1_eat ? action :
8102 i == Ykey_2_eat ? action :
8103 i == Ykey_3_eat ? action :
8104 i == Ykey_4_eat ? action :
8105 i == Ykey_5_eat ? action :
8106 i == Ykey_6_eat ? action :
8107 i == Ykey_7_eat ? action :
8108 i == Ykey_8_eat ? action :
8109 i == Ylenses_eat ? action :
8110 i == Ymagnify_eat ? action :
8111 i == Ygrass_eat ? action :
8112 i == Ydirt_eat ? action :
8113 i == Xsand_stonein_1 ? action :
8114 i == Xsand_stonein_2 ? action :
8115 i == Xsand_stonein_3 ? action :
8116 i == Xsand_stonein_4 ? action :
8117 i == Xsand_stoneout_1 ? action :
8118 i == Xsand_stoneout_2 ? action :
8119 i == Xboom_android ? ACTION_EXPLODING :
8120 action_exploding ? ACTION_EXPLODING :
8121 action_active ? action :
8122 action_other ? action :
8124 int graphic = (el_act_dir2img(effective_element, effective_action,
8126 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8128 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8129 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8130 boolean has_action_graphics = (graphic != base_graphic);
8131 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8132 struct GraphicInfo *g = &graphic_info[graphic];
8134 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8136 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8139 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8140 boolean special_animation = (action != ACTION_DEFAULT &&
8141 g->anim_frames == 3 &&
8142 g->anim_delay == 2 &&
8143 g->anim_mode & ANIM_LINEAR);
8144 int sync_frame = (i == Xdrip_stretch ? 7 :
8145 i == Xdrip_stretchB ? 7 :
8146 i == Ydrip_s2 ? j + 8 :
8147 i == Ydrip_s2B ? j + 8 :
8156 i == Xfake_acid_1 ? 0 :
8157 i == Xfake_acid_2 ? 10 :
8158 i == Xfake_acid_3 ? 20 :
8159 i == Xfake_acid_4 ? 30 :
8160 i == Xfake_acid_5 ? 40 :
8161 i == Xfake_acid_6 ? 50 :
8162 i == Xfake_acid_7 ? 60 :
8163 i == Xfake_acid_8 ? 70 :
8165 i == Xball_2B ? j + 8 :
8166 i == Yball_eat ? j + 1 :
8167 i == Ykey_1_eat ? j + 1 :
8168 i == Ykey_2_eat ? j + 1 :
8169 i == Ykey_3_eat ? j + 1 :
8170 i == Ykey_4_eat ? j + 1 :
8171 i == Ykey_5_eat ? j + 1 :
8172 i == Ykey_6_eat ? j + 1 :
8173 i == Ykey_7_eat ? j + 1 :
8174 i == Ykey_8_eat ? j + 1 :
8175 i == Ylenses_eat ? j + 1 :
8176 i == Ymagnify_eat ? j + 1 :
8177 i == Ygrass_eat ? j + 1 :
8178 i == Ydirt_eat ? j + 1 :
8179 i == Xamoeba_1 ? 0 :
8180 i == Xamoeba_2 ? 1 :
8181 i == Xamoeba_3 ? 2 :
8182 i == Xamoeba_4 ? 3 :
8183 i == Xamoeba_5 ? 0 :
8184 i == Xamoeba_6 ? 1 :
8185 i == Xamoeba_7 ? 2 :
8186 i == Xamoeba_8 ? 3 :
8187 i == Xexit_2 ? j + 8 :
8188 i == Xexit_3 ? j + 16 :
8189 i == Xdynamite_1 ? 0 :
8190 i == Xdynamite_2 ? 8 :
8191 i == Xdynamite_3 ? 16 :
8192 i == Xdynamite_4 ? 24 :
8193 i == Xsand_stonein_1 ? j + 1 :
8194 i == Xsand_stonein_2 ? j + 9 :
8195 i == Xsand_stonein_3 ? j + 17 :
8196 i == Xsand_stonein_4 ? j + 25 :
8197 i == Xsand_stoneout_1 && j == 0 ? 0 :
8198 i == Xsand_stoneout_1 && j == 1 ? 0 :
8199 i == Xsand_stoneout_1 && j == 2 ? 1 :
8200 i == Xsand_stoneout_1 && j == 3 ? 2 :
8201 i == Xsand_stoneout_1 && j == 4 ? 2 :
8202 i == Xsand_stoneout_1 && j == 5 ? 3 :
8203 i == Xsand_stoneout_1 && j == 6 ? 4 :
8204 i == Xsand_stoneout_1 && j == 7 ? 4 :
8205 i == Xsand_stoneout_2 && j == 0 ? 5 :
8206 i == Xsand_stoneout_2 && j == 1 ? 6 :
8207 i == Xsand_stoneout_2 && j == 2 ? 7 :
8208 i == Xsand_stoneout_2 && j == 3 ? 8 :
8209 i == Xsand_stoneout_2 && j == 4 ? 9 :
8210 i == Xsand_stoneout_2 && j == 5 ? 11 :
8211 i == Xsand_stoneout_2 && j == 6 ? 13 :
8212 i == Xsand_stoneout_2 && j == 7 ? 15 :
8213 i == Xboom_bug && j == 1 ? 2 :
8214 i == Xboom_bug && j == 2 ? 2 :
8215 i == Xboom_bug && j == 3 ? 4 :
8216 i == Xboom_bug && j == 4 ? 4 :
8217 i == Xboom_bug && j == 5 ? 2 :
8218 i == Xboom_bug && j == 6 ? 2 :
8219 i == Xboom_bug && j == 7 ? 0 :
8220 i == Xboom_bomb && j == 1 ? 2 :
8221 i == Xboom_bomb && j == 2 ? 2 :
8222 i == Xboom_bomb && j == 3 ? 4 :
8223 i == Xboom_bomb && j == 4 ? 4 :
8224 i == Xboom_bomb && j == 5 ? 2 :
8225 i == Xboom_bomb && j == 6 ? 2 :
8226 i == Xboom_bomb && j == 7 ? 0 :
8227 i == Xboom_android && j == 7 ? 6 :
8228 i == Xboom_1 && j == 1 ? 2 :
8229 i == Xboom_1 && j == 2 ? 2 :
8230 i == Xboom_1 && j == 3 ? 4 :
8231 i == Xboom_1 && j == 4 ? 4 :
8232 i == Xboom_1 && j == 5 ? 6 :
8233 i == Xboom_1 && j == 6 ? 6 :
8234 i == Xboom_1 && j == 7 ? 8 :
8235 i == Xboom_2 && j == 0 ? 8 :
8236 i == Xboom_2 && j == 1 ? 8 :
8237 i == Xboom_2 && j == 2 ? 10 :
8238 i == Xboom_2 && j == 3 ? 10 :
8239 i == Xboom_2 && j == 4 ? 10 :
8240 i == Xboom_2 && j == 5 ? 12 :
8241 i == Xboom_2 && j == 6 ? 12 :
8242 i == Xboom_2 && j == 7 ? 12 :
8243 special_animation && j == 4 ? 3 :
8244 effective_action != action ? 0 :
8248 Bitmap *debug_bitmap = g_em->bitmap;
8249 int debug_src_x = g_em->src_x;
8250 int debug_src_y = g_em->src_y;
8253 int frame = getAnimationFrame(g->anim_frames,
8256 g->anim_start_frame,
8259 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8260 g->double_movement && is_backside);
8262 g_em->bitmap = src_bitmap;
8263 g_em->src_x = src_x;
8264 g_em->src_y = src_y;
8265 g_em->src_offset_x = 0;
8266 g_em->src_offset_y = 0;
8267 g_em->dst_offset_x = 0;
8268 g_em->dst_offset_y = 0;
8269 g_em->width = TILEX;
8270 g_em->height = TILEY;
8272 g_em->preserve_background = FALSE;
8275 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8280 g_em->crumbled_bitmap = NULL;
8281 g_em->crumbled_src_x = 0;
8282 g_em->crumbled_src_y = 0;
8283 g_em->crumbled_border_size = 0;
8285 g_em->has_crumbled_graphics = FALSE;
8288 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
8289 printf("::: empty crumbled: %d [%s], %d, %d\n",
8290 effective_element, element_info[effective_element].token_name,
8291 effective_action, direction);
8294 /* if element can be crumbled, but certain action graphics are just empty
8295 space (like instantly snapping sand to empty space in 1 frame), do not
8296 treat these empty space graphics as crumbled graphics in EMC engine */
8297 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8299 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8300 g_crumbled->anim_delay,
8301 g_crumbled->anim_mode,
8302 g_crumbled->anim_start_frame,
8305 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8307 g_em->has_crumbled_graphics = TRUE;
8308 g_em->crumbled_bitmap = src_bitmap;
8309 g_em->crumbled_src_x = src_x;
8310 g_em->crumbled_src_y = src_y;
8311 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8315 if (g_em == &graphic_info_em_object[207][0])
8316 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8317 graphic_info_em_object[207][0].crumbled_src_x,
8318 graphic_info_em_object[207][0].crumbled_src_y,
8320 crumbled, frame, src_x, src_y,
8325 g->anim_start_frame,
8327 gfx.anim_random_frame,
8332 printf("::: EMC tile %d is crumbled\n", i);
8338 if (element == EL_ROCK &&
8339 effective_action == ACTION_FILLING)
8340 printf("::: has_action_graphics == %d\n", has_action_graphics);
8343 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8344 effective_action == ACTION_MOVING ||
8345 effective_action == ACTION_PUSHING ||
8346 effective_action == ACTION_EATING)) ||
8347 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8348 effective_action == ACTION_EMPTYING)))
8351 (effective_action == ACTION_FALLING ||
8352 effective_action == ACTION_FILLING ||
8353 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8354 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8355 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
8356 int num_steps = (i == Ydrip_s1 ? 16 :
8357 i == Ydrip_s1B ? 16 :
8358 i == Ydrip_s2 ? 16 :
8359 i == Ydrip_s2B ? 16 :
8360 i == Xsand_stonein_1 ? 32 :
8361 i == Xsand_stonein_2 ? 32 :
8362 i == Xsand_stonein_3 ? 32 :
8363 i == Xsand_stonein_4 ? 32 :
8364 i == Xsand_stoneout_1 ? 16 :
8365 i == Xsand_stoneout_2 ? 16 : 8);
8366 int cx = ABS(dx) * (TILEX / num_steps);
8367 int cy = ABS(dy) * (TILEY / num_steps);
8368 int step_frame = (i == Ydrip_s2 ? j + 8 :
8369 i == Ydrip_s2B ? j + 8 :
8370 i == Xsand_stonein_2 ? j + 8 :
8371 i == Xsand_stonein_3 ? j + 16 :
8372 i == Xsand_stonein_4 ? j + 24 :
8373 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8374 int step = (is_backside ? step_frame : num_steps - step_frame);
8376 if (is_backside) /* tile where movement starts */
8378 if (dx < 0 || dy < 0)
8380 g_em->src_offset_x = cx * step;
8381 g_em->src_offset_y = cy * step;
8385 g_em->dst_offset_x = cx * step;
8386 g_em->dst_offset_y = cy * step;
8389 else /* tile where movement ends */
8391 if (dx < 0 || dy < 0)
8393 g_em->dst_offset_x = cx * step;
8394 g_em->dst_offset_y = cy * step;
8398 g_em->src_offset_x = cx * step;
8399 g_em->src_offset_y = cy * step;
8403 g_em->width = TILEX - cx * step;
8404 g_em->height = TILEY - cy * step;
8407 /* create unique graphic identifier to decide if tile must be redrawn */
8408 /* bit 31 - 16 (16 bit): EM style graphic
8409 bit 15 - 12 ( 4 bit): EM style frame
8410 bit 11 - 6 ( 6 bit): graphic width
8411 bit 5 - 0 ( 6 bit): graphic height */
8412 g_em->unique_identifier =
8413 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8417 /* skip check for EMC elements not contained in original EMC artwork */
8418 if (element == EL_EMC_FAKE_ACID)
8421 if (g_em->bitmap != debug_bitmap ||
8422 g_em->src_x != debug_src_x ||
8423 g_em->src_y != debug_src_y ||
8424 g_em->src_offset_x != 0 ||
8425 g_em->src_offset_y != 0 ||
8426 g_em->dst_offset_x != 0 ||
8427 g_em->dst_offset_y != 0 ||
8428 g_em->width != TILEX ||
8429 g_em->height != TILEY)
8431 static int last_i = -1;
8439 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8440 i, element, element_info[element].token_name,
8441 element_action_info[effective_action].suffix, direction);
8443 if (element != effective_element)
8444 printf(" [%d ('%s')]",
8446 element_info[effective_element].token_name);
8450 if (g_em->bitmap != debug_bitmap)
8451 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8452 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8454 if (g_em->src_x != debug_src_x ||
8455 g_em->src_y != debug_src_y)
8456 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8457 j, (is_backside ? 'B' : 'F'),
8458 g_em->src_x, g_em->src_y,
8459 g_em->src_x / 32, g_em->src_y / 32,
8460 debug_src_x, debug_src_y,
8461 debug_src_x / 32, debug_src_y / 32);
8463 if (g_em->src_offset_x != 0 ||
8464 g_em->src_offset_y != 0 ||
8465 g_em->dst_offset_x != 0 ||
8466 g_em->dst_offset_y != 0)
8467 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8469 g_em->src_offset_x, g_em->src_offset_y,
8470 g_em->dst_offset_x, g_em->dst_offset_y);
8472 if (g_em->width != TILEX ||
8473 g_em->height != TILEY)
8474 printf(" %d (%d): size %d,%d should be %d,%d\n",
8476 g_em->width, g_em->height, TILEX, TILEY);
8478 num_em_gfx_errors++;
8485 for (i = 0; i < TILE_MAX; i++)
8487 for (j = 0; j < 8; j++)
8489 int element = object_mapping[i].element_rnd;
8490 int action = object_mapping[i].action;
8491 int direction = object_mapping[i].direction;
8492 boolean is_backside = object_mapping[i].is_backside;
8493 int graphic_action = el_act_dir2img(element, action, direction);
8494 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8496 if ((action == ACTION_SMASHED_BY_ROCK ||
8497 action == ACTION_SMASHED_BY_SPRING ||
8498 action == ACTION_EATING) &&
8499 graphic_action == graphic_default)
8501 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8502 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8503 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8504 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8507 /* no separate animation for "smashed by rock" -- use rock instead */
8508 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8509 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8511 g_em->bitmap = g_xx->bitmap;
8512 g_em->src_x = g_xx->src_x;
8513 g_em->src_y = g_xx->src_y;
8514 g_em->src_offset_x = g_xx->src_offset_x;
8515 g_em->src_offset_y = g_xx->src_offset_y;
8516 g_em->dst_offset_x = g_xx->dst_offset_x;
8517 g_em->dst_offset_y = g_xx->dst_offset_y;
8518 g_em->width = g_xx->width;
8519 g_em->height = g_xx->height;
8520 g_em->unique_identifier = g_xx->unique_identifier;
8523 g_em->preserve_background = TRUE;
8528 for (p = 0; p < MAX_PLAYERS; p++)
8530 for (i = 0; i < SPR_MAX; i++)
8532 int element = player_mapping[p][i].element_rnd;
8533 int action = player_mapping[p][i].action;
8534 int direction = player_mapping[p][i].direction;
8536 for (j = 0; j < 8; j++)
8538 int effective_element = element;
8539 int effective_action = action;
8540 int graphic = (direction == MV_NONE ?
8541 el_act2img(effective_element, effective_action) :
8542 el_act_dir2img(effective_element, effective_action,
8544 struct GraphicInfo *g = &graphic_info[graphic];
8545 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8551 Bitmap *debug_bitmap = g_em->bitmap;
8552 int debug_src_x = g_em->src_x;
8553 int debug_src_y = g_em->src_y;
8556 int frame = getAnimationFrame(g->anim_frames,
8559 g->anim_start_frame,
8562 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8564 g_em->bitmap = src_bitmap;
8565 g_em->src_x = src_x;
8566 g_em->src_y = src_y;
8567 g_em->src_offset_x = 0;
8568 g_em->src_offset_y = 0;
8569 g_em->dst_offset_x = 0;
8570 g_em->dst_offset_y = 0;
8571 g_em->width = TILEX;
8572 g_em->height = TILEY;
8576 /* skip check for EMC elements not contained in original EMC artwork */
8577 if (element == EL_PLAYER_3 ||
8578 element == EL_PLAYER_4)
8581 if (g_em->bitmap != debug_bitmap ||
8582 g_em->src_x != debug_src_x ||
8583 g_em->src_y != debug_src_y)
8585 static int last_i = -1;
8593 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8594 p, i, element, element_info[element].token_name,
8595 element_action_info[effective_action].suffix, direction);
8597 if (element != effective_element)
8598 printf(" [%d ('%s')]",
8600 element_info[effective_element].token_name);
8604 if (g_em->bitmap != debug_bitmap)
8605 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8606 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8608 if (g_em->src_x != debug_src_x ||
8609 g_em->src_y != debug_src_y)
8610 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8612 g_em->src_x, g_em->src_y,
8613 g_em->src_x / 32, g_em->src_y / 32,
8614 debug_src_x, debug_src_y,
8615 debug_src_x / 32, debug_src_y / 32);
8617 num_em_gfx_errors++;
8627 printf("::: [%d errors found]\n", num_em_gfx_errors);
8633 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8634 boolean any_player_moving,
8635 boolean player_is_dropping)
8639 if (tape.single_step && tape.recording && !tape.pausing)
8641 boolean active_players = FALSE;
8643 for (i = 0; i < MAX_PLAYERS; i++)
8644 if (action[i] != JOY_NO_ACTION)
8645 active_players = TRUE;
8648 if (frame == 0 && !player_is_dropping)
8649 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8653 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8654 boolean murphy_is_dropping)
8657 printf("::: waiting: %d, dropping: %d\n",
8658 murphy_is_waiting, murphy_is_dropping);
8661 if (tape.single_step && tape.recording && !tape.pausing)
8663 // if (murphy_is_waiting || murphy_is_dropping)
8664 if (murphy_is_waiting)
8667 printf("::: murphy is waiting -> pause mode\n");
8670 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8675 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8676 int graphic, int sync_frame, int x, int y)
8678 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8680 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8683 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8685 return (IS_NEXT_FRAME(sync_frame, graphic));
8688 int getGraphicInfo_Delay(int graphic)
8690 return graphic_info[graphic].anim_delay;
8693 void PlayMenuSoundExt(int sound)
8695 if (sound == SND_UNDEFINED)
8698 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8699 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8702 if (IS_LOOP_SOUND(sound))
8703 PlaySoundLoop(sound);
8708 void PlayMenuSound()
8710 PlayMenuSoundExt(menu.sound[game_status]);
8713 void PlayMenuSoundStereo(int sound, int stereo_position)
8715 if (sound == SND_UNDEFINED)
8718 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8719 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8722 if (IS_LOOP_SOUND(sound))
8723 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8725 PlaySoundStereo(sound, stereo_position);
8728 void PlayMenuSoundIfLoopExt(int sound)
8730 if (sound == SND_UNDEFINED)
8733 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8734 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8737 if (IS_LOOP_SOUND(sound))
8738 PlaySoundLoop(sound);
8741 void PlayMenuSoundIfLoop()
8743 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8746 void PlayMenuMusicExt(int music)
8748 if (music == MUS_UNDEFINED)
8751 if (!setup.sound_music)
8757 void PlayMenuMusic()
8759 PlayMenuMusicExt(menu.music[game_status]);
8762 void PlaySoundActivating()
8765 PlaySound(SND_MENU_ITEM_ACTIVATING);
8769 void PlaySoundSelecting()
8772 PlaySound(SND_MENU_ITEM_SELECTING);
8776 void ToggleFullscreenIfNeeded()
8778 boolean change_fullscreen = (setup.fullscreen !=
8779 video.fullscreen_enabled);
8780 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8781 !strEqual(setup.fullscreen_mode,
8782 video.fullscreen_mode_current));
8784 if (!video.fullscreen_available)
8787 if (change_fullscreen || change_fullscreen_mode)
8789 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8791 /* save backbuffer content which gets lost when toggling fullscreen mode */
8792 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8794 if (change_fullscreen_mode)
8796 /* keep fullscreen, but change fullscreen mode (screen resolution) */
8797 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
8800 /* toggle fullscreen */
8801 ChangeVideoModeIfNeeded(setup.fullscreen);
8803 setup.fullscreen = video.fullscreen_enabled;
8805 /* restore backbuffer content from temporary backbuffer backup bitmap */
8806 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8808 FreeBitmap(tmp_backbuffer);
8811 /* update visible window/screen */
8812 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8814 redraw_mask = REDRAW_ALL;
8819 void ChangeViewportPropertiesIfNeeded()
8821 int *door_1_x = &DX;
8822 int *door_1_y = &DY;
8823 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
8824 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
8825 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
8826 game_status == GAME_MODE_EDITOR ? game_status :
8828 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8829 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8830 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
8831 int border_size = vp_playfield->border_size;
8832 int new_sx = vp_playfield->x + border_size;
8833 int new_sy = vp_playfield->y + border_size;
8834 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? TILESIZE_VAR :
8835 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8836 int new_sxsize = vp_playfield->width - 2 * border_size;
8837 int new_sysize = vp_playfield->height - 2 * border_size;
8839 int new_scr_fieldx = new_sxsize / tilesize;
8840 int new_scr_fieldy = new_sysize / tilesize;
8842 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
8843 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
8847 /* !!! TEST ONLY !!! */
8848 // InitGfxBuffers();
8852 if (viewport.window.width != WIN_XSIZE ||
8853 viewport.window.height != WIN_YSIZE)
8855 WIN_XSIZE = viewport.window.width;
8856 WIN_YSIZE = viewport.window.height;
8858 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8862 SetDrawDeactivationMask(REDRAW_NONE);
8863 SetDrawBackgroundMask(REDRAW_FIELD);
8865 // RedrawBackground();
8869 if (new_scr_fieldx != SCR_FIELDX ||
8870 new_scr_fieldy != SCR_FIELDY ||
8873 vp_playfield->x != REAL_SX ||
8874 vp_playfield->y != REAL_SY ||
8875 vp_door_1->x != *door_1_x ||
8876 vp_door_1->y != *door_1_y ||
8877 vp_door_2->x != *door_2_x ||
8878 vp_door_2->y != *door_2_y)
8880 SCR_FIELDX = new_scr_fieldx;
8881 SCR_FIELDY = new_scr_fieldy;
8884 REAL_SX = vp_playfield->x;
8885 REAL_SY = vp_playfield->y;
8887 SXSIZE = new_sxsize;
8888 SYSIZE = new_sysize;
8889 FULL_SXSIZE = vp_playfield->width;
8890 FULL_SYSIZE = vp_playfield->width;
8892 *door_1_x = vp_door_1->x;
8893 *door_1_y = vp_door_1->y;
8894 *door_2_x = vp_door_2->x;
8895 *door_2_y = vp_door_2->y;
8899 if (gfx_game_mode == GAME_MODE_MAIN)
8907 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);