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)
120 drawto_field = fieldbuffer;
122 else /* DRAW_BACKBUFFER */
128 BX2 = SCR_FIELDX - 1;
129 BY2 = SCR_FIELDY - 1;
133 drawto_field = backbuffer;
137 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
139 if (game_status == GAME_MODE_PLAYING &&
140 level.game_engine_type == GAME_ENGINE_TYPE_EM)
142 /* currently there is no partial redraw -- always redraw whole playfield */
143 RedrawPlayfield_EM(TRUE);
145 /* blit playfield from scroll buffer to normal back buffer for fading in */
146 BlitScreenToBitmap_EM(backbuffer);
148 else if (game_status == GAME_MODE_PLAYING &&
149 level.game_engine_type == GAME_ENGINE_TYPE_SP)
151 /* currently there is no partial redraw -- always redraw whole playfield */
152 RedrawPlayfield_SP(TRUE);
154 /* blit playfield from scroll buffer to normal back buffer for fading in */
155 BlitScreenToBitmap_SP(backbuffer);
157 else if (game_status == GAME_MODE_PLAYING &&
158 !game.envelope_active)
164 width = gfx.sxsize + 2 * TILEX;
165 height = gfx.sysize + 2 * TILEY;
171 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
172 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
174 for (xx = BX1; xx <= BX2; xx++)
175 for (yy = BY1; yy <= BY2; yy++)
176 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
177 DrawScreenField(xx, yy);
181 if (setup.soft_scrolling)
183 int fx = FX, fy = FY;
185 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
186 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
188 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
200 BlitBitmap(drawto, window, x, y, width, height, x, y);
203 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
205 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
207 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
208 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
211 void DrawMaskedBorder_FIELD()
213 if (global.border_status >= GAME_MODE_TITLE &&
214 global.border_status <= GAME_MODE_PLAYING &&
215 border.draw_masked[global.border_status])
216 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
219 void DrawMaskedBorder_DOOR_1()
221 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
222 (global.border_status != GAME_MODE_EDITOR ||
223 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
224 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
227 void DrawMaskedBorder_DOOR_2()
229 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
230 global.border_status != GAME_MODE_EDITOR)
231 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
234 void DrawMaskedBorder_DOOR_3()
236 /* currently not available */
239 void DrawMaskedBorder_ALL()
241 DrawMaskedBorder_FIELD();
242 DrawMaskedBorder_DOOR_1();
243 DrawMaskedBorder_DOOR_2();
244 DrawMaskedBorder_DOOR_3();
247 void DrawMaskedBorder(int redraw_mask)
249 /* never draw masked screen borders on borderless screens */
250 if (effectiveGameStatus() == GAME_MODE_LOADING ||
251 effectiveGameStatus() == GAME_MODE_TITLE)
254 if (redraw_mask & REDRAW_ALL)
255 DrawMaskedBorder_ALL();
258 if (redraw_mask & REDRAW_FIELD)
259 DrawMaskedBorder_FIELD();
260 if (redraw_mask & REDRAW_DOOR_1)
261 DrawMaskedBorder_DOOR_1();
262 if (redraw_mask & REDRAW_DOOR_2)
263 DrawMaskedBorder_DOOR_2();
264 if (redraw_mask & REDRAW_DOOR_3)
265 DrawMaskedBorder_DOOR_3();
272 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
275 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
276 for (x = 0; x < SCR_FIELDX; x++)
277 for (y = 0 ; y < SCR_FIELDY; y++)
278 if (redraw[redraw_x1 + x][redraw_y1 + y])
279 printf("::: - %d, %d [%s]\n",
280 LEVELX(x), LEVELY(y),
281 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
284 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
285 redraw_mask |= REDRAW_FIELD;
287 if (redraw_mask & REDRAW_FIELD)
288 redraw_mask &= ~REDRAW_TILES;
290 if (redraw_mask == REDRAW_NONE)
293 if (redraw_mask & REDRAW_TILES &&
294 game_status == GAME_MODE_PLAYING &&
295 border.draw_masked[GAME_MODE_PLAYING])
296 redraw_mask |= REDRAW_FIELD;
298 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
300 static boolean last_frame_skipped = FALSE;
301 boolean skip_even_when_not_scrolling = TRUE;
302 boolean just_scrolling = (ScreenMovDir != 0);
303 boolean verbose = FALSE;
305 if (global.fps_slowdown_factor > 1 &&
306 (FrameCounter % global.fps_slowdown_factor) &&
307 (just_scrolling || skip_even_when_not_scrolling))
309 redraw_mask &= ~REDRAW_MAIN;
311 last_frame_skipped = TRUE;
314 printf("FRAME SKIPPED\n");
318 if (last_frame_skipped)
319 redraw_mask |= REDRAW_FIELD;
321 last_frame_skipped = FALSE;
324 printf("frame not skipped\n");
328 /* synchronize X11 graphics at this point; if we would synchronize the
329 display immediately after the buffer switching (after the XFlush),
330 this could mean that we have to wait for the graphics to complete,
331 although we could go on doing calculations for the next frame */
335 /* prevent drawing masked border to backbuffer when using playfield buffer */
336 if (game_status != GAME_MODE_PLAYING ||
337 redraw_mask & REDRAW_FROM_BACKBUFFER ||
338 buffer == backbuffer)
339 DrawMaskedBorder(redraw_mask);
341 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
343 if (redraw_mask & REDRAW_ALL)
345 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
347 redraw_mask = REDRAW_NONE;
350 if (redraw_mask & REDRAW_FIELD)
353 printf("::: REDRAW_FIELD\n");
356 if (game_status != GAME_MODE_PLAYING ||
357 redraw_mask & REDRAW_FROM_BACKBUFFER)
359 BlitBitmap(backbuffer, window,
360 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
364 int fx = FX, fy = FY;
366 if (setup.soft_scrolling)
368 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
369 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
372 if (setup.soft_scrolling ||
373 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
374 ABS(ScreenMovPos) == ScrollStepSize ||
375 redraw_tiles > REDRAWTILES_THRESHOLD)
377 if (border.draw_masked[GAME_MODE_PLAYING])
379 if (buffer != backbuffer)
381 /* copy playfield buffer to backbuffer to add masked border */
382 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
383 DrawMaskedBorder(REDRAW_FIELD);
386 BlitBitmap(backbuffer, window,
387 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
392 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
397 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
399 (setup.soft_scrolling ?
400 "setup.soft_scrolling" :
401 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
402 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
403 ABS(ScreenGfxPos) == ScrollStepSize ?
404 "ABS(ScreenGfxPos) == ScrollStepSize" :
405 "redraw_tiles > REDRAWTILES_THRESHOLD"));
411 redraw_mask &= ~REDRAW_MAIN;
414 if (redraw_mask & REDRAW_DOORS)
416 if (redraw_mask & REDRAW_DOOR_1)
417 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
419 if (redraw_mask & REDRAW_DOOR_2)
420 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
422 if (redraw_mask & REDRAW_DOOR_3)
423 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
425 redraw_mask &= ~REDRAW_DOORS;
428 if (redraw_mask & REDRAW_MICROLEVEL)
430 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
431 SX, SY + 10 * TILEY);
433 redraw_mask &= ~REDRAW_MICROLEVEL;
436 if (redraw_mask & REDRAW_TILES)
439 printf("::: REDRAW_TILES\n");
442 for (x = 0; x < SCR_FIELDX; x++)
443 for (y = 0 ; y < SCR_FIELDY; y++)
444 if (redraw[redraw_x1 + x][redraw_y1 + y])
445 BlitBitmap(buffer, window,
446 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
447 SX + x * TILEX, SY + y * TILEY);
450 if (redraw_mask & REDRAW_FPS) /* display frames per second */
455 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
456 if (!global.fps_slowdown)
459 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
461 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
463 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
469 for (x = 0; x < MAX_BUF_XSIZE; x++)
470 for (y = 0; y < MAX_BUF_YSIZE; y++)
473 redraw_mask = REDRAW_NONE;
476 static void FadeCrossSaveBackbuffer()
478 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
481 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
483 static int fade_type_skip = FADE_TYPE_NONE;
484 void (*draw_border_function)(void) = NULL;
485 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
486 int x, y, width, height;
487 int fade_delay, post_delay;
489 if (fade_type == FADE_TYPE_FADE_OUT)
491 if (fade_type_skip != FADE_TYPE_NONE)
494 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
497 /* skip all fade operations until specified fade operation */
498 if (fade_type & fade_type_skip)
499 fade_type_skip = FADE_TYPE_NONE;
504 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
506 FadeCrossSaveBackbuffer();
512 redraw_mask |= fade_mask;
514 if (fade_type == FADE_TYPE_SKIP)
517 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
520 fade_type_skip = fade_mode;
526 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
531 fade_delay = fading.fade_delay;
532 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
535 if (fade_type_skip != FADE_TYPE_NONE)
538 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
541 /* skip all fade operations until specified fade operation */
542 if (fade_type & fade_type_skip)
543 fade_type_skip = FADE_TYPE_NONE;
553 if (global.autoplay_leveldir)
555 // fading.fade_mode = FADE_MODE_NONE;
562 if (fading.fade_mode == FADE_MODE_NONE)
570 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
573 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
577 if (fade_mask == REDRAW_NONE)
578 fade_mask = REDRAW_FIELD;
581 // if (fade_mask & REDRAW_FIELD)
582 if (fade_mask == REDRAW_FIELD)
587 height = FULL_SYSIZE;
590 fade_delay = fading.fade_delay;
591 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
594 if (border.draw_masked_when_fading)
595 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
597 DrawMaskedBorder_FIELD(); /* draw once */
599 else /* REDRAW_ALL */
607 fade_delay = fading.fade_delay;
608 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
613 if (!setup.fade_screens ||
615 fading.fade_mode == FADE_MODE_NONE)
617 if (!setup.fade_screens || fade_delay == 0)
620 if (fade_mode == FADE_MODE_FADE_OUT)
624 if (fade_mode == FADE_MODE_FADE_OUT &&
625 fading.fade_mode != FADE_MODE_NONE)
626 ClearRectangle(backbuffer, x, y, width, height);
630 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
631 redraw_mask = REDRAW_NONE;
639 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
640 draw_border_function);
642 redraw_mask &= ~fade_mask;
645 void FadeIn(int fade_mask)
647 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
648 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
650 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
653 void FadeOut(int fade_mask)
655 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
656 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
658 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
660 global.border_status = game_status;
663 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
665 static struct TitleFadingInfo fading_leave_stored;
668 fading_leave_stored = fading_leave;
670 fading = fading_leave_stored;
673 void FadeSetEnterMenu()
675 fading = menu.enter_menu;
678 printf("::: storing enter_menu\n");
681 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
684 void FadeSetLeaveMenu()
686 fading = menu.leave_menu;
689 printf("::: storing leave_menu\n");
692 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
695 void FadeSetEnterScreen()
697 fading = menu.enter_screen[game_status];
700 printf("::: storing leave_screen[%d]\n", game_status);
703 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
706 void FadeSetNextScreen()
708 fading = menu.next_screen;
711 printf("::: storing next_screen\n");
714 // (do not overwrite fade mode set by FadeSetEnterScreen)
715 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
718 void FadeSetLeaveScreen()
721 printf("::: recalling last stored value\n");
724 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
727 void FadeSetFromType(int type)
729 if (type & TYPE_ENTER_SCREEN)
730 FadeSetEnterScreen();
731 else if (type & TYPE_ENTER)
733 else if (type & TYPE_LEAVE)
737 void FadeSetDisabled()
739 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
741 fading = fading_none;
744 void FadeSkipNextFadeIn()
746 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
749 void FadeSkipNextFadeOut()
751 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
754 void SetWindowBackgroundImageIfDefined(int graphic)
756 if (graphic_info[graphic].bitmap)
757 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
760 void SetMainBackgroundImageIfDefined(int graphic)
762 if (graphic_info[graphic].bitmap)
763 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
766 void SetDoorBackgroundImageIfDefined(int graphic)
768 if (graphic_info[graphic].bitmap)
769 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
772 void SetWindowBackgroundImage(int graphic)
774 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
775 graphic_info[graphic].bitmap ?
776 graphic_info[graphic].bitmap :
777 graphic_info[IMG_BACKGROUND].bitmap);
780 void SetMainBackgroundImage(int graphic)
782 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
783 graphic_info[graphic].bitmap ?
784 graphic_info[graphic].bitmap :
785 graphic_info[IMG_BACKGROUND].bitmap);
788 void SetDoorBackgroundImage(int graphic)
790 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
791 graphic_info[graphic].bitmap ?
792 graphic_info[graphic].bitmap :
793 graphic_info[IMG_BACKGROUND].bitmap);
796 void SetPanelBackground()
798 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
799 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
801 SetDoorBackgroundBitmap(bitmap_db_panel);
804 void DrawBackground(int x, int y, int width, int height)
806 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
807 /* (when entering hall of fame after playing) */
809 ClearRectangleOnBackground(drawto, x, y, width, height);
811 ClearRectangleOnBackground(backbuffer, x, y, width, height);
814 redraw_mask |= REDRAW_FIELD;
817 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
819 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
821 if (font->bitmap == NULL)
824 DrawBackground(x, y, width, height);
827 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
829 struct GraphicInfo *g = &graphic_info[graphic];
831 if (g->bitmap == NULL)
834 DrawBackground(x, y, width, height);
839 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
840 /* (when entering hall of fame after playing) */
841 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
843 /* !!! maybe this should be done before clearing the background !!! */
844 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
846 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
847 SetDrawtoField(DRAW_BUFFERED);
850 SetDrawtoField(DRAW_BACKBUFFER);
853 void MarkTileDirty(int x, int y)
855 int xx = redraw_x1 + x;
856 int yy = redraw_y1 + y;
861 redraw[xx][yy] = TRUE;
862 redraw_mask |= REDRAW_TILES;
865 void SetBorderElement()
869 BorderElement = EL_EMPTY;
871 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
873 for (x = 0; x < lev_fieldx; x++)
875 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
876 BorderElement = EL_STEELWALL;
878 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
884 void FloodFillLevel(int from_x, int from_y, int fill_element,
885 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
886 int max_fieldx, int max_fieldy)
890 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
891 static int safety = 0;
893 /* check if starting field still has the desired content */
894 if (field[from_x][from_y] == fill_element)
899 if (safety > max_fieldx * max_fieldy)
900 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
902 old_element = field[from_x][from_y];
903 field[from_x][from_y] = fill_element;
905 for (i = 0; i < 4; i++)
907 x = from_x + check[i][0];
908 y = from_y + check[i][1];
910 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
911 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
917 void SetRandomAnimationValue(int x, int y)
919 gfx.anim_random_frame = GfxRandom[x][y];
922 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
924 /* animation synchronized with global frame counter, not move position */
925 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
926 sync_frame = FrameCounter;
928 return getAnimationFrame(graphic_info[graphic].anim_frames,
929 graphic_info[graphic].anim_delay,
930 graphic_info[graphic].anim_mode,
931 graphic_info[graphic].anim_start_frame,
935 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
936 Bitmap **bitmap, int *x, int *y)
940 int width_mult, width_div;
941 int height_mult, height_div;
945 { 15, 16, 2, 3 }, /* 1 x 1 */
946 { 7, 8, 2, 3 }, /* 2 x 2 */
947 { 3, 4, 2, 3 }, /* 4 x 4 */
948 { 1, 2, 2, 3 }, /* 8 x 8 */
949 { 0, 1, 2, 3 }, /* 16 x 16 */
950 { 0, 1, 0, 1 }, /* 32 x 32 */
952 struct GraphicInfo *g = &graphic_info[graphic];
953 Bitmap *src_bitmap = g->bitmap;
954 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
955 int offset_calc_pos = log_2(tilesize);
956 int width_mult = offset_calc[offset_calc_pos].width_mult;
957 int width_div = offset_calc[offset_calc_pos].width_div;
958 int height_mult = offset_calc[offset_calc_pos].height_mult;
959 int height_div = offset_calc[offset_calc_pos].height_div;
960 int startx = src_bitmap->width * width_mult / width_div;
961 int starty = src_bitmap->height * height_mult / height_div;
962 int src_x = g->src_x * tilesize / TILESIZE;
963 int src_y = g->src_y * tilesize / TILESIZE;
964 int width = g->width * tilesize / TILESIZE;
965 int height = g->height * tilesize / TILESIZE;
966 int offset_x = g->offset_x * tilesize / TILESIZE;
967 int offset_y = g->offset_y * tilesize / TILESIZE;
969 if (g->offset_y == 0) /* frames are ordered horizontally */
971 int max_width = g->anim_frames_per_line * width;
972 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
974 src_x = pos % max_width;
975 src_y = src_y % height + pos / max_width * height;
977 else if (g->offset_x == 0) /* frames are ordered vertically */
979 int max_height = g->anim_frames_per_line * height;
980 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
982 src_x = src_x % width + pos / max_height * width;
983 src_y = pos % max_height;
985 else /* frames are ordered diagonally */
987 src_x = src_x + frame * offset_x;
988 src_y = src_y + frame * offset_y;
991 *bitmap = src_bitmap;
996 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
999 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1001 struct GraphicInfo *g = &graphic_info[graphic];
1002 int mini_startx = 0;
1003 int mini_starty = g->bitmap->height * 2 / 3;
1005 *bitmap = g->bitmap;
1006 *x = mini_startx + g->src_x / 2;
1007 *y = mini_starty + g->src_y / 2;
1011 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1012 int *x, int *y, boolean get_backside)
1014 struct GraphicInfo *g = &graphic_info[graphic];
1015 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1016 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1018 *bitmap = g->bitmap;
1020 if (g->offset_y == 0) /* frames are ordered horizontally */
1022 int max_width = g->anim_frames_per_line * g->width;
1023 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1025 *x = pos % max_width;
1026 *y = src_y % g->height + pos / max_width * g->height;
1028 else if (g->offset_x == 0) /* frames are ordered vertically */
1030 int max_height = g->anim_frames_per_line * g->height;
1031 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1033 *x = src_x % g->width + pos / max_height * g->width;
1034 *y = pos % max_height;
1036 else /* frames are ordered diagonally */
1038 *x = src_x + frame * g->offset_x;
1039 *y = src_y + frame * g->offset_y;
1043 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1045 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1048 void DrawGraphic(int x, int y, int graphic, int frame)
1051 if (!IN_SCR_FIELD(x, y))
1053 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1054 printf("DrawGraphic(): This should never happen!\n");
1059 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1060 MarkTileDirty(x, y);
1063 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1069 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1070 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1073 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1076 if (!IN_SCR_FIELD(x, y))
1078 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1079 printf("DrawGraphicThruMask(): This should never happen!\n");
1084 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1086 MarkTileDirty(x, y);
1089 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1095 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1097 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1098 dst_x - src_x, dst_y - src_y);
1099 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1102 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1104 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1106 MarkTileDirty(x / tilesize, y / tilesize);
1109 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1115 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1116 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1119 void DrawMiniGraphic(int x, int y, int graphic)
1121 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1122 MarkTileDirty(x / 2, y / 2);
1125 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1130 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1131 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1134 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1135 int graphic, int frame,
1136 int cut_mode, int mask_mode)
1141 int width = TILEX, height = TILEY;
1144 if (dx || dy) /* shifted graphic */
1146 if (x < BX1) /* object enters playfield from the left */
1153 else if (x > BX2) /* object enters playfield from the right */
1159 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1165 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1167 else if (dx) /* general horizontal movement */
1168 MarkTileDirty(x + SIGN(dx), y);
1170 if (y < BY1) /* object enters playfield from the top */
1172 if (cut_mode==CUT_BELOW) /* object completely above top border */
1180 else if (y > BY2) /* object enters playfield from the bottom */
1186 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1192 else if (dy > 0 && cut_mode == CUT_ABOVE)
1194 if (y == BY2) /* object completely above bottom border */
1200 MarkTileDirty(x, y + 1);
1201 } /* object leaves playfield to the bottom */
1202 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1204 else if (dy) /* general vertical movement */
1205 MarkTileDirty(x, y + SIGN(dy));
1209 if (!IN_SCR_FIELD(x, y))
1211 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1212 printf("DrawGraphicShifted(): This should never happen!\n");
1217 if (width > 0 && height > 0)
1219 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1224 dst_x = FX + x * TILEX + dx;
1225 dst_y = FY + y * TILEY + dy;
1227 if (mask_mode == USE_MASKING)
1229 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1230 dst_x - src_x, dst_y - src_y);
1231 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1235 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1238 MarkTileDirty(x, y);
1242 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1243 int graphic, int frame,
1244 int cut_mode, int mask_mode)
1249 int width = TILEX, height = TILEY;
1252 int x2 = x + SIGN(dx);
1253 int y2 = y + SIGN(dy);
1255 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1256 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1258 /* movement with two-tile animations must be sync'ed with movement position,
1259 not with current GfxFrame (which can be higher when using slow movement) */
1260 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1261 int anim_frames = graphic_info[graphic].anim_frames;
1263 /* (we also need anim_delay here for movement animations with less frames) */
1264 int anim_delay = graphic_info[graphic].anim_delay;
1265 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1267 int sync_frame = anim_pos * anim_frames / TILESIZE;
1270 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1271 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1273 /* re-calculate animation frame for two-tile movement animation */
1274 frame = getGraphicAnimationFrame(graphic, sync_frame);
1278 printf("::: %d, %d, %d => %d [%d]\n",
1279 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1281 printf("::: %d, %d => %d\n",
1282 anim_pos, anim_frames, sync_frame);
1287 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1288 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1291 /* check if movement start graphic inside screen area and should be drawn */
1292 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1294 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1296 dst_x = FX + x1 * TILEX;
1297 dst_y = FY + y1 * TILEY;
1299 if (mask_mode == USE_MASKING)
1301 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1302 dst_x - src_x, dst_y - src_y);
1303 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1307 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1310 MarkTileDirty(x1, y1);
1313 /* check if movement end graphic inside screen area and should be drawn */
1314 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1316 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1318 dst_x = FX + x2 * TILEX;
1319 dst_y = FY + y2 * TILEY;
1321 if (mask_mode == USE_MASKING)
1323 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1324 dst_x - src_x, dst_y - src_y);
1325 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1329 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1332 MarkTileDirty(x2, y2);
1336 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1337 int graphic, int frame,
1338 int cut_mode, int mask_mode)
1342 DrawGraphic(x, y, graphic, frame);
1347 if (graphic_info[graphic].double_movement) /* EM style movement images */
1348 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1350 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1353 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1354 int frame, int cut_mode)
1356 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1359 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1360 int cut_mode, int mask_mode)
1362 int lx = LEVELX(x), ly = LEVELY(y);
1366 if (IN_LEV_FIELD(lx, ly))
1368 SetRandomAnimationValue(lx, ly);
1370 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1371 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1373 /* do not use double (EM style) movement graphic when not moving */
1374 if (graphic_info[graphic].double_movement && !dx && !dy)
1376 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1377 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1380 else /* border element */
1382 graphic = el2img(element);
1383 frame = getGraphicAnimationFrame(graphic, -1);
1386 if (element == EL_EXPANDABLE_WALL)
1388 boolean left_stopped = FALSE, right_stopped = FALSE;
1390 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1391 left_stopped = TRUE;
1392 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1393 right_stopped = TRUE;
1395 if (left_stopped && right_stopped)
1397 else if (left_stopped)
1399 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1400 frame = graphic_info[graphic].anim_frames - 1;
1402 else if (right_stopped)
1404 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1405 frame = graphic_info[graphic].anim_frames - 1;
1410 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1411 else if (mask_mode == USE_MASKING)
1412 DrawGraphicThruMask(x, y, graphic, frame);
1414 DrawGraphic(x, y, graphic, frame);
1417 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1418 int cut_mode, int mask_mode)
1420 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1421 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1422 cut_mode, mask_mode);
1425 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1428 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1431 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1434 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1437 void DrawLevelElementThruMask(int x, int y, int element)
1439 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1442 void DrawLevelFieldThruMask(int x, int y)
1444 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1447 /* !!! implementation of quicksand is totally broken !!! */
1448 #define IS_CRUMBLED_TILE(x, y, e) \
1449 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1450 !IS_MOVING(x, y) || \
1451 (e) == EL_QUICKSAND_EMPTYING || \
1452 (e) == EL_QUICKSAND_FAST_EMPTYING))
1454 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1459 int width, height, cx, cy;
1460 int sx = SCREENX(x), sy = SCREENY(y);
1461 int crumbled_border_size = graphic_info[graphic].border_size;
1464 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1466 for (i = 1; i < 4; i++)
1468 int dxx = (i & 1 ? dx : 0);
1469 int dyy = (i & 2 ? dy : 0);
1472 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1475 /* check if neighbour field is of same crumble type */
1476 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1477 graphic_info[graphic].class ==
1478 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1480 /* return if check prevents inner corner */
1481 if (same == (dxx == dx && dyy == dy))
1485 /* if we reach this point, we have an inner corner */
1487 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1489 width = crumbled_border_size;
1490 height = crumbled_border_size;
1491 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1492 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1494 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1495 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1498 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1503 int width, height, bx, by, cx, cy;
1504 int sx = SCREENX(x), sy = SCREENY(y);
1505 int crumbled_border_size = graphic_info[graphic].border_size;
1508 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1510 /* draw simple, sloppy, non-corner-accurate crumbled border */
1513 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1514 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1515 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1516 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1518 if (dir == 1 || dir == 2) /* left or right crumbled border */
1520 width = crumbled_border_size;
1522 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1525 else /* top or bottom crumbled border */
1528 height = crumbled_border_size;
1530 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1534 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1535 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1537 /* (remaining middle border part must be at least as big as corner part) */
1538 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1539 crumbled_border_size >= TILESIZE / 3)
1542 /* correct corners of crumbled border, if needed */
1545 for (i = -1; i <= 1; i+=2)
1547 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1548 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1549 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1552 /* check if neighbour field is of same crumble type */
1553 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1554 graphic_info[graphic].class ==
1555 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1557 /* no crumbled corner, but continued crumbled border */
1559 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
1560 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
1561 int b1 = (i == 1 ? crumbled_border_size :
1562 TILESIZE - 2 * crumbled_border_size);
1564 width = crumbled_border_size;
1565 height = crumbled_border_size;
1567 if (dir == 1 || dir == 2)
1582 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1583 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1587 if (dir == 1 || dir == 2) /* left or right crumbled border */
1589 for (i = -1; i <= 1; i+=2)
1593 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1596 /* check if neighbour field is of same crumble type */
1597 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1598 graphic_info[graphic].class ==
1599 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1601 /* no crumbled corner, but continued crumbled border */
1603 width = crumbled_border_size;
1604 height = crumbled_border_size;
1605 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1606 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
1608 by = (i == 1 ? crumbled_border_size :
1609 TILEY - 2 * crumbled_border_size);
1611 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1612 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1616 else /* top or bottom crumbled border */
1618 for (i = -1; i <= 1; i+=2)
1622 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1625 /* check if neighbour field is of same crumble type */
1626 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1627 graphic_info[graphic].class ==
1628 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1630 /* no crumbled corner, but continued crumbled border */
1632 width = crumbled_border_size;
1633 height = crumbled_border_size;
1634 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1635 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1636 bx = (i == 1 ? crumbled_border_size :
1637 TILEX - 2 * crumbled_border_size);
1640 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1641 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1648 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1650 int sx = SCREENX(x), sy = SCREENY(y);
1653 static int xy[4][2] =
1661 if (!IN_LEV_FIELD(x, y))
1664 element = TILE_GFX_ELEMENT(x, y);
1666 /* crumble field itself */
1667 if (IS_CRUMBLED_TILE(x, y, element))
1669 if (!IN_SCR_FIELD(sx, sy))
1672 for (i = 0; i < 4; i++)
1674 int xx = x + xy[i][0];
1675 int yy = y + xy[i][1];
1677 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1680 /* check if neighbour field is of same crumble type */
1682 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1683 graphic_info[graphic].class ==
1684 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1687 if (IS_CRUMBLED_TILE(xx, yy, element))
1691 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1694 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1695 graphic_info[graphic].anim_frames == 2)
1697 for (i = 0; i < 4; i++)
1699 int dx = (i & 1 ? +1 : -1);
1700 int dy = (i & 2 ? +1 : -1);
1702 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1706 MarkTileDirty(sx, sy);
1708 else /* center field not crumbled -- crumble neighbour fields */
1710 for (i = 0; i < 4; i++)
1712 int xx = x + xy[i][0];
1713 int yy = y + xy[i][1];
1714 int sxx = sx + xy[i][0];
1715 int syy = sy + xy[i][1];
1717 if (!IN_LEV_FIELD(xx, yy) ||
1718 !IN_SCR_FIELD(sxx, syy))
1721 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1724 element = TILE_GFX_ELEMENT(xx, yy);
1726 if (!IS_CRUMBLED_TILE(xx, yy, element))
1729 graphic = el_act2crm(element, ACTION_DEFAULT);
1731 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1733 MarkTileDirty(sxx, syy);
1738 void DrawLevelFieldCrumbled(int x, int y)
1742 if (!IN_LEV_FIELD(x, y))
1746 /* !!! CHECK THIS !!! */
1749 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1750 GFX_CRUMBLED(GfxElement[x][y]))
1753 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1754 GfxElement[x][y] != EL_UNDEFINED &&
1755 GFX_CRUMBLED(GfxElement[x][y]))
1757 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1764 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1766 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1769 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1772 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1775 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1776 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1777 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1778 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1779 int sx = SCREENX(x), sy = SCREENY(y);
1781 DrawGraphic(sx, sy, graphic1, frame1);
1782 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1785 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1787 int sx = SCREENX(x), sy = SCREENY(y);
1788 static int xy[4][2] =
1797 for (i = 0; i < 4; i++)
1799 int xx = x + xy[i][0];
1800 int yy = y + xy[i][1];
1801 int sxx = sx + xy[i][0];
1802 int syy = sy + xy[i][1];
1804 if (!IN_LEV_FIELD(xx, yy) ||
1805 !IN_SCR_FIELD(sxx, syy) ||
1806 !GFX_CRUMBLED(Feld[xx][yy]) ||
1810 DrawLevelField(xx, yy);
1814 static int getBorderElement(int x, int y)
1818 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1819 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1820 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1821 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1822 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1823 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1824 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1826 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1827 int steel_position = (x == -1 && y == -1 ? 0 :
1828 x == lev_fieldx && y == -1 ? 1 :
1829 x == -1 && y == lev_fieldy ? 2 :
1830 x == lev_fieldx && y == lev_fieldy ? 3 :
1831 x == -1 || x == lev_fieldx ? 4 :
1832 y == -1 || y == lev_fieldy ? 5 : 6);
1834 return border[steel_position][steel_type];
1837 void DrawScreenElement(int x, int y, int element)
1839 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1840 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1843 void DrawLevelElement(int x, int y, int element)
1845 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1846 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1849 void DrawScreenField(int x, int y)
1851 int lx = LEVELX(x), ly = LEVELY(y);
1852 int element, content;
1854 if (!IN_LEV_FIELD(lx, ly))
1856 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1859 element = getBorderElement(lx, ly);
1861 DrawScreenElement(x, y, element);
1866 element = Feld[lx][ly];
1867 content = Store[lx][ly];
1869 if (IS_MOVING(lx, ly))
1871 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1872 boolean cut_mode = NO_CUTTING;
1874 if (element == EL_QUICKSAND_EMPTYING ||
1875 element == EL_QUICKSAND_FAST_EMPTYING ||
1876 element == EL_MAGIC_WALL_EMPTYING ||
1877 element == EL_BD_MAGIC_WALL_EMPTYING ||
1878 element == EL_DC_MAGIC_WALL_EMPTYING ||
1879 element == EL_AMOEBA_DROPPING)
1880 cut_mode = CUT_ABOVE;
1881 else if (element == EL_QUICKSAND_FILLING ||
1882 element == EL_QUICKSAND_FAST_FILLING ||
1883 element == EL_MAGIC_WALL_FILLING ||
1884 element == EL_BD_MAGIC_WALL_FILLING ||
1885 element == EL_DC_MAGIC_WALL_FILLING)
1886 cut_mode = CUT_BELOW;
1889 if (lx == 9 && ly == 1)
1890 printf("::: %s [%d] [%d, %d] [%d]\n",
1891 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1892 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1893 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1894 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1895 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1898 if (cut_mode == CUT_ABOVE)
1900 DrawScreenElement(x, y, element);
1902 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1905 DrawScreenElement(x, y, EL_EMPTY);
1908 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1909 else if (cut_mode == NO_CUTTING)
1910 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1913 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1916 if (cut_mode == CUT_BELOW &&
1917 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1918 DrawLevelElement(lx, ly + 1, element);
1922 if (content == EL_ACID)
1924 int dir = MovDir[lx][ly];
1925 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1926 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1928 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1931 else if (IS_BLOCKED(lx, ly))
1936 boolean cut_mode = NO_CUTTING;
1937 int element_old, content_old;
1939 Blocked2Moving(lx, ly, &oldx, &oldy);
1942 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1943 MovDir[oldx][oldy] == MV_RIGHT);
1945 element_old = Feld[oldx][oldy];
1946 content_old = Store[oldx][oldy];
1948 if (element_old == EL_QUICKSAND_EMPTYING ||
1949 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1950 element_old == EL_MAGIC_WALL_EMPTYING ||
1951 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1952 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1953 element_old == EL_AMOEBA_DROPPING)
1954 cut_mode = CUT_ABOVE;
1956 DrawScreenElement(x, y, EL_EMPTY);
1959 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1961 else if (cut_mode == NO_CUTTING)
1962 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1965 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1968 else if (IS_DRAWABLE(element))
1969 DrawScreenElement(x, y, element);
1971 DrawScreenElement(x, y, EL_EMPTY);
1974 void DrawLevelField(int x, int y)
1976 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1977 DrawScreenField(SCREENX(x), SCREENY(y));
1978 else if (IS_MOVING(x, y))
1982 Moving2Blocked(x, y, &newx, &newy);
1983 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1984 DrawScreenField(SCREENX(newx), SCREENY(newy));
1986 else if (IS_BLOCKED(x, y))
1990 Blocked2Moving(x, y, &oldx, &oldy);
1991 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1992 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1996 void DrawMiniElement(int x, int y, int element)
2000 graphic = el2edimg(element);
2001 DrawMiniGraphic(x, y, graphic);
2004 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2006 int x = sx + scroll_x, y = sy + scroll_y;
2008 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2009 DrawMiniElement(sx, sy, EL_EMPTY);
2010 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2011 DrawMiniElement(sx, sy, Feld[x][y]);
2013 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2016 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
2017 int x, int y, int xsize, int ysize, int font_nr)
2019 int font_width = getFontWidth(font_nr);
2020 int font_height = getFontHeight(font_nr);
2021 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2024 int dst_x = SX + startx + x * font_width;
2025 int dst_y = SY + starty + y * font_height;
2026 int width = graphic_info[graphic].width;
2027 int height = graphic_info[graphic].height;
2028 int inner_width = MAX(width - 2 * font_width, font_width);
2029 int inner_height = MAX(height - 2 * font_height, font_height);
2030 int inner_sx = (width >= 3 * font_width ? font_width : 0);
2031 int inner_sy = (height >= 3 * font_height ? font_height : 0);
2032 boolean draw_masked = graphic_info[graphic].draw_masked;
2034 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2036 if (src_bitmap == NULL || width < font_width || height < font_height)
2038 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
2042 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
2043 inner_sx + (x - 1) * font_width % inner_width);
2044 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
2045 inner_sy + (y - 1) * font_height % inner_height);
2049 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2050 dst_x - src_x, dst_y - src_y);
2051 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2055 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2059 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2061 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2062 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2063 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2064 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2065 boolean no_delay = (tape.warp_forward);
2066 unsigned long anim_delay = 0;
2067 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2068 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2069 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2070 int font_width = getFontWidth(font_nr);
2071 int font_height = getFontHeight(font_nr);
2072 int max_xsize = level.envelope[envelope_nr].xsize;
2073 int max_ysize = level.envelope[envelope_nr].ysize;
2074 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2075 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2076 int xend = max_xsize;
2077 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2078 int xstep = (xstart < xend ? 1 : 0);
2079 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2082 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2084 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2085 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2086 int sx = (SXSIZE - xsize * font_width) / 2;
2087 int sy = (SYSIZE - ysize * font_height) / 2;
2090 SetDrawtoField(DRAW_BUFFERED);
2092 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2094 SetDrawtoField(DRAW_BACKBUFFER);
2096 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2097 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2100 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2101 level.envelope[envelope_nr].text, font_nr, max_xsize,
2102 xsize - 2, ysize - 2, mask_mode,
2103 level.envelope[envelope_nr].autowrap,
2104 level.envelope[envelope_nr].centered, FALSE);
2106 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2107 level.envelope[envelope_nr].text, font_nr, max_xsize,
2108 xsize - 2, ysize - 2, mask_mode);
2111 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2114 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2118 void ShowEnvelope(int envelope_nr)
2120 int element = EL_ENVELOPE_1 + envelope_nr;
2121 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2122 int sound_opening = element_info[element].sound[ACTION_OPENING];
2123 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2124 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2125 boolean no_delay = (tape.warp_forward);
2126 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2127 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2128 int anim_mode = graphic_info[graphic].anim_mode;
2129 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2130 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2132 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2134 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2136 if (anim_mode == ANIM_DEFAULT)
2137 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2139 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2142 Delay(wait_delay_value);
2144 WaitForEventToContinue();
2146 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2148 if (anim_mode != ANIM_NONE)
2149 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2151 if (anim_mode == ANIM_DEFAULT)
2152 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2154 game.envelope_active = FALSE;
2156 SetDrawtoField(DRAW_BUFFERED);
2158 redraw_mask |= REDRAW_FIELD;
2162 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2166 int graphic = el2preimg(element);
2168 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2169 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2177 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2178 SetDrawBackgroundMask(REDRAW_FIELD);
2180 SetDrawBackgroundMask(REDRAW_NONE);
2185 for (x = BX1; x <= BX2; x++)
2186 for (y = BY1; y <= BY2; y++)
2187 DrawScreenField(x, y);
2189 redraw_mask |= REDRAW_FIELD;
2192 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2196 for (x = 0; x < size_x; x++)
2197 for (y = 0; y < size_y; y++)
2198 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2200 redraw_mask |= REDRAW_FIELD;
2203 static void DrawPreviewLevelExt(int from_x, int from_y)
2205 boolean show_level_border = (BorderElement != EL_EMPTY);
2206 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2207 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2208 int tile_size = preview.tile_size;
2209 int preview_width = preview.xsize * tile_size;
2210 int preview_height = preview.ysize * tile_size;
2211 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2212 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2213 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2214 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2217 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2219 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2220 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2222 for (x = 0; x < real_preview_xsize; x++)
2224 for (y = 0; y < real_preview_ysize; y++)
2226 int lx = from_x + x + (show_level_border ? -1 : 0);
2227 int ly = from_y + y + (show_level_border ? -1 : 0);
2228 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2229 getBorderElement(lx, ly));
2231 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2232 element, tile_size);
2236 redraw_mask |= REDRAW_MICROLEVEL;
2239 #define MICROLABEL_EMPTY 0
2240 #define MICROLABEL_LEVEL_NAME 1
2241 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2242 #define MICROLABEL_LEVEL_AUTHOR 3
2243 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2244 #define MICROLABEL_IMPORTED_FROM 5
2245 #define MICROLABEL_IMPORTED_BY_HEAD 6
2246 #define MICROLABEL_IMPORTED_BY 7
2248 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2250 int max_text_width = SXSIZE;
2251 int font_width = getFontWidth(font_nr);
2253 if (pos->align == ALIGN_CENTER)
2254 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2255 else if (pos->align == ALIGN_RIGHT)
2256 max_text_width = pos->x;
2258 max_text_width = SXSIZE - pos->x;
2260 return max_text_width / font_width;
2263 static void DrawPreviewLevelLabelExt(int mode)
2265 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2266 char label_text[MAX_OUTPUT_LINESIZE + 1];
2267 int max_len_label_text;
2269 int font_nr = pos->font;
2272 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2273 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2274 mode == MICROLABEL_IMPORTED_BY_HEAD)
2275 font_nr = pos->font_alt;
2277 int font_nr = FONT_TEXT_2;
2280 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2281 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2282 mode == MICROLABEL_IMPORTED_BY_HEAD)
2283 font_nr = FONT_TEXT_3;
2287 max_len_label_text = getMaxTextLength(pos, font_nr);
2289 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2293 if (pos->size != -1)
2294 max_len_label_text = pos->size;
2297 for (i = 0; i < max_len_label_text; i++)
2298 label_text[i] = ' ';
2299 label_text[max_len_label_text] = '\0';
2301 if (strlen(label_text) > 0)
2304 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2306 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2307 int lypos = MICROLABEL2_YPOS;
2309 DrawText(lxpos, lypos, label_text, font_nr);
2314 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2315 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2316 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2317 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2318 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2319 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2320 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2321 max_len_label_text);
2322 label_text[max_len_label_text] = '\0';
2324 if (strlen(label_text) > 0)
2327 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2329 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2330 int lypos = MICROLABEL2_YPOS;
2332 DrawText(lxpos, lypos, label_text, font_nr);
2336 redraw_mask |= REDRAW_MICROLEVEL;
2339 void DrawPreviewLevel(boolean restart)
2341 static unsigned long scroll_delay = 0;
2342 static unsigned long label_delay = 0;
2343 static int from_x, from_y, scroll_direction;
2344 static int label_state, label_counter;
2345 unsigned long scroll_delay_value = preview.step_delay;
2346 boolean show_level_border = (BorderElement != EL_EMPTY);
2347 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2348 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2349 int last_game_status = game_status; /* save current game status */
2352 /* force PREVIEW font on preview level */
2353 game_status = GAME_MODE_PSEUDO_PREVIEW;
2361 if (preview.anim_mode == ANIM_CENTERED)
2363 if (level_xsize > preview.xsize)
2364 from_x = (level_xsize - preview.xsize) / 2;
2365 if (level_ysize > preview.ysize)
2366 from_y = (level_ysize - preview.ysize) / 2;
2369 from_x += preview.xoffset;
2370 from_y += preview.yoffset;
2372 scroll_direction = MV_RIGHT;
2376 DrawPreviewLevelExt(from_x, from_y);
2377 DrawPreviewLevelLabelExt(label_state);
2379 /* initialize delay counters */
2380 DelayReached(&scroll_delay, 0);
2381 DelayReached(&label_delay, 0);
2383 if (leveldir_current->name)
2385 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2386 char label_text[MAX_OUTPUT_LINESIZE + 1];
2388 int font_nr = pos->font;
2390 int font_nr = FONT_TEXT_1;
2393 int max_len_label_text = getMaxTextLength(pos, font_nr);
2395 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2403 if (pos->size != -1)
2404 max_len_label_text = pos->size;
2407 strncpy(label_text, leveldir_current->name, max_len_label_text);
2408 label_text[max_len_label_text] = '\0';
2411 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2413 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2414 lypos = SY + MICROLABEL1_YPOS;
2416 DrawText(lxpos, lypos, label_text, font_nr);
2420 game_status = last_game_status; /* restore current game status */
2425 /* scroll preview level, if needed */
2426 if (preview.anim_mode != ANIM_NONE &&
2427 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2428 DelayReached(&scroll_delay, scroll_delay_value))
2430 switch (scroll_direction)
2435 from_x -= preview.step_offset;
2436 from_x = (from_x < 0 ? 0 : from_x);
2439 scroll_direction = MV_UP;
2443 if (from_x < level_xsize - preview.xsize)
2445 from_x += preview.step_offset;
2446 from_x = (from_x > level_xsize - preview.xsize ?
2447 level_xsize - preview.xsize : from_x);
2450 scroll_direction = MV_DOWN;
2456 from_y -= preview.step_offset;
2457 from_y = (from_y < 0 ? 0 : from_y);
2460 scroll_direction = MV_RIGHT;
2464 if (from_y < level_ysize - preview.ysize)
2466 from_y += preview.step_offset;
2467 from_y = (from_y > level_ysize - preview.ysize ?
2468 level_ysize - preview.ysize : from_y);
2471 scroll_direction = MV_LEFT;
2478 DrawPreviewLevelExt(from_x, from_y);
2481 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2482 /* redraw micro level label, if needed */
2483 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2484 !strEqual(level.author, ANONYMOUS_NAME) &&
2485 !strEqual(level.author, leveldir_current->name) &&
2486 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2488 int max_label_counter = 23;
2490 if (leveldir_current->imported_from != NULL &&
2491 strlen(leveldir_current->imported_from) > 0)
2492 max_label_counter += 14;
2493 if (leveldir_current->imported_by != NULL &&
2494 strlen(leveldir_current->imported_by) > 0)
2495 max_label_counter += 14;
2497 label_counter = (label_counter + 1) % max_label_counter;
2498 label_state = (label_counter >= 0 && label_counter <= 7 ?
2499 MICROLABEL_LEVEL_NAME :
2500 label_counter >= 9 && label_counter <= 12 ?
2501 MICROLABEL_LEVEL_AUTHOR_HEAD :
2502 label_counter >= 14 && label_counter <= 21 ?
2503 MICROLABEL_LEVEL_AUTHOR :
2504 label_counter >= 23 && label_counter <= 26 ?
2505 MICROLABEL_IMPORTED_FROM_HEAD :
2506 label_counter >= 28 && label_counter <= 35 ?
2507 MICROLABEL_IMPORTED_FROM :
2508 label_counter >= 37 && label_counter <= 40 ?
2509 MICROLABEL_IMPORTED_BY_HEAD :
2510 label_counter >= 42 && label_counter <= 49 ?
2511 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2513 if (leveldir_current->imported_from == NULL &&
2514 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2515 label_state == MICROLABEL_IMPORTED_FROM))
2516 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2517 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2519 DrawPreviewLevelLabelExt(label_state);
2522 game_status = last_game_status; /* restore current game status */
2525 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2526 int graphic, int sync_frame, int mask_mode)
2528 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2530 if (mask_mode == USE_MASKING)
2531 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2533 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2536 inline void DrawGraphicAnimation(int x, int y, int graphic)
2538 int lx = LEVELX(x), ly = LEVELY(y);
2540 if (!IN_SCR_FIELD(x, y))
2543 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2544 graphic, GfxFrame[lx][ly], NO_MASKING);
2545 MarkTileDirty(x, y);
2548 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2550 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2553 void DrawLevelElementAnimation(int x, int y, int element)
2555 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2557 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2560 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2562 int sx = SCREENX(x), sy = SCREENY(y);
2564 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2567 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2570 DrawGraphicAnimation(sx, sy, graphic);
2573 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2574 DrawLevelFieldCrumbled(x, y);
2576 if (GFX_CRUMBLED(Feld[x][y]))
2577 DrawLevelFieldCrumbled(x, y);
2581 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2583 int sx = SCREENX(x), sy = SCREENY(y);
2586 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2589 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2591 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2594 DrawGraphicAnimation(sx, sy, graphic);
2596 if (GFX_CRUMBLED(element))
2597 DrawLevelFieldCrumbled(x, y);
2600 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2602 if (player->use_murphy)
2604 /* this works only because currently only one player can be "murphy" ... */
2605 static int last_horizontal_dir = MV_LEFT;
2606 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2608 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2609 last_horizontal_dir = move_dir;
2611 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2613 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2615 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2621 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2624 static boolean equalGraphics(int graphic1, int graphic2)
2626 struct GraphicInfo *g1 = &graphic_info[graphic1];
2627 struct GraphicInfo *g2 = &graphic_info[graphic2];
2629 return (g1->bitmap == g2->bitmap &&
2630 g1->src_x == g2->src_x &&
2631 g1->src_y == g2->src_y &&
2632 g1->anim_frames == g2->anim_frames &&
2633 g1->anim_delay == g2->anim_delay &&
2634 g1->anim_mode == g2->anim_mode);
2637 void DrawAllPlayers()
2641 for (i = 0; i < MAX_PLAYERS; i++)
2642 if (stored_player[i].active)
2643 DrawPlayer(&stored_player[i]);
2646 void DrawPlayerField(int x, int y)
2648 if (!IS_PLAYER(x, y))
2651 DrawPlayer(PLAYERINFO(x, y));
2654 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2656 void DrawPlayer(struct PlayerInfo *player)
2658 int jx = player->jx;
2659 int jy = player->jy;
2660 int move_dir = player->MovDir;
2661 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2662 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2663 int last_jx = (player->is_moving ? jx - dx : jx);
2664 int last_jy = (player->is_moving ? jy - dy : jy);
2665 int next_jx = jx + dx;
2666 int next_jy = jy + dy;
2667 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2668 boolean player_is_opaque = FALSE;
2669 int sx = SCREENX(jx), sy = SCREENY(jy);
2670 int sxx = 0, syy = 0;
2671 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2673 int action = ACTION_DEFAULT;
2674 int last_player_graphic = getPlayerGraphic(player, move_dir);
2675 int last_player_frame = player->Frame;
2678 /* GfxElement[][] is set to the element the player is digging or collecting;
2679 remove also for off-screen player if the player is not moving anymore */
2680 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2681 GfxElement[jx][jy] = EL_UNDEFINED;
2683 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2687 if (!IN_LEV_FIELD(jx, jy))
2689 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2690 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2691 printf("DrawPlayerField(): This should never happen!\n");
2696 if (element == EL_EXPLOSION)
2699 action = (player->is_pushing ? ACTION_PUSHING :
2700 player->is_digging ? ACTION_DIGGING :
2701 player->is_collecting ? ACTION_COLLECTING :
2702 player->is_moving ? ACTION_MOVING :
2703 player->is_snapping ? ACTION_SNAPPING :
2704 player->is_dropping ? ACTION_DROPPING :
2705 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2707 if (player->is_waiting)
2708 move_dir = player->dir_waiting;
2710 InitPlayerGfxAnimation(player, action, move_dir);
2712 /* ----------------------------------------------------------------------- */
2713 /* draw things in the field the player is leaving, if needed */
2714 /* ----------------------------------------------------------------------- */
2716 if (player->is_moving)
2718 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2720 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2722 if (last_element == EL_DYNAMITE_ACTIVE ||
2723 last_element == EL_EM_DYNAMITE_ACTIVE ||
2724 last_element == EL_SP_DISK_RED_ACTIVE)
2725 DrawDynamite(last_jx, last_jy);
2727 DrawLevelFieldThruMask(last_jx, last_jy);
2729 else if (last_element == EL_DYNAMITE_ACTIVE ||
2730 last_element == EL_EM_DYNAMITE_ACTIVE ||
2731 last_element == EL_SP_DISK_RED_ACTIVE)
2732 DrawDynamite(last_jx, last_jy);
2734 /* !!! this is not enough to prevent flickering of players which are
2735 moving next to each others without a free tile between them -- this
2736 can only be solved by drawing all players layer by layer (first the
2737 background, then the foreground etc.) !!! => TODO */
2738 else if (!IS_PLAYER(last_jx, last_jy))
2739 DrawLevelField(last_jx, last_jy);
2742 DrawLevelField(last_jx, last_jy);
2745 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2746 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2749 if (!IN_SCR_FIELD(sx, sy))
2752 /* ----------------------------------------------------------------------- */
2753 /* draw things behind the player, if needed */
2754 /* ----------------------------------------------------------------------- */
2757 DrawLevelElement(jx, jy, Back[jx][jy]);
2758 else if (IS_ACTIVE_BOMB(element))
2759 DrawLevelElement(jx, jy, EL_EMPTY);
2762 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2764 int old_element = GfxElement[jx][jy];
2765 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2766 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2768 if (GFX_CRUMBLED(old_element))
2769 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
2771 DrawGraphic(sx, sy, old_graphic, frame);
2773 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2774 player_is_opaque = TRUE;
2778 GfxElement[jx][jy] = EL_UNDEFINED;
2780 /* make sure that pushed elements are drawn with correct frame rate */
2782 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2784 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2785 GfxFrame[jx][jy] = player->StepFrame;
2787 if (player->is_pushing && player->is_moving)
2788 GfxFrame[jx][jy] = player->StepFrame;
2791 DrawLevelField(jx, jy);
2795 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
2796 /* ----------------------------------------------------------------------- */
2797 /* draw player himself */
2798 /* ----------------------------------------------------------------------- */
2800 graphic = getPlayerGraphic(player, move_dir);
2802 /* in the case of changed player action or direction, prevent the current
2803 animation frame from being restarted for identical animations */
2804 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2805 player->Frame = last_player_frame;
2807 frame = getGraphicAnimationFrame(graphic, player->Frame);
2811 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2812 sxx = player->GfxPos;
2814 syy = player->GfxPos;
2817 if (!setup.soft_scrolling && ScreenMovPos)
2820 if (player_is_opaque)
2821 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2823 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2825 if (SHIELD_ON(player))
2827 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2828 IMG_SHIELD_NORMAL_ACTIVE);
2829 int frame = getGraphicAnimationFrame(graphic, -1);
2831 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2835 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2838 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2839 sxx = player->GfxPos;
2841 syy = player->GfxPos;
2845 /* ----------------------------------------------------------------------- */
2846 /* draw things the player is pushing, if needed */
2847 /* ----------------------------------------------------------------------- */
2850 printf("::: %d, %d [%d, %d] [%d]\n",
2851 player->is_pushing, player_is_moving, player->GfxAction,
2852 player->is_moving, player_is_moving);
2856 if (player->is_pushing && player->is_moving)
2858 int px = SCREENX(jx), py = SCREENY(jy);
2859 int pxx = (TILEX - ABS(sxx)) * dx;
2860 int pyy = (TILEY - ABS(syy)) * dy;
2861 int gfx_frame = GfxFrame[jx][jy];
2867 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2869 element = Feld[next_jx][next_jy];
2870 gfx_frame = GfxFrame[next_jx][next_jy];
2873 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2876 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2877 frame = getGraphicAnimationFrame(graphic, sync_frame);
2879 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2882 /* draw background element under pushed element (like the Sokoban field) */
2884 if (game.use_masked_pushing && IS_MOVING(jx, jy))
2886 /* this allows transparent pushing animation over non-black background */
2889 DrawLevelElement(jx, jy, Back[jx][jy]);
2891 DrawLevelElement(jx, jy, EL_EMPTY);
2893 if (Back[next_jx][next_jy])
2894 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2896 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2898 else if (Back[next_jx][next_jy])
2899 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2901 if (Back[next_jx][next_jy])
2902 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2906 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
2907 jx, px, player->GfxPos, player->StepFrame,
2912 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
2916 /* do not draw (EM style) pushing animation when pushing is finished */
2917 /* (two-tile animations usually do not contain start and end frame) */
2918 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
2919 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
2921 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2923 /* masked drawing is needed for EMC style (double) movement graphics */
2924 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
2925 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2930 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2931 /* ----------------------------------------------------------------------- */
2932 /* draw player himself */
2933 /* ----------------------------------------------------------------------- */
2935 graphic = getPlayerGraphic(player, move_dir);
2937 /* in the case of changed player action or direction, prevent the current
2938 animation frame from being restarted for identical animations */
2939 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2940 player->Frame = last_player_frame;
2942 frame = getGraphicAnimationFrame(graphic, player->Frame);
2946 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2947 sxx = player->GfxPos;
2949 syy = player->GfxPos;
2952 if (!setup.soft_scrolling && ScreenMovPos)
2955 if (player_is_opaque)
2956 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2958 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2960 if (SHIELD_ON(player))
2962 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2963 IMG_SHIELD_NORMAL_ACTIVE);
2964 int frame = getGraphicAnimationFrame(graphic, -1);
2966 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2970 /* ----------------------------------------------------------------------- */
2971 /* draw things in front of player (active dynamite or dynabombs) */
2972 /* ----------------------------------------------------------------------- */
2974 if (IS_ACTIVE_BOMB(element))
2976 graphic = el2img(element);
2977 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2979 if (game.emulation == EMU_SUPAPLEX)
2980 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2982 DrawGraphicThruMask(sx, sy, graphic, frame);
2985 if (player_is_moving && last_element == EL_EXPLOSION)
2987 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2988 GfxElement[last_jx][last_jy] : EL_EMPTY);
2989 int graphic = el_act2img(element, ACTION_EXPLODING);
2990 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2991 int phase = ExplodePhase[last_jx][last_jy] - 1;
2992 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2995 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2998 /* ----------------------------------------------------------------------- */
2999 /* draw elements the player is just walking/passing through/under */
3000 /* ----------------------------------------------------------------------- */
3002 if (player_is_moving)
3004 /* handle the field the player is leaving ... */
3005 if (IS_ACCESSIBLE_INSIDE(last_element))
3006 DrawLevelField(last_jx, last_jy);
3007 else if (IS_ACCESSIBLE_UNDER(last_element))
3008 DrawLevelFieldThruMask(last_jx, last_jy);
3011 /* do not redraw accessible elements if the player is just pushing them */
3012 if (!player_is_moving || !player->is_pushing)
3014 /* ... and the field the player is entering */
3015 if (IS_ACCESSIBLE_INSIDE(element))
3016 DrawLevelField(jx, jy);
3017 else if (IS_ACCESSIBLE_UNDER(element))
3018 DrawLevelFieldThruMask(jx, jy);
3021 MarkTileDirty(sx, sy);
3024 /* ------------------------------------------------------------------------- */
3026 void WaitForEventToContinue()
3028 boolean still_wait = TRUE;
3030 /* simulate releasing mouse button over last gadget, if still pressed */
3032 HandleGadgets(-1, -1, 0);
3034 button_status = MB_RELEASED;
3050 case EVENT_BUTTONPRESS:
3051 case EVENT_KEYPRESS:
3055 case EVENT_KEYRELEASE:
3056 ClearPlayerAction();
3060 HandleOtherEvents(&event);
3064 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3071 /* don't eat all CPU time */
3076 #define MAX_REQUEST_LINES 13
3077 #define MAX_REQUEST_LINE_FONT1_LEN 7
3078 #define MAX_REQUEST_LINE_FONT2_LEN 10
3080 boolean Request(char *text, unsigned int req_state)
3082 int mx, my, ty, result = -1;
3083 unsigned int old_door_state;
3084 int last_game_status = game_status; /* save current game status */
3085 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3086 int font_nr = FONT_TEXT_2;
3087 int max_word_len = 0;
3090 for (text_ptr = text; *text_ptr; text_ptr++)
3092 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3094 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3096 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3098 font_nr = FONT_TEXT_1;
3100 font_nr = FONT_LEVEL_NUMBER;
3107 if (game_status == GAME_MODE_PLAYING)
3109 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3110 BlitScreenToBitmap_EM(backbuffer);
3111 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3112 BlitScreenToBitmap_SP(backbuffer);
3115 /* disable deactivated drawing when quick-loading level tape recording */
3116 if (tape.playing && tape.deactivate_display)
3117 TapeDeactivateDisplayOff(TRUE);
3119 SetMouseCursor(CURSOR_DEFAULT);
3121 #if defined(NETWORK_AVALIABLE)
3122 /* pause network game while waiting for request to answer */
3123 if (options.network &&
3124 game_status == GAME_MODE_PLAYING &&
3125 req_state & REQUEST_WAIT_FOR_INPUT)
3126 SendToServer_PausePlaying();
3129 old_door_state = GetDoorState();
3131 /* simulate releasing mouse button over last gadget, if still pressed */
3133 HandleGadgets(-1, -1, 0);
3137 if (old_door_state & DOOR_OPEN_1)
3139 CloseDoor(DOOR_CLOSE_1);
3141 /* save old door content */
3142 BlitBitmap(bitmap_db_door, bitmap_db_door,
3143 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3144 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3148 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3151 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3153 /* clear door drawing field */
3154 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3156 /* force DOOR font inside door area */
3157 game_status = GAME_MODE_PSEUDO_DOOR;
3159 /* write text for request */
3160 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
3162 char text_line[max_request_line_len + 1];
3168 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3171 if (!tc || tc == ' ')
3182 strncpy(text_line, text, tl);
3185 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3186 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3187 text_line, font_nr);
3189 text += tl + (tc == ' ' ? 1 : 0);
3192 game_status = last_game_status; /* restore current game status */
3194 if (req_state & REQ_ASK)
3196 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3197 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3199 else if (req_state & REQ_CONFIRM)
3201 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3203 else if (req_state & REQ_PLAYER)
3205 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3206 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3207 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3208 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3211 /* copy request gadgets to door backbuffer */
3212 BlitBitmap(drawto, bitmap_db_door,
3213 DX, DY, DXSIZE, DYSIZE,
3214 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3216 OpenDoor(DOOR_OPEN_1);
3218 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3220 if (game_status == GAME_MODE_PLAYING)
3222 SetPanelBackground();
3223 SetDrawBackgroundMask(REDRAW_DOOR_1);
3227 SetDrawBackgroundMask(REDRAW_FIELD);
3233 if (game_status != GAME_MODE_MAIN)
3236 button_status = MB_RELEASED;
3238 request_gadget_id = -1;
3240 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3252 case EVENT_BUTTONPRESS:
3253 case EVENT_BUTTONRELEASE:
3254 case EVENT_MOTIONNOTIFY:
3256 if (event.type == EVENT_MOTIONNOTIFY)
3258 if (!PointerInWindow(window))
3259 continue; /* window and pointer are on different screens */
3264 motion_status = TRUE;
3265 mx = ((MotionEvent *) &event)->x;
3266 my = ((MotionEvent *) &event)->y;
3270 motion_status = FALSE;
3271 mx = ((ButtonEvent *) &event)->x;
3272 my = ((ButtonEvent *) &event)->y;
3273 if (event.type == EVENT_BUTTONPRESS)
3274 button_status = ((ButtonEvent *) &event)->button;
3276 button_status = MB_RELEASED;
3279 /* this sets 'request_gadget_id' */
3280 HandleGadgets(mx, my, button_status);
3282 switch (request_gadget_id)
3284 case TOOL_CTRL_ID_YES:
3287 case TOOL_CTRL_ID_NO:
3290 case TOOL_CTRL_ID_CONFIRM:
3291 result = TRUE | FALSE;
3294 case TOOL_CTRL_ID_PLAYER_1:
3297 case TOOL_CTRL_ID_PLAYER_2:
3300 case TOOL_CTRL_ID_PLAYER_3:
3303 case TOOL_CTRL_ID_PLAYER_4:
3314 case EVENT_KEYPRESS:
3315 switch (GetEventKey((KeyEvent *)&event, TRUE))
3318 if (req_state & REQ_CONFIRM)
3334 if (req_state & REQ_PLAYER)
3338 case EVENT_KEYRELEASE:
3339 ClearPlayerAction();
3343 HandleOtherEvents(&event);
3347 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3349 int joy = AnyJoystick();
3351 if (joy & JOY_BUTTON_1)
3353 else if (joy & JOY_BUTTON_2)
3359 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3361 HandleGameActions();
3367 if (!PendingEvent()) /* delay only if no pending events */
3378 if (!PendingEvent()) /* delay only if no pending events */
3381 /* don't eat all CPU time */
3388 if (game_status != GAME_MODE_MAIN)
3393 if (!(req_state & REQ_STAY_OPEN))
3395 CloseDoor(DOOR_CLOSE_1);
3397 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3398 (req_state & REQ_REOPEN))
3399 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3404 if (game_status == GAME_MODE_PLAYING)
3406 SetPanelBackground();
3407 SetDrawBackgroundMask(REDRAW_DOOR_1);
3411 SetDrawBackgroundMask(REDRAW_FIELD);
3414 #if defined(NETWORK_AVALIABLE)
3415 /* continue network game after request */
3416 if (options.network &&
3417 game_status == GAME_MODE_PLAYING &&
3418 req_state & REQUEST_WAIT_FOR_INPUT)
3419 SendToServer_ContinuePlaying();
3422 /* restore deactivated drawing when quick-loading level tape recording */
3423 if (tape.playing && tape.deactivate_display)
3424 TapeDeactivateDisplayOn();
3429 unsigned int OpenDoor(unsigned int door_state)
3431 if (door_state & DOOR_COPY_BACK)
3433 if (door_state & DOOR_OPEN_1)
3434 BlitBitmap(bitmap_db_door, bitmap_db_door,
3435 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3436 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3438 if (door_state & DOOR_OPEN_2)
3439 BlitBitmap(bitmap_db_door, bitmap_db_door,
3440 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3441 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3443 door_state &= ~DOOR_COPY_BACK;
3446 return MoveDoor(door_state);
3449 unsigned int CloseDoor(unsigned int door_state)
3451 unsigned int old_door_state = GetDoorState();
3453 if (!(door_state & DOOR_NO_COPY_BACK))
3455 if (old_door_state & DOOR_OPEN_1)
3456 BlitBitmap(backbuffer, bitmap_db_door,
3457 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3459 if (old_door_state & DOOR_OPEN_2)
3460 BlitBitmap(backbuffer, bitmap_db_door,
3461 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3463 door_state &= ~DOOR_NO_COPY_BACK;
3466 return MoveDoor(door_state);
3469 unsigned int GetDoorState()
3471 return MoveDoor(DOOR_GET_STATE);
3474 unsigned int SetDoorState(unsigned int door_state)
3476 return MoveDoor(door_state | DOOR_SET_STATE);
3479 unsigned int MoveDoor(unsigned int door_state)
3481 static int door1 = DOOR_OPEN_1;
3482 static int door2 = DOOR_CLOSE_2;
3483 unsigned long door_delay = 0;
3484 unsigned long door_delay_value;
3487 if (door_1.width < 0 || door_1.width > DXSIZE)
3488 door_1.width = DXSIZE;
3489 if (door_1.height < 0 || door_1.height > DYSIZE)
3490 door_1.height = DYSIZE;
3491 if (door_2.width < 0 || door_2.width > VXSIZE)
3492 door_2.width = VXSIZE;
3493 if (door_2.height < 0 || door_2.height > VYSIZE)
3494 door_2.height = VYSIZE;
3496 if (door_state == DOOR_GET_STATE)
3497 return (door1 | door2);
3499 if (door_state & DOOR_SET_STATE)
3501 if (door_state & DOOR_ACTION_1)
3502 door1 = door_state & DOOR_ACTION_1;
3503 if (door_state & DOOR_ACTION_2)
3504 door2 = door_state & DOOR_ACTION_2;
3506 return (door1 | door2);
3509 if (!(door_state & DOOR_FORCE_REDRAW))
3511 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3512 door_state &= ~DOOR_OPEN_1;
3513 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3514 door_state &= ~DOOR_CLOSE_1;
3515 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3516 door_state &= ~DOOR_OPEN_2;
3517 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3518 door_state &= ~DOOR_CLOSE_2;
3521 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3524 if (setup.quick_doors)
3526 stepsize = 20; /* must be chosen to always draw last frame */
3527 door_delay_value = 0;
3530 if (global.autoplay_leveldir)
3532 door_state |= DOOR_NO_DELAY;
3533 door_state &= ~DOOR_CLOSE_ALL;
3537 if (game_status == GAME_MODE_EDITOR)
3538 door_state |= DOOR_NO_DELAY;
3541 if (door_state & DOOR_ACTION)
3543 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3544 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3545 boolean door_1_done = (!handle_door_1);
3546 boolean door_2_done = (!handle_door_2);
3547 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3548 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3549 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3550 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3551 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3552 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3553 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3554 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3555 int door_skip = max_door_size - door_size;
3556 int end = door_size;
3557 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3560 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3562 /* opening door sound has priority over simultaneously closing door */
3563 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3564 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3565 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3566 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3569 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3572 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3573 GC gc = bitmap->stored_clip_gc;
3575 if (door_state & DOOR_ACTION_1)
3577 int a = MIN(x * door_1.step_offset, end);
3578 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3579 int i = p + door_skip;
3581 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3583 BlitBitmap(bitmap_db_door, drawto,
3584 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3585 DXSIZE, DYSIZE, DX, DY);
3589 BlitBitmap(bitmap_db_door, drawto,
3590 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3591 DXSIZE, DYSIZE - p / 2, DX, DY);
3593 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3596 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3598 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3599 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3600 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3601 int dst2_x = DX, dst2_y = DY;
3602 int width = i, height = DYSIZE;
3604 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3605 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3608 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3609 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3612 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3614 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3615 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3616 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3617 int dst2_x = DX, dst2_y = DY;
3618 int width = DXSIZE, height = i;
3620 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3621 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3624 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3625 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3628 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3630 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3632 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3633 BlitBitmapMasked(bitmap, drawto,
3634 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3635 DX + DXSIZE - i, DY + j);
3636 BlitBitmapMasked(bitmap, drawto,
3637 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3638 DX + DXSIZE - i, DY + 140 + j);
3639 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3640 DY - (DOOR_GFX_PAGEY1 + j));
3641 BlitBitmapMasked(bitmap, drawto,
3642 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3644 BlitBitmapMasked(bitmap, drawto,
3645 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3648 BlitBitmapMasked(bitmap, drawto,
3649 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3651 BlitBitmapMasked(bitmap, drawto,
3652 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3654 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3655 BlitBitmapMasked(bitmap, drawto,
3656 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3657 DX + DXSIZE - i, DY + 77 + j);
3658 BlitBitmapMasked(bitmap, drawto,
3659 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3660 DX + DXSIZE - i, DY + 203 + j);
3663 redraw_mask |= REDRAW_DOOR_1;
3664 door_1_done = (a == end);
3667 if (door_state & DOOR_ACTION_2)
3669 int a = MIN(x * door_2.step_offset, door_size);
3670 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3671 int i = p + door_skip;
3673 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3675 BlitBitmap(bitmap_db_door, drawto,
3676 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3677 VXSIZE, VYSIZE, VX, VY);
3679 else if (x <= VYSIZE)
3681 BlitBitmap(bitmap_db_door, drawto,
3682 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3683 VXSIZE, VYSIZE - p / 2, VX, VY);
3685 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3688 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3690 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3691 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3692 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3693 int dst2_x = VX, dst2_y = VY;
3694 int width = i, height = VYSIZE;
3696 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3697 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3700 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3701 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3704 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3706 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3707 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3708 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3709 int dst2_x = VX, dst2_y = VY;
3710 int width = VXSIZE, height = i;
3712 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3713 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3716 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3717 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3720 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3722 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3724 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3725 BlitBitmapMasked(bitmap, drawto,
3726 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3727 VX + VXSIZE - i, VY + j);
3728 SetClipOrigin(bitmap, gc,
3729 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3730 BlitBitmapMasked(bitmap, drawto,
3731 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3734 BlitBitmapMasked(bitmap, drawto,
3735 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3736 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3737 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3738 BlitBitmapMasked(bitmap, drawto,
3739 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3741 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3744 redraw_mask |= REDRAW_DOOR_2;
3745 door_2_done = (a == VXSIZE);
3748 if (!(door_state & DOOR_NO_DELAY))
3752 if (game_status == GAME_MODE_MAIN)
3755 WaitUntilDelayReached(&door_delay, door_delay_value);
3760 if (door_state & DOOR_ACTION_1)
3761 door1 = door_state & DOOR_ACTION_1;
3762 if (door_state & DOOR_ACTION_2)
3763 door2 = door_state & DOOR_ACTION_2;
3765 return (door1 | door2);
3768 void DrawSpecialEditorDoor()
3770 /* draw bigger toolbox window */
3771 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3772 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3774 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3775 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3778 redraw_mask |= REDRAW_ALL;
3781 void UndrawSpecialEditorDoor()
3783 /* draw normal tape recorder window */
3784 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3785 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3788 redraw_mask |= REDRAW_ALL;
3792 /* ---------- new tool button stuff ---------------------------------------- */
3794 /* graphic position values for tool buttons */
3795 #define TOOL_BUTTON_YES_XPOS 2
3796 #define TOOL_BUTTON_YES_YPOS 250
3797 #define TOOL_BUTTON_YES_GFX_YPOS 0
3798 #define TOOL_BUTTON_YES_XSIZE 46
3799 #define TOOL_BUTTON_YES_YSIZE 28
3800 #define TOOL_BUTTON_NO_XPOS 52
3801 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3802 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3803 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3804 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3805 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3806 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3807 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3808 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3809 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3810 #define TOOL_BUTTON_PLAYER_XSIZE 30
3811 #define TOOL_BUTTON_PLAYER_YSIZE 30
3812 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3813 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3814 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3815 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3816 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3817 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3818 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3819 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3820 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3821 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3822 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3823 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3824 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3825 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3826 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3827 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3828 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3829 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3830 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3831 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3840 } toolbutton_info[NUM_TOOL_BUTTONS] =
3843 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3844 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3845 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3850 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3851 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3852 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3857 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3858 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3859 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3860 TOOL_CTRL_ID_CONFIRM,
3864 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3865 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3866 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3867 TOOL_CTRL_ID_PLAYER_1,
3871 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3872 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3873 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3874 TOOL_CTRL_ID_PLAYER_2,
3878 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3879 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3880 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3881 TOOL_CTRL_ID_PLAYER_3,
3885 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3886 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3887 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3888 TOOL_CTRL_ID_PLAYER_4,
3893 void CreateToolButtons()
3897 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3899 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3900 Bitmap *deco_bitmap = None;
3901 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3902 struct GadgetInfo *gi;
3903 unsigned long event_mask;
3904 int gd_xoffset, gd_yoffset;
3905 int gd_x1, gd_x2, gd_y;
3908 event_mask = GD_EVENT_RELEASED;
3910 gd_xoffset = toolbutton_info[i].xpos;
3911 gd_yoffset = toolbutton_info[i].ypos;
3912 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3913 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3914 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3916 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3918 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3920 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3921 &deco_bitmap, &deco_x, &deco_y);
3922 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3923 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3926 gi = CreateGadget(GDI_CUSTOM_ID, id,
3927 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3928 GDI_X, DX + toolbutton_info[i].x,
3929 GDI_Y, DY + toolbutton_info[i].y,
3930 GDI_WIDTH, toolbutton_info[i].width,
3931 GDI_HEIGHT, toolbutton_info[i].height,
3932 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3933 GDI_STATE, GD_BUTTON_UNPRESSED,
3934 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3935 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3936 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3937 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3938 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3939 GDI_DECORATION_SHIFTING, 1, 1,
3940 GDI_DIRECT_DRAW, FALSE,
3941 GDI_EVENT_MASK, event_mask,
3942 GDI_CALLBACK_ACTION, HandleToolButtons,
3946 Error(ERR_EXIT, "cannot create gadget");
3948 tool_gadget[id] = gi;
3952 void FreeToolButtons()
3956 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3957 FreeGadget(tool_gadget[i]);
3960 static void UnmapToolButtons()
3964 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3965 UnmapGadget(tool_gadget[i]);
3968 static void HandleToolButtons(struct GadgetInfo *gi)
3970 request_gadget_id = gi->custom_id;
3973 static struct Mapping_EM_to_RND_object
3976 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3977 boolean is_backside; /* backside of moving element */
3983 em_object_mapping_list[] =
3986 Xblank, TRUE, FALSE,
3990 Yacid_splash_eB, FALSE, FALSE,
3991 EL_ACID_SPLASH_RIGHT, -1, -1
3994 Yacid_splash_wB, FALSE, FALSE,
3995 EL_ACID_SPLASH_LEFT, -1, -1
3998 #ifdef EM_ENGINE_BAD_ROLL
4000 Xstone_force_e, FALSE, FALSE,
4001 EL_ROCK, -1, MV_BIT_RIGHT
4004 Xstone_force_w, FALSE, FALSE,
4005 EL_ROCK, -1, MV_BIT_LEFT
4008 Xnut_force_e, FALSE, FALSE,
4009 EL_NUT, -1, MV_BIT_RIGHT
4012 Xnut_force_w, FALSE, FALSE,
4013 EL_NUT, -1, MV_BIT_LEFT
4016 Xspring_force_e, FALSE, FALSE,
4017 EL_SPRING, -1, MV_BIT_RIGHT
4020 Xspring_force_w, FALSE, FALSE,
4021 EL_SPRING, -1, MV_BIT_LEFT
4024 Xemerald_force_e, FALSE, FALSE,
4025 EL_EMERALD, -1, MV_BIT_RIGHT
4028 Xemerald_force_w, FALSE, FALSE,
4029 EL_EMERALD, -1, MV_BIT_LEFT
4032 Xdiamond_force_e, FALSE, FALSE,
4033 EL_DIAMOND, -1, MV_BIT_RIGHT
4036 Xdiamond_force_w, FALSE, FALSE,
4037 EL_DIAMOND, -1, MV_BIT_LEFT
4040 Xbomb_force_e, FALSE, FALSE,
4041 EL_BOMB, -1, MV_BIT_RIGHT
4044 Xbomb_force_w, FALSE, FALSE,
4045 EL_BOMB, -1, MV_BIT_LEFT
4047 #endif /* EM_ENGINE_BAD_ROLL */
4050 Xstone, TRUE, FALSE,
4054 Xstone_pause, FALSE, FALSE,
4058 Xstone_fall, FALSE, FALSE,
4062 Ystone_s, FALSE, FALSE,
4063 EL_ROCK, ACTION_FALLING, -1
4066 Ystone_sB, FALSE, TRUE,
4067 EL_ROCK, ACTION_FALLING, -1
4070 Ystone_e, FALSE, FALSE,
4071 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4074 Ystone_eB, FALSE, TRUE,
4075 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4078 Ystone_w, FALSE, FALSE,
4079 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4082 Ystone_wB, FALSE, TRUE,
4083 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4090 Xnut_pause, FALSE, FALSE,
4094 Xnut_fall, FALSE, FALSE,
4098 Ynut_s, FALSE, FALSE,
4099 EL_NUT, ACTION_FALLING, -1
4102 Ynut_sB, FALSE, TRUE,
4103 EL_NUT, ACTION_FALLING, -1
4106 Ynut_e, FALSE, FALSE,
4107 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4110 Ynut_eB, FALSE, TRUE,
4111 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4114 Ynut_w, FALSE, FALSE,
4115 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4118 Ynut_wB, FALSE, TRUE,
4119 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4122 Xbug_n, TRUE, FALSE,
4126 Xbug_e, TRUE, FALSE,
4127 EL_BUG_RIGHT, -1, -1
4130 Xbug_s, TRUE, FALSE,
4134 Xbug_w, TRUE, FALSE,
4138 Xbug_gon, FALSE, FALSE,
4142 Xbug_goe, FALSE, FALSE,
4143 EL_BUG_RIGHT, -1, -1
4146 Xbug_gos, FALSE, FALSE,
4150 Xbug_gow, FALSE, FALSE,
4154 Ybug_n, FALSE, FALSE,
4155 EL_BUG, ACTION_MOVING, MV_BIT_UP
4158 Ybug_nB, FALSE, TRUE,
4159 EL_BUG, ACTION_MOVING, MV_BIT_UP
4162 Ybug_e, FALSE, FALSE,
4163 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4166 Ybug_eB, FALSE, TRUE,
4167 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4170 Ybug_s, FALSE, FALSE,
4171 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4174 Ybug_sB, FALSE, TRUE,
4175 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4178 Ybug_w, FALSE, FALSE,
4179 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4182 Ybug_wB, FALSE, TRUE,
4183 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4186 Ybug_w_n, FALSE, FALSE,
4187 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4190 Ybug_n_e, FALSE, FALSE,
4191 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4194 Ybug_e_s, FALSE, FALSE,
4195 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4198 Ybug_s_w, FALSE, FALSE,
4199 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4202 Ybug_e_n, FALSE, FALSE,
4203 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4206 Ybug_s_e, FALSE, FALSE,
4207 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4210 Ybug_w_s, FALSE, FALSE,
4211 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4214 Ybug_n_w, FALSE, FALSE,
4215 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4218 Ybug_stone, FALSE, FALSE,
4219 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4222 Ybug_spring, FALSE, FALSE,
4223 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4226 Xtank_n, TRUE, FALSE,
4227 EL_SPACESHIP_UP, -1, -1
4230 Xtank_e, TRUE, FALSE,
4231 EL_SPACESHIP_RIGHT, -1, -1
4234 Xtank_s, TRUE, FALSE,
4235 EL_SPACESHIP_DOWN, -1, -1
4238 Xtank_w, TRUE, FALSE,
4239 EL_SPACESHIP_LEFT, -1, -1
4242 Xtank_gon, FALSE, FALSE,
4243 EL_SPACESHIP_UP, -1, -1
4246 Xtank_goe, FALSE, FALSE,
4247 EL_SPACESHIP_RIGHT, -1, -1
4250 Xtank_gos, FALSE, FALSE,
4251 EL_SPACESHIP_DOWN, -1, -1
4254 Xtank_gow, FALSE, FALSE,
4255 EL_SPACESHIP_LEFT, -1, -1
4258 Ytank_n, FALSE, FALSE,
4259 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4262 Ytank_nB, FALSE, TRUE,
4263 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4266 Ytank_e, FALSE, FALSE,
4267 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4270 Ytank_eB, FALSE, TRUE,
4271 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4274 Ytank_s, FALSE, FALSE,
4275 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4278 Ytank_sB, FALSE, TRUE,
4279 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4282 Ytank_w, FALSE, FALSE,
4283 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4286 Ytank_wB, FALSE, TRUE,
4287 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4290 Ytank_w_n, FALSE, FALSE,
4291 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4294 Ytank_n_e, FALSE, FALSE,
4295 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4298 Ytank_e_s, FALSE, FALSE,
4299 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4302 Ytank_s_w, FALSE, FALSE,
4303 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4306 Ytank_e_n, FALSE, FALSE,
4307 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4310 Ytank_s_e, FALSE, FALSE,
4311 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4314 Ytank_w_s, FALSE, FALSE,
4315 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4318 Ytank_n_w, FALSE, FALSE,
4319 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4322 Ytank_stone, FALSE, FALSE,
4323 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4326 Ytank_spring, FALSE, FALSE,
4327 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4330 Xandroid, TRUE, FALSE,
4331 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4334 Xandroid_1_n, FALSE, FALSE,
4335 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4338 Xandroid_2_n, FALSE, FALSE,
4339 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4342 Xandroid_1_e, FALSE, FALSE,
4343 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4346 Xandroid_2_e, FALSE, FALSE,
4347 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4350 Xandroid_1_w, FALSE, FALSE,
4351 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4354 Xandroid_2_w, FALSE, FALSE,
4355 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4358 Xandroid_1_s, FALSE, FALSE,
4359 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4362 Xandroid_2_s, FALSE, FALSE,
4363 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4366 Yandroid_n, FALSE, FALSE,
4367 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4370 Yandroid_nB, FALSE, TRUE,
4371 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4374 Yandroid_ne, FALSE, FALSE,
4375 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4378 Yandroid_neB, FALSE, TRUE,
4379 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4382 Yandroid_e, FALSE, FALSE,
4383 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4386 Yandroid_eB, FALSE, TRUE,
4387 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4390 Yandroid_se, FALSE, FALSE,
4391 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4394 Yandroid_seB, FALSE, TRUE,
4395 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4398 Yandroid_s, FALSE, FALSE,
4399 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4402 Yandroid_sB, FALSE, TRUE,
4403 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4406 Yandroid_sw, FALSE, FALSE,
4407 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4410 Yandroid_swB, FALSE, TRUE,
4411 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4414 Yandroid_w, FALSE, FALSE,
4415 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4418 Yandroid_wB, FALSE, TRUE,
4419 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4422 Yandroid_nw, FALSE, FALSE,
4423 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4426 Yandroid_nwB, FALSE, TRUE,
4427 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4430 Xspring, TRUE, FALSE,
4434 Xspring_pause, FALSE, FALSE,
4438 Xspring_e, FALSE, FALSE,
4442 Xspring_w, FALSE, FALSE,
4446 Xspring_fall, FALSE, FALSE,
4450 Yspring_s, FALSE, FALSE,
4451 EL_SPRING, ACTION_FALLING, -1
4454 Yspring_sB, FALSE, TRUE,
4455 EL_SPRING, ACTION_FALLING, -1
4458 Yspring_e, FALSE, FALSE,
4459 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4462 Yspring_eB, FALSE, TRUE,
4463 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4466 Yspring_w, FALSE, FALSE,
4467 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4470 Yspring_wB, FALSE, TRUE,
4471 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4474 Yspring_kill_e, FALSE, FALSE,
4475 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4478 Yspring_kill_eB, FALSE, TRUE,
4479 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4482 Yspring_kill_w, FALSE, FALSE,
4483 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4486 Yspring_kill_wB, FALSE, TRUE,
4487 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4490 Xeater_n, TRUE, FALSE,
4491 EL_YAMYAM_UP, -1, -1
4494 Xeater_e, TRUE, FALSE,
4495 EL_YAMYAM_RIGHT, -1, -1
4498 Xeater_w, TRUE, FALSE,
4499 EL_YAMYAM_LEFT, -1, -1
4502 Xeater_s, TRUE, FALSE,
4503 EL_YAMYAM_DOWN, -1, -1
4506 Yeater_n, FALSE, FALSE,
4507 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4510 Yeater_nB, FALSE, TRUE,
4511 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4514 Yeater_e, FALSE, FALSE,
4515 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4518 Yeater_eB, FALSE, TRUE,
4519 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4522 Yeater_s, FALSE, FALSE,
4523 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4526 Yeater_sB, FALSE, TRUE,
4527 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4530 Yeater_w, FALSE, FALSE,
4531 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4534 Yeater_wB, FALSE, TRUE,
4535 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4538 Yeater_stone, FALSE, FALSE,
4539 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4542 Yeater_spring, FALSE, FALSE,
4543 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4546 Xalien, TRUE, FALSE,
4550 Xalien_pause, FALSE, FALSE,
4554 Yalien_n, FALSE, FALSE,
4555 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4558 Yalien_nB, FALSE, TRUE,
4559 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4562 Yalien_e, FALSE, FALSE,
4563 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4566 Yalien_eB, FALSE, TRUE,
4567 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4570 Yalien_s, FALSE, FALSE,
4571 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4574 Yalien_sB, FALSE, TRUE,
4575 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4578 Yalien_w, FALSE, FALSE,
4579 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4582 Yalien_wB, FALSE, TRUE,
4583 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4586 Yalien_stone, FALSE, FALSE,
4587 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4590 Yalien_spring, FALSE, FALSE,
4591 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4594 Xemerald, TRUE, FALSE,
4598 Xemerald_pause, FALSE, FALSE,
4602 Xemerald_fall, FALSE, FALSE,
4606 Xemerald_shine, FALSE, FALSE,
4607 EL_EMERALD, ACTION_TWINKLING, -1
4610 Yemerald_s, FALSE, FALSE,
4611 EL_EMERALD, ACTION_FALLING, -1
4614 Yemerald_sB, FALSE, TRUE,
4615 EL_EMERALD, ACTION_FALLING, -1
4618 Yemerald_e, FALSE, FALSE,
4619 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4622 Yemerald_eB, FALSE, TRUE,
4623 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4626 Yemerald_w, FALSE, FALSE,
4627 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4630 Yemerald_wB, FALSE, TRUE,
4631 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4634 Yemerald_eat, FALSE, FALSE,
4635 EL_EMERALD, ACTION_COLLECTING, -1
4638 Yemerald_stone, FALSE, FALSE,
4639 EL_NUT, ACTION_BREAKING, -1
4642 Xdiamond, TRUE, FALSE,
4646 Xdiamond_pause, FALSE, FALSE,
4650 Xdiamond_fall, FALSE, FALSE,
4654 Xdiamond_shine, FALSE, FALSE,
4655 EL_DIAMOND, ACTION_TWINKLING, -1
4658 Ydiamond_s, FALSE, FALSE,
4659 EL_DIAMOND, ACTION_FALLING, -1
4662 Ydiamond_sB, FALSE, TRUE,
4663 EL_DIAMOND, ACTION_FALLING, -1
4666 Ydiamond_e, FALSE, FALSE,
4667 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4670 Ydiamond_eB, FALSE, TRUE,
4671 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4674 Ydiamond_w, FALSE, FALSE,
4675 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4678 Ydiamond_wB, FALSE, TRUE,
4679 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4682 Ydiamond_eat, FALSE, FALSE,
4683 EL_DIAMOND, ACTION_COLLECTING, -1
4686 Ydiamond_stone, FALSE, FALSE,
4687 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4690 Xdrip_fall, TRUE, FALSE,
4691 EL_AMOEBA_DROP, -1, -1
4694 Xdrip_stretch, FALSE, FALSE,
4695 EL_AMOEBA_DROP, ACTION_FALLING, -1
4698 Xdrip_stretchB, FALSE, TRUE,
4699 EL_AMOEBA_DROP, ACTION_FALLING, -1
4702 Xdrip_eat, FALSE, FALSE,
4703 EL_AMOEBA_DROP, ACTION_GROWING, -1
4706 Ydrip_s1, FALSE, FALSE,
4707 EL_AMOEBA_DROP, ACTION_FALLING, -1
4710 Ydrip_s1B, FALSE, TRUE,
4711 EL_AMOEBA_DROP, ACTION_FALLING, -1
4714 Ydrip_s2, FALSE, FALSE,
4715 EL_AMOEBA_DROP, ACTION_FALLING, -1
4718 Ydrip_s2B, FALSE, TRUE,
4719 EL_AMOEBA_DROP, ACTION_FALLING, -1
4726 Xbomb_pause, FALSE, FALSE,
4730 Xbomb_fall, FALSE, FALSE,
4734 Ybomb_s, FALSE, FALSE,
4735 EL_BOMB, ACTION_FALLING, -1
4738 Ybomb_sB, FALSE, TRUE,
4739 EL_BOMB, ACTION_FALLING, -1
4742 Ybomb_e, FALSE, FALSE,
4743 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4746 Ybomb_eB, FALSE, TRUE,
4747 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4750 Ybomb_w, FALSE, FALSE,
4751 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4754 Ybomb_wB, FALSE, TRUE,
4755 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4758 Ybomb_eat, FALSE, FALSE,
4759 EL_BOMB, ACTION_ACTIVATING, -1
4762 Xballoon, TRUE, FALSE,
4766 Yballoon_n, FALSE, FALSE,
4767 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4770 Yballoon_nB, FALSE, TRUE,
4771 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4774 Yballoon_e, FALSE, FALSE,
4775 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4778 Yballoon_eB, FALSE, TRUE,
4779 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4782 Yballoon_s, FALSE, FALSE,
4783 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4786 Yballoon_sB, FALSE, TRUE,
4787 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4790 Yballoon_w, FALSE, FALSE,
4791 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4794 Yballoon_wB, FALSE, TRUE,
4795 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4798 Xgrass, TRUE, FALSE,
4799 EL_EMC_GRASS, -1, -1
4802 Ygrass_nB, FALSE, FALSE,
4803 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4806 Ygrass_eB, FALSE, FALSE,
4807 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4810 Ygrass_sB, FALSE, FALSE,
4811 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4814 Ygrass_wB, FALSE, FALSE,
4815 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4822 Ydirt_nB, FALSE, FALSE,
4823 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4826 Ydirt_eB, FALSE, FALSE,
4827 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4830 Ydirt_sB, FALSE, FALSE,
4831 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4834 Ydirt_wB, FALSE, FALSE,
4835 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4838 Xacid_ne, TRUE, FALSE,
4839 EL_ACID_POOL_TOPRIGHT, -1, -1
4842 Xacid_se, TRUE, FALSE,
4843 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4846 Xacid_s, TRUE, FALSE,
4847 EL_ACID_POOL_BOTTOM, -1, -1
4850 Xacid_sw, TRUE, FALSE,
4851 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4854 Xacid_nw, TRUE, FALSE,
4855 EL_ACID_POOL_TOPLEFT, -1, -1
4858 Xacid_1, TRUE, FALSE,
4862 Xacid_2, FALSE, FALSE,
4866 Xacid_3, FALSE, FALSE,
4870 Xacid_4, FALSE, FALSE,
4874 Xacid_5, FALSE, FALSE,
4878 Xacid_6, FALSE, FALSE,
4882 Xacid_7, FALSE, FALSE,
4886 Xacid_8, FALSE, FALSE,
4890 Xball_1, TRUE, FALSE,
4891 EL_EMC_MAGIC_BALL, -1, -1
4894 Xball_1B, FALSE, FALSE,
4895 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4898 Xball_2, FALSE, FALSE,
4899 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4902 Xball_2B, FALSE, FALSE,
4903 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4906 Yball_eat, FALSE, FALSE,
4907 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4910 Ykey_1_eat, FALSE, FALSE,
4911 EL_EM_KEY_1, ACTION_COLLECTING, -1
4914 Ykey_2_eat, FALSE, FALSE,
4915 EL_EM_KEY_2, ACTION_COLLECTING, -1
4918 Ykey_3_eat, FALSE, FALSE,
4919 EL_EM_KEY_3, ACTION_COLLECTING, -1
4922 Ykey_4_eat, FALSE, FALSE,
4923 EL_EM_KEY_4, ACTION_COLLECTING, -1
4926 Ykey_5_eat, FALSE, FALSE,
4927 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4930 Ykey_6_eat, FALSE, FALSE,
4931 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4934 Ykey_7_eat, FALSE, FALSE,
4935 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4938 Ykey_8_eat, FALSE, FALSE,
4939 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4942 Ylenses_eat, FALSE, FALSE,
4943 EL_EMC_LENSES, ACTION_COLLECTING, -1
4946 Ymagnify_eat, FALSE, FALSE,
4947 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4950 Ygrass_eat, FALSE, FALSE,
4951 EL_EMC_GRASS, ACTION_SNAPPING, -1
4954 Ydirt_eat, FALSE, FALSE,
4955 EL_SAND, ACTION_SNAPPING, -1
4958 Xgrow_ns, TRUE, FALSE,
4959 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4962 Ygrow_ns_eat, FALSE, FALSE,
4963 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4966 Xgrow_ew, TRUE, FALSE,
4967 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4970 Ygrow_ew_eat, FALSE, FALSE,
4971 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4974 Xwonderwall, TRUE, FALSE,
4975 EL_MAGIC_WALL, -1, -1
4978 XwonderwallB, FALSE, FALSE,
4979 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4982 Xamoeba_1, TRUE, FALSE,
4983 EL_AMOEBA_DRY, ACTION_OTHER, -1
4986 Xamoeba_2, FALSE, FALSE,
4987 EL_AMOEBA_DRY, ACTION_OTHER, -1
4990 Xamoeba_3, FALSE, FALSE,
4991 EL_AMOEBA_DRY, ACTION_OTHER, -1
4994 Xamoeba_4, FALSE, FALSE,
4995 EL_AMOEBA_DRY, ACTION_OTHER, -1
4998 Xamoeba_5, TRUE, FALSE,
4999 EL_AMOEBA_WET, ACTION_OTHER, -1
5002 Xamoeba_6, FALSE, FALSE,
5003 EL_AMOEBA_WET, ACTION_OTHER, -1
5006 Xamoeba_7, FALSE, FALSE,
5007 EL_AMOEBA_WET, ACTION_OTHER, -1
5010 Xamoeba_8, FALSE, FALSE,
5011 EL_AMOEBA_WET, ACTION_OTHER, -1
5014 Xdoor_1, TRUE, FALSE,
5015 EL_EM_GATE_1, -1, -1
5018 Xdoor_2, TRUE, FALSE,
5019 EL_EM_GATE_2, -1, -1
5022 Xdoor_3, TRUE, FALSE,
5023 EL_EM_GATE_3, -1, -1
5026 Xdoor_4, TRUE, FALSE,
5027 EL_EM_GATE_4, -1, -1
5030 Xdoor_5, TRUE, FALSE,
5031 EL_EMC_GATE_5, -1, -1
5034 Xdoor_6, TRUE, FALSE,
5035 EL_EMC_GATE_6, -1, -1
5038 Xdoor_7, TRUE, FALSE,
5039 EL_EMC_GATE_7, -1, -1
5042 Xdoor_8, TRUE, FALSE,
5043 EL_EMC_GATE_8, -1, -1
5046 Xkey_1, TRUE, FALSE,
5050 Xkey_2, TRUE, FALSE,
5054 Xkey_3, TRUE, FALSE,
5058 Xkey_4, TRUE, FALSE,
5062 Xkey_5, TRUE, FALSE,
5063 EL_EMC_KEY_5, -1, -1
5066 Xkey_6, TRUE, FALSE,
5067 EL_EMC_KEY_6, -1, -1
5070 Xkey_7, TRUE, FALSE,
5071 EL_EMC_KEY_7, -1, -1
5074 Xkey_8, TRUE, FALSE,
5075 EL_EMC_KEY_8, -1, -1
5078 Xwind_n, TRUE, FALSE,
5079 EL_BALLOON_SWITCH_UP, -1, -1
5082 Xwind_e, TRUE, FALSE,
5083 EL_BALLOON_SWITCH_RIGHT, -1, -1
5086 Xwind_s, TRUE, FALSE,
5087 EL_BALLOON_SWITCH_DOWN, -1, -1
5090 Xwind_w, TRUE, FALSE,
5091 EL_BALLOON_SWITCH_LEFT, -1, -1
5094 Xwind_nesw, TRUE, FALSE,
5095 EL_BALLOON_SWITCH_ANY, -1, -1
5098 Xwind_stop, TRUE, FALSE,
5099 EL_BALLOON_SWITCH_NONE, -1, -1
5103 EL_EM_EXIT_CLOSED, -1, -1
5106 Xexit_1, TRUE, FALSE,
5107 EL_EM_EXIT_OPEN, -1, -1
5110 Xexit_2, FALSE, FALSE,
5111 EL_EM_EXIT_OPEN, -1, -1
5114 Xexit_3, FALSE, FALSE,
5115 EL_EM_EXIT_OPEN, -1, -1
5118 Xdynamite, TRUE, FALSE,
5119 EL_EM_DYNAMITE, -1, -1
5122 Ydynamite_eat, FALSE, FALSE,
5123 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5126 Xdynamite_1, TRUE, FALSE,
5127 EL_EM_DYNAMITE_ACTIVE, -1, -1
5130 Xdynamite_2, FALSE, FALSE,
5131 EL_EM_DYNAMITE_ACTIVE, -1, -1
5134 Xdynamite_3, FALSE, FALSE,
5135 EL_EM_DYNAMITE_ACTIVE, -1, -1
5138 Xdynamite_4, FALSE, FALSE,
5139 EL_EM_DYNAMITE_ACTIVE, -1, -1
5142 Xbumper, TRUE, FALSE,
5143 EL_EMC_SPRING_BUMPER, -1, -1
5146 XbumperB, FALSE, FALSE,
5147 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5150 Xwheel, TRUE, FALSE,
5151 EL_ROBOT_WHEEL, -1, -1
5154 XwheelB, FALSE, FALSE,
5155 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5158 Xswitch, TRUE, FALSE,
5159 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5162 XswitchB, FALSE, FALSE,
5163 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5167 EL_QUICKSAND_EMPTY, -1, -1
5170 Xsand_stone, TRUE, FALSE,
5171 EL_QUICKSAND_FULL, -1, -1
5174 Xsand_stonein_1, FALSE, TRUE,
5175 EL_ROCK, ACTION_FILLING, -1
5178 Xsand_stonein_2, FALSE, TRUE,
5179 EL_ROCK, ACTION_FILLING, -1
5182 Xsand_stonein_3, FALSE, TRUE,
5183 EL_ROCK, ACTION_FILLING, -1
5186 Xsand_stonein_4, FALSE, TRUE,
5187 EL_ROCK, ACTION_FILLING, -1
5191 Xsand_stonesand_1, FALSE, FALSE,
5192 EL_QUICKSAND_EMPTYING, -1, -1
5195 Xsand_stonesand_2, FALSE, FALSE,
5196 EL_QUICKSAND_EMPTYING, -1, -1
5199 Xsand_stonesand_3, FALSE, FALSE,
5200 EL_QUICKSAND_EMPTYING, -1, -1
5203 Xsand_stonesand_4, FALSE, FALSE,
5204 EL_QUICKSAND_EMPTYING, -1, -1
5207 Xsand_stonesand_quickout_1, FALSE, FALSE,
5208 EL_QUICKSAND_EMPTYING, -1, -1
5211 Xsand_stonesand_quickout_2, FALSE, FALSE,
5212 EL_QUICKSAND_EMPTYING, -1, -1
5216 Xsand_stonesand_1, FALSE, FALSE,
5217 EL_QUICKSAND_FULL, -1, -1
5220 Xsand_stonesand_2, FALSE, FALSE,
5221 EL_QUICKSAND_FULL, -1, -1
5224 Xsand_stonesand_3, FALSE, FALSE,
5225 EL_QUICKSAND_FULL, -1, -1
5228 Xsand_stonesand_4, FALSE, FALSE,
5229 EL_QUICKSAND_FULL, -1, -1
5233 Xsand_stoneout_1, FALSE, FALSE,
5234 EL_ROCK, ACTION_EMPTYING, -1
5237 Xsand_stoneout_2, FALSE, FALSE,
5238 EL_ROCK, ACTION_EMPTYING, -1
5242 Xsand_sandstone_1, FALSE, FALSE,
5243 EL_QUICKSAND_FILLING, -1, -1
5246 Xsand_sandstone_2, FALSE, FALSE,
5247 EL_QUICKSAND_FILLING, -1, -1
5250 Xsand_sandstone_3, FALSE, FALSE,
5251 EL_QUICKSAND_FILLING, -1, -1
5254 Xsand_sandstone_4, FALSE, FALSE,
5255 EL_QUICKSAND_FILLING, -1, -1
5259 Xsand_sandstone_1, FALSE, FALSE,
5260 EL_QUICKSAND_FULL, -1, -1
5263 Xsand_sandstone_2, FALSE, FALSE,
5264 EL_QUICKSAND_FULL, -1, -1
5267 Xsand_sandstone_3, FALSE, FALSE,
5268 EL_QUICKSAND_FULL, -1, -1
5271 Xsand_sandstone_4, FALSE, FALSE,
5272 EL_QUICKSAND_FULL, -1, -1
5276 Xplant, TRUE, FALSE,
5277 EL_EMC_PLANT, -1, -1
5280 Yplant, FALSE, FALSE,
5281 EL_EMC_PLANT, -1, -1
5284 Xlenses, TRUE, FALSE,
5285 EL_EMC_LENSES, -1, -1
5288 Xmagnify, TRUE, FALSE,
5289 EL_EMC_MAGNIFIER, -1, -1
5292 Xdripper, TRUE, FALSE,
5293 EL_EMC_DRIPPER, -1, -1
5296 XdripperB, FALSE, FALSE,
5297 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5300 Xfake_blank, TRUE, FALSE,
5301 EL_INVISIBLE_WALL, -1, -1
5304 Xfake_blankB, FALSE, FALSE,
5305 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5308 Xfake_grass, TRUE, FALSE,
5309 EL_EMC_FAKE_GRASS, -1, -1
5312 Xfake_grassB, FALSE, FALSE,
5313 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5316 Xfake_door_1, TRUE, FALSE,
5317 EL_EM_GATE_1_GRAY, -1, -1
5320 Xfake_door_2, TRUE, FALSE,
5321 EL_EM_GATE_2_GRAY, -1, -1
5324 Xfake_door_3, TRUE, FALSE,
5325 EL_EM_GATE_3_GRAY, -1, -1
5328 Xfake_door_4, TRUE, FALSE,
5329 EL_EM_GATE_4_GRAY, -1, -1
5332 Xfake_door_5, TRUE, FALSE,
5333 EL_EMC_GATE_5_GRAY, -1, -1
5336 Xfake_door_6, TRUE, FALSE,
5337 EL_EMC_GATE_6_GRAY, -1, -1
5340 Xfake_door_7, TRUE, FALSE,
5341 EL_EMC_GATE_7_GRAY, -1, -1
5344 Xfake_door_8, TRUE, FALSE,
5345 EL_EMC_GATE_8_GRAY, -1, -1
5348 Xfake_acid_1, TRUE, FALSE,
5349 EL_EMC_FAKE_ACID, -1, -1
5352 Xfake_acid_2, FALSE, FALSE,
5353 EL_EMC_FAKE_ACID, -1, -1
5356 Xfake_acid_3, FALSE, FALSE,
5357 EL_EMC_FAKE_ACID, -1, -1
5360 Xfake_acid_4, FALSE, FALSE,
5361 EL_EMC_FAKE_ACID, -1, -1
5364 Xfake_acid_5, FALSE, FALSE,
5365 EL_EMC_FAKE_ACID, -1, -1
5368 Xfake_acid_6, FALSE, FALSE,
5369 EL_EMC_FAKE_ACID, -1, -1
5372 Xfake_acid_7, FALSE, FALSE,
5373 EL_EMC_FAKE_ACID, -1, -1
5376 Xfake_acid_8, FALSE, FALSE,
5377 EL_EMC_FAKE_ACID, -1, -1
5380 Xsteel_1, TRUE, FALSE,
5381 EL_STEELWALL, -1, -1
5384 Xsteel_2, TRUE, FALSE,
5385 EL_EMC_STEELWALL_2, -1, -1
5388 Xsteel_3, TRUE, FALSE,
5389 EL_EMC_STEELWALL_3, -1, -1
5392 Xsteel_4, TRUE, FALSE,
5393 EL_EMC_STEELWALL_4, -1, -1
5396 Xwall_1, TRUE, FALSE,
5400 Xwall_2, TRUE, FALSE,
5401 EL_EMC_WALL_14, -1, -1
5404 Xwall_3, TRUE, FALSE,
5405 EL_EMC_WALL_15, -1, -1
5408 Xwall_4, TRUE, FALSE,
5409 EL_EMC_WALL_16, -1, -1
5412 Xround_wall_1, TRUE, FALSE,
5413 EL_WALL_SLIPPERY, -1, -1
5416 Xround_wall_2, TRUE, FALSE,
5417 EL_EMC_WALL_SLIPPERY_2, -1, -1
5420 Xround_wall_3, TRUE, FALSE,
5421 EL_EMC_WALL_SLIPPERY_3, -1, -1
5424 Xround_wall_4, TRUE, FALSE,
5425 EL_EMC_WALL_SLIPPERY_4, -1, -1
5428 Xdecor_1, TRUE, FALSE,
5429 EL_EMC_WALL_8, -1, -1
5432 Xdecor_2, TRUE, FALSE,
5433 EL_EMC_WALL_6, -1, -1
5436 Xdecor_3, TRUE, FALSE,
5437 EL_EMC_WALL_4, -1, -1
5440 Xdecor_4, TRUE, FALSE,
5441 EL_EMC_WALL_7, -1, -1
5444 Xdecor_5, TRUE, FALSE,
5445 EL_EMC_WALL_5, -1, -1
5448 Xdecor_6, TRUE, FALSE,
5449 EL_EMC_WALL_9, -1, -1
5452 Xdecor_7, TRUE, FALSE,
5453 EL_EMC_WALL_10, -1, -1
5456 Xdecor_8, TRUE, FALSE,
5457 EL_EMC_WALL_1, -1, -1
5460 Xdecor_9, TRUE, FALSE,
5461 EL_EMC_WALL_2, -1, -1
5464 Xdecor_10, TRUE, FALSE,
5465 EL_EMC_WALL_3, -1, -1
5468 Xdecor_11, TRUE, FALSE,
5469 EL_EMC_WALL_11, -1, -1
5472 Xdecor_12, TRUE, FALSE,
5473 EL_EMC_WALL_12, -1, -1
5476 Xalpha_0, TRUE, FALSE,
5477 EL_CHAR('0'), -1, -1
5480 Xalpha_1, TRUE, FALSE,
5481 EL_CHAR('1'), -1, -1
5484 Xalpha_2, TRUE, FALSE,
5485 EL_CHAR('2'), -1, -1
5488 Xalpha_3, TRUE, FALSE,
5489 EL_CHAR('3'), -1, -1
5492 Xalpha_4, TRUE, FALSE,
5493 EL_CHAR('4'), -1, -1
5496 Xalpha_5, TRUE, FALSE,
5497 EL_CHAR('5'), -1, -1
5500 Xalpha_6, TRUE, FALSE,
5501 EL_CHAR('6'), -1, -1
5504 Xalpha_7, TRUE, FALSE,
5505 EL_CHAR('7'), -1, -1
5508 Xalpha_8, TRUE, FALSE,
5509 EL_CHAR('8'), -1, -1
5512 Xalpha_9, TRUE, FALSE,
5513 EL_CHAR('9'), -1, -1
5516 Xalpha_excla, TRUE, FALSE,
5517 EL_CHAR('!'), -1, -1
5520 Xalpha_quote, TRUE, FALSE,
5521 EL_CHAR('"'), -1, -1
5524 Xalpha_comma, TRUE, FALSE,
5525 EL_CHAR(','), -1, -1
5528 Xalpha_minus, TRUE, FALSE,
5529 EL_CHAR('-'), -1, -1
5532 Xalpha_perio, TRUE, FALSE,
5533 EL_CHAR('.'), -1, -1
5536 Xalpha_colon, TRUE, FALSE,
5537 EL_CHAR(':'), -1, -1
5540 Xalpha_quest, TRUE, FALSE,
5541 EL_CHAR('?'), -1, -1
5544 Xalpha_a, TRUE, FALSE,
5545 EL_CHAR('A'), -1, -1
5548 Xalpha_b, TRUE, FALSE,
5549 EL_CHAR('B'), -1, -1
5552 Xalpha_c, TRUE, FALSE,
5553 EL_CHAR('C'), -1, -1
5556 Xalpha_d, TRUE, FALSE,
5557 EL_CHAR('D'), -1, -1
5560 Xalpha_e, TRUE, FALSE,
5561 EL_CHAR('E'), -1, -1
5564 Xalpha_f, TRUE, FALSE,
5565 EL_CHAR('F'), -1, -1
5568 Xalpha_g, TRUE, FALSE,
5569 EL_CHAR('G'), -1, -1
5572 Xalpha_h, TRUE, FALSE,
5573 EL_CHAR('H'), -1, -1
5576 Xalpha_i, TRUE, FALSE,
5577 EL_CHAR('I'), -1, -1
5580 Xalpha_j, TRUE, FALSE,
5581 EL_CHAR('J'), -1, -1
5584 Xalpha_k, TRUE, FALSE,
5585 EL_CHAR('K'), -1, -1
5588 Xalpha_l, TRUE, FALSE,
5589 EL_CHAR('L'), -1, -1
5592 Xalpha_m, TRUE, FALSE,
5593 EL_CHAR('M'), -1, -1
5596 Xalpha_n, TRUE, FALSE,
5597 EL_CHAR('N'), -1, -1
5600 Xalpha_o, TRUE, FALSE,
5601 EL_CHAR('O'), -1, -1
5604 Xalpha_p, TRUE, FALSE,
5605 EL_CHAR('P'), -1, -1
5608 Xalpha_q, TRUE, FALSE,
5609 EL_CHAR('Q'), -1, -1
5612 Xalpha_r, TRUE, FALSE,
5613 EL_CHAR('R'), -1, -1
5616 Xalpha_s, TRUE, FALSE,
5617 EL_CHAR('S'), -1, -1
5620 Xalpha_t, TRUE, FALSE,
5621 EL_CHAR('T'), -1, -1
5624 Xalpha_u, TRUE, FALSE,
5625 EL_CHAR('U'), -1, -1
5628 Xalpha_v, TRUE, FALSE,
5629 EL_CHAR('V'), -1, -1
5632 Xalpha_w, TRUE, FALSE,
5633 EL_CHAR('W'), -1, -1
5636 Xalpha_x, TRUE, FALSE,
5637 EL_CHAR('X'), -1, -1
5640 Xalpha_y, TRUE, FALSE,
5641 EL_CHAR('Y'), -1, -1
5644 Xalpha_z, TRUE, FALSE,
5645 EL_CHAR('Z'), -1, -1
5648 Xalpha_arrow_e, TRUE, FALSE,
5649 EL_CHAR('>'), -1, -1
5652 Xalpha_arrow_w, TRUE, FALSE,
5653 EL_CHAR('<'), -1, -1
5656 Xalpha_copyr, TRUE, FALSE,
5657 EL_CHAR('©'), -1, -1
5661 Xboom_bug, FALSE, FALSE,
5662 EL_BUG, ACTION_EXPLODING, -1
5665 Xboom_bomb, FALSE, FALSE,
5666 EL_BOMB, ACTION_EXPLODING, -1
5669 Xboom_android, FALSE, FALSE,
5670 EL_EMC_ANDROID, ACTION_OTHER, -1
5673 Xboom_1, FALSE, FALSE,
5674 EL_DEFAULT, ACTION_EXPLODING, -1
5677 Xboom_2, FALSE, FALSE,
5678 EL_DEFAULT, ACTION_EXPLODING, -1
5681 Znormal, FALSE, FALSE,
5685 Zdynamite, FALSE, FALSE,
5689 Zplayer, FALSE, FALSE,
5693 ZBORDER, FALSE, FALSE,
5703 static struct Mapping_EM_to_RND_player
5712 em_player_mapping_list[] =
5716 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5720 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5724 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5728 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5732 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5736 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5740 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5744 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5748 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5752 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5756 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5760 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5764 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5768 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5772 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5776 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5780 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5784 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5788 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5792 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5796 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5800 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5804 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5808 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5812 EL_PLAYER_1, ACTION_DEFAULT, -1,
5816 EL_PLAYER_2, ACTION_DEFAULT, -1,
5820 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5824 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5828 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5832 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5836 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5840 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5844 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5848 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5852 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5856 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5860 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5864 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5868 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5872 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5876 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5880 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5884 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5888 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5892 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5896 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5900 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5904 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5908 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5912 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5916 EL_PLAYER_3, ACTION_DEFAULT, -1,
5920 EL_PLAYER_4, ACTION_DEFAULT, -1,
5929 int map_element_RND_to_EM(int element_rnd)
5931 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5932 static boolean mapping_initialized = FALSE;
5934 if (!mapping_initialized)
5938 /* return "Xalpha_quest" for all undefined elements in mapping array */
5939 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5940 mapping_RND_to_EM[i] = Xalpha_quest;
5942 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5943 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5944 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5945 em_object_mapping_list[i].element_em;
5947 mapping_initialized = TRUE;
5950 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5951 return mapping_RND_to_EM[element_rnd];
5953 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5958 int map_element_EM_to_RND(int element_em)
5960 static unsigned short mapping_EM_to_RND[TILE_MAX];
5961 static boolean mapping_initialized = FALSE;
5963 if (!mapping_initialized)
5967 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5968 for (i = 0; i < TILE_MAX; i++)
5969 mapping_EM_to_RND[i] = EL_UNKNOWN;
5971 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5972 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5973 em_object_mapping_list[i].element_rnd;
5975 mapping_initialized = TRUE;
5978 if (element_em >= 0 && element_em < TILE_MAX)
5979 return mapping_EM_to_RND[element_em];
5981 Error(ERR_WARN, "invalid EM level element %d", element_em);
5986 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5988 struct LevelInfo_EM *level_em = level->native_em_level;
5989 struct LEVEL *lev = level_em->lev;
5992 for (i = 0; i < TILE_MAX; i++)
5993 lev->android_array[i] = Xblank;
5995 for (i = 0; i < level->num_android_clone_elements; i++)
5997 int element_rnd = level->android_clone_element[i];
5998 int element_em = map_element_RND_to_EM(element_rnd);
6000 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6001 if (em_object_mapping_list[j].element_rnd == element_rnd)
6002 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6006 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6008 struct LevelInfo_EM *level_em = level->native_em_level;
6009 struct LEVEL *lev = level_em->lev;
6012 level->num_android_clone_elements = 0;
6014 for (i = 0; i < TILE_MAX; i++)
6016 int element_em = lev->android_array[i];
6018 boolean element_found = FALSE;
6020 if (element_em == Xblank)
6023 element_rnd = map_element_EM_to_RND(element_em);
6025 for (j = 0; j < level->num_android_clone_elements; j++)
6026 if (level->android_clone_element[j] == element_rnd)
6027 element_found = TRUE;
6031 level->android_clone_element[level->num_android_clone_elements++] =
6034 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6039 if (level->num_android_clone_elements == 0)
6041 level->num_android_clone_elements = 1;
6042 level->android_clone_element[0] = EL_EMPTY;
6046 int map_direction_RND_to_EM(int direction)
6048 return (direction == MV_UP ? 0 :
6049 direction == MV_RIGHT ? 1 :
6050 direction == MV_DOWN ? 2 :
6051 direction == MV_LEFT ? 3 :
6055 int map_direction_EM_to_RND(int direction)
6057 return (direction == 0 ? MV_UP :
6058 direction == 1 ? MV_RIGHT :
6059 direction == 2 ? MV_DOWN :
6060 direction == 3 ? MV_LEFT :
6064 int map_element_RND_to_SP(int element_rnd)
6066 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6068 if (element_rnd >= EL_SP_START &&
6069 element_rnd <= EL_SP_END)
6070 element_sp = element_rnd - EL_SP_START;
6071 else if (element_rnd == EL_EMPTY_SPACE)
6073 else if (element_rnd == EL_INVISIBLE_WALL)
6079 int map_element_SP_to_RND(int element_sp)
6081 int element_rnd = EL_UNKNOWN;
6083 if (element_sp >= 0x00 &&
6085 element_rnd = EL_SP_START + element_sp;
6086 else if (element_sp == 0x28)
6087 element_rnd = EL_INVISIBLE_WALL;
6092 int map_action_SP_to_RND(int action_sp)
6096 case actActive: return ACTION_ACTIVE;
6097 case actImpact: return ACTION_IMPACT;
6098 case actExploding: return ACTION_EXPLODING;
6099 case actDigging: return ACTION_DIGGING;
6100 case actSnapping: return ACTION_SNAPPING;
6101 case actCollecting: return ACTION_COLLECTING;
6102 case actPassing: return ACTION_PASSING;
6103 case actPushing: return ACTION_PUSHING;
6104 case actDropping: return ACTION_DROPPING;
6106 default: return ACTION_DEFAULT;
6110 int get_next_element(int element)
6114 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6115 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6116 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6117 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6118 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6119 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6120 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6121 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6122 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6123 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6124 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6126 default: return element;
6131 int el_act_dir2img(int element, int action, int direction)
6133 element = GFX_ELEMENT(element);
6135 if (direction == MV_NONE)
6136 return element_info[element].graphic[action];
6138 direction = MV_DIR_TO_BIT(direction);
6140 return element_info[element].direction_graphic[action][direction];
6143 int el_act_dir2img(int element, int action, int direction)
6145 element = GFX_ELEMENT(element);
6146 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6148 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6149 return element_info[element].direction_graphic[action][direction];
6154 static int el_act_dir2crm(int element, int action, int direction)
6156 element = GFX_ELEMENT(element);
6158 if (direction == MV_NONE)
6159 return element_info[element].crumbled[action];
6161 direction = MV_DIR_TO_BIT(direction);
6163 return element_info[element].direction_crumbled[action][direction];
6166 static int el_act_dir2crm(int element, int action, int direction)
6168 element = GFX_ELEMENT(element);
6169 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6171 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6172 return element_info[element].direction_crumbled[action][direction];
6176 int el_act2img(int element, int action)
6178 element = GFX_ELEMENT(element);
6180 return element_info[element].graphic[action];
6183 int el_act2crm(int element, int action)
6185 element = GFX_ELEMENT(element);
6187 return element_info[element].crumbled[action];
6190 int el_dir2img(int element, int direction)
6192 element = GFX_ELEMENT(element);
6194 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6197 int el2baseimg(int element)
6199 return element_info[element].graphic[ACTION_DEFAULT];
6202 int el2img(int element)
6204 element = GFX_ELEMENT(element);
6206 return element_info[element].graphic[ACTION_DEFAULT];
6209 int el2edimg(int element)
6211 element = GFX_ELEMENT(element);
6213 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6216 int el2preimg(int element)
6218 element = GFX_ELEMENT(element);
6220 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6223 int el2panelimg(int element)
6225 element = GFX_ELEMENT(element);
6227 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6230 int font2baseimg(int font_nr)
6232 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6235 int getBeltNrFromBeltElement(int element)
6237 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6238 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6239 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6242 int getBeltNrFromBeltActiveElement(int element)
6244 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6245 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6246 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6249 int getBeltNrFromBeltSwitchElement(int element)
6251 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6252 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6253 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6256 int getBeltDirNrFromBeltElement(int element)
6258 static int belt_base_element[4] =
6260 EL_CONVEYOR_BELT_1_LEFT,
6261 EL_CONVEYOR_BELT_2_LEFT,
6262 EL_CONVEYOR_BELT_3_LEFT,
6263 EL_CONVEYOR_BELT_4_LEFT
6266 int belt_nr = getBeltNrFromBeltElement(element);
6267 int belt_dir_nr = element - belt_base_element[belt_nr];
6269 return (belt_dir_nr % 3);
6272 int getBeltDirNrFromBeltSwitchElement(int element)
6274 static int belt_base_element[4] =
6276 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6277 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6278 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6279 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6282 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6283 int belt_dir_nr = element - belt_base_element[belt_nr];
6285 return (belt_dir_nr % 3);
6288 int getBeltDirFromBeltElement(int element)
6290 static int belt_move_dir[3] =
6297 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6299 return belt_move_dir[belt_dir_nr];
6302 int getBeltDirFromBeltSwitchElement(int element)
6304 static int belt_move_dir[3] =
6311 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6313 return belt_move_dir[belt_dir_nr];
6316 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6318 static int belt_base_element[4] =
6320 EL_CONVEYOR_BELT_1_LEFT,
6321 EL_CONVEYOR_BELT_2_LEFT,
6322 EL_CONVEYOR_BELT_3_LEFT,
6323 EL_CONVEYOR_BELT_4_LEFT
6326 return belt_base_element[belt_nr] + belt_dir_nr;
6329 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6331 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6333 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6336 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6338 static int belt_base_element[4] =
6340 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6341 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6342 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6343 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6346 return belt_base_element[belt_nr] + belt_dir_nr;
6349 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6351 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6353 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6356 int getNumActivePlayers_EM()
6358 int num_players = 0;
6364 for (i = 0; i < MAX_PLAYERS; i++)
6365 if (tape.player_participates[i])
6371 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6373 int game_frame_delay_value;
6375 game_frame_delay_value =
6376 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6377 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6380 if (tape.playing && tape.warp_forward && !tape.pausing)
6381 game_frame_delay_value = 0;
6383 return game_frame_delay_value;
6386 unsigned int InitRND(long seed)
6388 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6389 return InitEngineRandom_EM(seed);
6390 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6391 return InitEngineRandom_SP(seed);
6393 return InitEngineRandom_RND(seed);
6397 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6398 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6401 inline static int get_effective_element_EM(int tile, int frame_em)
6403 int element = object_mapping[tile].element_rnd;
6404 int action = object_mapping[tile].action;
6405 boolean is_backside = object_mapping[tile].is_backside;
6406 boolean action_removing = (action == ACTION_DIGGING ||
6407 action == ACTION_SNAPPING ||
6408 action == ACTION_COLLECTING);
6414 case Yacid_splash_eB:
6415 case Yacid_splash_wB:
6416 return (frame_em > 5 ? EL_EMPTY : element);
6422 else /* frame_em == 7 */
6426 case Yacid_splash_eB:
6427 case Yacid_splash_wB:
6430 case Yemerald_stone:
6433 case Ydiamond_stone:
6437 case Xdrip_stretchB:
6456 case Xsand_stonein_1:
6457 case Xsand_stonein_2:
6458 case Xsand_stonein_3:
6459 case Xsand_stonein_4:
6463 return (is_backside || action_removing ? EL_EMPTY : element);
6468 inline static boolean check_linear_animation_EM(int tile)
6472 case Xsand_stonesand_1:
6473 case Xsand_stonesand_quickout_1:
6474 case Xsand_sandstone_1:
6475 case Xsand_stonein_1:
6476 case Xsand_stoneout_1:
6501 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6502 boolean has_crumbled_graphics,
6503 int crumbled, int sync_frame)
6505 /* if element can be crumbled, but certain action graphics are just empty
6506 space (like instantly snapping sand to empty space in 1 frame), do not
6507 treat these empty space graphics as crumbled graphics in EMC engine */
6508 if (crumbled == IMG_EMPTY_SPACE)
6509 has_crumbled_graphics = FALSE;
6511 if (has_crumbled_graphics)
6513 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6514 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6515 g_crumbled->anim_delay,
6516 g_crumbled->anim_mode,
6517 g_crumbled->anim_start_frame,
6520 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6521 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6523 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6525 g_em->has_crumbled_graphics = TRUE;
6529 g_em->crumbled_bitmap = NULL;
6530 g_em->crumbled_src_x = 0;
6531 g_em->crumbled_src_y = 0;
6532 g_em->crumbled_border_size = 0;
6534 g_em->has_crumbled_graphics = FALSE;
6538 void ResetGfxAnimation_EM(int x, int y, int tile)
6543 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6544 int tile, int frame_em, int x, int y)
6546 int action = object_mapping[tile].action;
6548 int direction = object_mapping[tile].direction;
6549 int effective_element = get_effective_element_EM(tile, frame_em);
6550 int graphic = (direction == MV_NONE ?
6551 el_act2img(effective_element, action) :
6552 el_act_dir2img(effective_element, action, direction));
6553 struct GraphicInfo *g = &graphic_info[graphic];
6556 boolean action_removing = (action == ACTION_DIGGING ||
6557 action == ACTION_SNAPPING ||
6558 action == ACTION_COLLECTING);
6559 boolean action_moving = (action == ACTION_FALLING ||
6560 action == ACTION_MOVING ||
6561 action == ACTION_PUSHING ||
6562 action == ACTION_EATING ||
6563 action == ACTION_FILLING ||
6564 action == ACTION_EMPTYING);
6565 boolean action_falling = (action == ACTION_FALLING ||
6566 action == ACTION_FILLING ||
6567 action == ACTION_EMPTYING);
6569 /* special case: graphic uses "2nd movement tile" and has defined
6570 7 frames for movement animation (or less) => use default graphic
6571 for last (8th) frame which ends the movement animation */
6572 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6574 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6575 graphic = (direction == MV_NONE ?
6576 el_act2img(effective_element, action) :
6577 el_act_dir2img(effective_element, action, direction));
6579 g = &graphic_info[graphic];
6583 if (tile == Xsand_stonesand_1 ||
6584 tile == Xsand_stonesand_2 ||
6585 tile == Xsand_stonesand_3 ||
6586 tile == Xsand_stonesand_4)
6587 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6591 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6595 // printf("::: resetting... [%d]\n", tile);
6598 if (action_removing || check_linear_animation_EM(tile))
6600 GfxFrame[x][y] = frame_em;
6602 // printf("::: resetting... [%d]\n", tile);
6605 else if (action_moving)
6607 boolean is_backside = object_mapping[tile].is_backside;
6611 int direction = object_mapping[tile].direction;
6612 int move_dir = (action_falling ? MV_DOWN : direction);
6617 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6618 if (g->double_movement && frame_em == 0)
6622 // printf("::: resetting... [%d]\n", tile);
6626 if (move_dir == MV_LEFT)
6627 GfxFrame[x - 1][y] = GfxFrame[x][y];
6628 else if (move_dir == MV_RIGHT)
6629 GfxFrame[x + 1][y] = GfxFrame[x][y];
6630 else if (move_dir == MV_UP)
6631 GfxFrame[x][y - 1] = GfxFrame[x][y];
6632 else if (move_dir == MV_DOWN)
6633 GfxFrame[x][y + 1] = GfxFrame[x][y];
6640 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6641 if (tile == Xsand_stonesand_quickout_1 ||
6642 tile == Xsand_stonesand_quickout_2)
6647 if (tile == Xsand_stonesand_1 ||
6648 tile == Xsand_stonesand_2 ||
6649 tile == Xsand_stonesand_3 ||
6650 tile == Xsand_stonesand_4)
6651 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6655 if (graphic_info[graphic].anim_global_sync)
6656 sync_frame = FrameCounter;
6657 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6658 sync_frame = GfxFrame[x][y];
6660 sync_frame = 0; /* playfield border (pseudo steel) */
6662 SetRandomAnimationValue(x, y);
6664 int frame = getAnimationFrame(g->anim_frames,
6667 g->anim_start_frame,
6670 g_em->unique_identifier =
6671 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6675 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6676 int tile, int frame_em, int x, int y)
6678 int action = object_mapping[tile].action;
6679 int direction = object_mapping[tile].direction;
6680 boolean is_backside = object_mapping[tile].is_backside;
6681 int effective_element = get_effective_element_EM(tile, frame_em);
6683 int effective_action = action;
6685 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
6687 int graphic = (direction == MV_NONE ?
6688 el_act2img(effective_element, effective_action) :
6689 el_act_dir2img(effective_element, effective_action,
6691 int crumbled = (direction == MV_NONE ?
6692 el_act2crm(effective_element, effective_action) :
6693 el_act_dir2crm(effective_element, effective_action,
6695 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6696 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6697 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6698 struct GraphicInfo *g = &graphic_info[graphic];
6700 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6704 /* special case: graphic uses "2nd movement tile" and has defined
6705 7 frames for movement animation (or less) => use default graphic
6706 for last (8th) frame which ends the movement animation */
6707 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6709 effective_action = ACTION_DEFAULT;
6710 graphic = (direction == MV_NONE ?
6711 el_act2img(effective_element, effective_action) :
6712 el_act_dir2img(effective_element, effective_action,
6714 crumbled = (direction == MV_NONE ?
6715 el_act2crm(effective_element, effective_action) :
6716 el_act_dir2crm(effective_element, effective_action,
6719 g = &graphic_info[graphic];
6729 if (frame_em == 0) /* reset animation frame for certain elements */
6731 if (check_linear_animation_EM(tile))
6736 if (graphic_info[graphic].anim_global_sync)
6737 sync_frame = FrameCounter;
6738 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6739 sync_frame = GfxFrame[x][y];
6741 sync_frame = 0; /* playfield border (pseudo steel) */
6743 SetRandomAnimationValue(x, y);
6748 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6749 i == Xdrip_stretchB ? 7 :
6750 i == Ydrip_s2 ? j + 8 :
6751 i == Ydrip_s2B ? j + 8 :
6760 i == Xfake_acid_1 ? 0 :
6761 i == Xfake_acid_2 ? 10 :
6762 i == Xfake_acid_3 ? 20 :
6763 i == Xfake_acid_4 ? 30 :
6764 i == Xfake_acid_5 ? 40 :
6765 i == Xfake_acid_6 ? 50 :
6766 i == Xfake_acid_7 ? 60 :
6767 i == Xfake_acid_8 ? 70 :
6769 i == Xball_2B ? j + 8 :
6770 i == Yball_eat ? j + 1 :
6771 i == Ykey_1_eat ? j + 1 :
6772 i == Ykey_2_eat ? j + 1 :
6773 i == Ykey_3_eat ? j + 1 :
6774 i == Ykey_4_eat ? j + 1 :
6775 i == Ykey_5_eat ? j + 1 :
6776 i == Ykey_6_eat ? j + 1 :
6777 i == Ykey_7_eat ? j + 1 :
6778 i == Ykey_8_eat ? j + 1 :
6779 i == Ylenses_eat ? j + 1 :
6780 i == Ymagnify_eat ? j + 1 :
6781 i == Ygrass_eat ? j + 1 :
6782 i == Ydirt_eat ? j + 1 :
6783 i == Xamoeba_1 ? 0 :
6784 i == Xamoeba_2 ? 1 :
6785 i == Xamoeba_3 ? 2 :
6786 i == Xamoeba_4 ? 3 :
6787 i == Xamoeba_5 ? 0 :
6788 i == Xamoeba_6 ? 1 :
6789 i == Xamoeba_7 ? 2 :
6790 i == Xamoeba_8 ? 3 :
6791 i == Xexit_2 ? j + 8 :
6792 i == Xexit_3 ? j + 16 :
6793 i == Xdynamite_1 ? 0 :
6794 i == Xdynamite_2 ? 8 :
6795 i == Xdynamite_3 ? 16 :
6796 i == Xdynamite_4 ? 24 :
6797 i == Xsand_stonein_1 ? j + 1 :
6798 i == Xsand_stonein_2 ? j + 9 :
6799 i == Xsand_stonein_3 ? j + 17 :
6800 i == Xsand_stonein_4 ? j + 25 :
6801 i == Xsand_stoneout_1 && j == 0 ? 0 :
6802 i == Xsand_stoneout_1 && j == 1 ? 0 :
6803 i == Xsand_stoneout_1 && j == 2 ? 1 :
6804 i == Xsand_stoneout_1 && j == 3 ? 2 :
6805 i == Xsand_stoneout_1 && j == 4 ? 2 :
6806 i == Xsand_stoneout_1 && j == 5 ? 3 :
6807 i == Xsand_stoneout_1 && j == 6 ? 4 :
6808 i == Xsand_stoneout_1 && j == 7 ? 4 :
6809 i == Xsand_stoneout_2 && j == 0 ? 5 :
6810 i == Xsand_stoneout_2 && j == 1 ? 6 :
6811 i == Xsand_stoneout_2 && j == 2 ? 7 :
6812 i == Xsand_stoneout_2 && j == 3 ? 8 :
6813 i == Xsand_stoneout_2 && j == 4 ? 9 :
6814 i == Xsand_stoneout_2 && j == 5 ? 11 :
6815 i == Xsand_stoneout_2 && j == 6 ? 13 :
6816 i == Xsand_stoneout_2 && j == 7 ? 15 :
6817 i == Xboom_bug && j == 1 ? 2 :
6818 i == Xboom_bug && j == 2 ? 2 :
6819 i == Xboom_bug && j == 3 ? 4 :
6820 i == Xboom_bug && j == 4 ? 4 :
6821 i == Xboom_bug && j == 5 ? 2 :
6822 i == Xboom_bug && j == 6 ? 2 :
6823 i == Xboom_bug && j == 7 ? 0 :
6824 i == Xboom_bomb && j == 1 ? 2 :
6825 i == Xboom_bomb && j == 2 ? 2 :
6826 i == Xboom_bomb && j == 3 ? 4 :
6827 i == Xboom_bomb && j == 4 ? 4 :
6828 i == Xboom_bomb && j == 5 ? 2 :
6829 i == Xboom_bomb && j == 6 ? 2 :
6830 i == Xboom_bomb && j == 7 ? 0 :
6831 i == Xboom_android && j == 7 ? 6 :
6832 i == Xboom_1 && j == 1 ? 2 :
6833 i == Xboom_1 && j == 2 ? 2 :
6834 i == Xboom_1 && j == 3 ? 4 :
6835 i == Xboom_1 && j == 4 ? 4 :
6836 i == Xboom_1 && j == 5 ? 6 :
6837 i == Xboom_1 && j == 6 ? 6 :
6838 i == Xboom_1 && j == 7 ? 8 :
6839 i == Xboom_2 && j == 0 ? 8 :
6840 i == Xboom_2 && j == 1 ? 8 :
6841 i == Xboom_2 && j == 2 ? 10 :
6842 i == Xboom_2 && j == 3 ? 10 :
6843 i == Xboom_2 && j == 4 ? 10 :
6844 i == Xboom_2 && j == 5 ? 12 :
6845 i == Xboom_2 && j == 6 ? 12 :
6846 i == Xboom_2 && j == 7 ? 12 :
6848 special_animation && j == 4 ? 3 :
6849 effective_action != action ? 0 :
6855 int xxx_effective_action;
6856 int xxx_has_action_graphics;
6859 int element = object_mapping[i].element_rnd;
6860 int action = object_mapping[i].action;
6861 int direction = object_mapping[i].direction;
6862 boolean is_backside = object_mapping[i].is_backside;
6864 boolean action_removing = (action == ACTION_DIGGING ||
6865 action == ACTION_SNAPPING ||
6866 action == ACTION_COLLECTING);
6868 boolean action_exploding = ((action == ACTION_EXPLODING ||
6869 action == ACTION_SMASHED_BY_ROCK ||
6870 action == ACTION_SMASHED_BY_SPRING) &&
6871 element != EL_DIAMOND);
6872 boolean action_active = (action == ACTION_ACTIVE);
6873 boolean action_other = (action == ACTION_OTHER);
6877 int effective_element = get_effective_element_EM(i, j);
6879 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6880 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6882 i == Xdrip_stretch ? element :
6883 i == Xdrip_stretchB ? element :
6884 i == Ydrip_s1 ? element :
6885 i == Ydrip_s1B ? element :
6886 i == Xball_1B ? element :
6887 i == Xball_2 ? element :
6888 i == Xball_2B ? element :
6889 i == Yball_eat ? element :
6890 i == Ykey_1_eat ? element :
6891 i == Ykey_2_eat ? element :
6892 i == Ykey_3_eat ? element :
6893 i == Ykey_4_eat ? element :
6894 i == Ykey_5_eat ? element :
6895 i == Ykey_6_eat ? element :
6896 i == Ykey_7_eat ? element :
6897 i == Ykey_8_eat ? element :
6898 i == Ylenses_eat ? element :
6899 i == Ymagnify_eat ? element :
6900 i == Ygrass_eat ? element :
6901 i == Ydirt_eat ? element :
6902 i == Yemerald_stone ? EL_EMERALD :
6903 i == Ydiamond_stone ? EL_ROCK :
6904 i == Xsand_stonein_1 ? element :
6905 i == Xsand_stonein_2 ? element :
6906 i == Xsand_stonein_3 ? element :
6907 i == Xsand_stonein_4 ? element :
6908 is_backside ? EL_EMPTY :
6909 action_removing ? EL_EMPTY :
6912 int effective_action = (j < 7 ? action :
6913 i == Xdrip_stretch ? action :
6914 i == Xdrip_stretchB ? action :
6915 i == Ydrip_s1 ? action :
6916 i == Ydrip_s1B ? action :
6917 i == Xball_1B ? action :
6918 i == Xball_2 ? action :
6919 i == Xball_2B ? action :
6920 i == Yball_eat ? action :
6921 i == Ykey_1_eat ? action :
6922 i == Ykey_2_eat ? action :
6923 i == Ykey_3_eat ? action :
6924 i == Ykey_4_eat ? action :
6925 i == Ykey_5_eat ? action :
6926 i == Ykey_6_eat ? action :
6927 i == Ykey_7_eat ? action :
6928 i == Ykey_8_eat ? action :
6929 i == Ylenses_eat ? action :
6930 i == Ymagnify_eat ? action :
6931 i == Ygrass_eat ? action :
6932 i == Ydirt_eat ? action :
6933 i == Xsand_stonein_1 ? action :
6934 i == Xsand_stonein_2 ? action :
6935 i == Xsand_stonein_3 ? action :
6936 i == Xsand_stonein_4 ? action :
6937 i == Xsand_stoneout_1 ? action :
6938 i == Xsand_stoneout_2 ? action :
6939 i == Xboom_android ? ACTION_EXPLODING :
6940 action_exploding ? ACTION_EXPLODING :
6941 action_active ? action :
6942 action_other ? action :
6944 int graphic = (el_act_dir2img(effective_element, effective_action,
6946 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6948 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6949 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6950 boolean has_action_graphics = (graphic != base_graphic);
6951 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6952 struct GraphicInfo *g = &graphic_info[graphic];
6954 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6956 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6959 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6960 boolean special_animation = (action != ACTION_DEFAULT &&
6961 g->anim_frames == 3 &&
6962 g->anim_delay == 2 &&
6963 g->anim_mode & ANIM_LINEAR);
6964 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6965 i == Xdrip_stretchB ? 7 :
6966 i == Ydrip_s2 ? j + 8 :
6967 i == Ydrip_s2B ? j + 8 :
6976 i == Xfake_acid_1 ? 0 :
6977 i == Xfake_acid_2 ? 10 :
6978 i == Xfake_acid_3 ? 20 :
6979 i == Xfake_acid_4 ? 30 :
6980 i == Xfake_acid_5 ? 40 :
6981 i == Xfake_acid_6 ? 50 :
6982 i == Xfake_acid_7 ? 60 :
6983 i == Xfake_acid_8 ? 70 :
6985 i == Xball_2B ? j + 8 :
6986 i == Yball_eat ? j + 1 :
6987 i == Ykey_1_eat ? j + 1 :
6988 i == Ykey_2_eat ? j + 1 :
6989 i == Ykey_3_eat ? j + 1 :
6990 i == Ykey_4_eat ? j + 1 :
6991 i == Ykey_5_eat ? j + 1 :
6992 i == Ykey_6_eat ? j + 1 :
6993 i == Ykey_7_eat ? j + 1 :
6994 i == Ykey_8_eat ? j + 1 :
6995 i == Ylenses_eat ? j + 1 :
6996 i == Ymagnify_eat ? j + 1 :
6997 i == Ygrass_eat ? j + 1 :
6998 i == Ydirt_eat ? j + 1 :
6999 i == Xamoeba_1 ? 0 :
7000 i == Xamoeba_2 ? 1 :
7001 i == Xamoeba_3 ? 2 :
7002 i == Xamoeba_4 ? 3 :
7003 i == Xamoeba_5 ? 0 :
7004 i == Xamoeba_6 ? 1 :
7005 i == Xamoeba_7 ? 2 :
7006 i == Xamoeba_8 ? 3 :
7007 i == Xexit_2 ? j + 8 :
7008 i == Xexit_3 ? j + 16 :
7009 i == Xdynamite_1 ? 0 :
7010 i == Xdynamite_2 ? 8 :
7011 i == Xdynamite_3 ? 16 :
7012 i == Xdynamite_4 ? 24 :
7013 i == Xsand_stonein_1 ? j + 1 :
7014 i == Xsand_stonein_2 ? j + 9 :
7015 i == Xsand_stonein_3 ? j + 17 :
7016 i == Xsand_stonein_4 ? j + 25 :
7017 i == Xsand_stoneout_1 && j == 0 ? 0 :
7018 i == Xsand_stoneout_1 && j == 1 ? 0 :
7019 i == Xsand_stoneout_1 && j == 2 ? 1 :
7020 i == Xsand_stoneout_1 && j == 3 ? 2 :
7021 i == Xsand_stoneout_1 && j == 4 ? 2 :
7022 i == Xsand_stoneout_1 && j == 5 ? 3 :
7023 i == Xsand_stoneout_1 && j == 6 ? 4 :
7024 i == Xsand_stoneout_1 && j == 7 ? 4 :
7025 i == Xsand_stoneout_2 && j == 0 ? 5 :
7026 i == Xsand_stoneout_2 && j == 1 ? 6 :
7027 i == Xsand_stoneout_2 && j == 2 ? 7 :
7028 i == Xsand_stoneout_2 && j == 3 ? 8 :
7029 i == Xsand_stoneout_2 && j == 4 ? 9 :
7030 i == Xsand_stoneout_2 && j == 5 ? 11 :
7031 i == Xsand_stoneout_2 && j == 6 ? 13 :
7032 i == Xsand_stoneout_2 && j == 7 ? 15 :
7033 i == Xboom_bug && j == 1 ? 2 :
7034 i == Xboom_bug && j == 2 ? 2 :
7035 i == Xboom_bug && j == 3 ? 4 :
7036 i == Xboom_bug && j == 4 ? 4 :
7037 i == Xboom_bug && j == 5 ? 2 :
7038 i == Xboom_bug && j == 6 ? 2 :
7039 i == Xboom_bug && j == 7 ? 0 :
7040 i == Xboom_bomb && j == 1 ? 2 :
7041 i == Xboom_bomb && j == 2 ? 2 :
7042 i == Xboom_bomb && j == 3 ? 4 :
7043 i == Xboom_bomb && j == 4 ? 4 :
7044 i == Xboom_bomb && j == 5 ? 2 :
7045 i == Xboom_bomb && j == 6 ? 2 :
7046 i == Xboom_bomb && j == 7 ? 0 :
7047 i == Xboom_android && j == 7 ? 6 :
7048 i == Xboom_1 && j == 1 ? 2 :
7049 i == Xboom_1 && j == 2 ? 2 :
7050 i == Xboom_1 && j == 3 ? 4 :
7051 i == Xboom_1 && j == 4 ? 4 :
7052 i == Xboom_1 && j == 5 ? 6 :
7053 i == Xboom_1 && j == 6 ? 6 :
7054 i == Xboom_1 && j == 7 ? 8 :
7055 i == Xboom_2 && j == 0 ? 8 :
7056 i == Xboom_2 && j == 1 ? 8 :
7057 i == Xboom_2 && j == 2 ? 10 :
7058 i == Xboom_2 && j == 3 ? 10 :
7059 i == Xboom_2 && j == 4 ? 10 :
7060 i == Xboom_2 && j == 5 ? 12 :
7061 i == Xboom_2 && j == 6 ? 12 :
7062 i == Xboom_2 && j == 7 ? 12 :
7063 special_animation && j == 4 ? 3 :
7064 effective_action != action ? 0 :
7067 xxx_effective_action = effective_action;
7068 xxx_has_action_graphics = has_action_graphics;
7073 int frame = getAnimationFrame(g->anim_frames,
7076 g->anim_start_frame,
7090 int old_src_x = g_em->src_x;
7091 int old_src_y = g_em->src_y;
7095 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7096 g->double_movement && is_backside);
7098 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7099 &g_em->src_x, &g_em->src_y, FALSE);
7110 if (graphic == IMG_BUG_MOVING_RIGHT)
7111 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7112 g->double_movement, is_backside,
7113 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7121 g_em->src_offset_x = 0;
7122 g_em->src_offset_y = 0;
7123 g_em->dst_offset_x = 0;
7124 g_em->dst_offset_y = 0;
7125 g_em->width = TILEX;
7126 g_em->height = TILEY;
7128 g_em->preserve_background = FALSE;
7131 /* (updating the "crumbled" graphic definitions is probably not really needed,
7132 as animations for crumbled graphics can't be longer than one EMC cycle) */
7134 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7139 g_em->crumbled_bitmap = NULL;
7140 g_em->crumbled_src_x = 0;
7141 g_em->crumbled_src_y = 0;
7143 g_em->has_crumbled_graphics = FALSE;
7145 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7147 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7148 g_crumbled->anim_delay,
7149 g_crumbled->anim_mode,
7150 g_crumbled->anim_start_frame,
7153 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7154 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7156 g_em->has_crumbled_graphics = TRUE;
7162 int effective_action = xxx_effective_action;
7163 int has_action_graphics = xxx_has_action_graphics;
7165 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7166 effective_action == ACTION_MOVING ||
7167 effective_action == ACTION_PUSHING ||
7168 effective_action == ACTION_EATING)) ||
7169 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7170 effective_action == ACTION_EMPTYING)))
7173 (effective_action == ACTION_FALLING ||
7174 effective_action == ACTION_FILLING ||
7175 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7176 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7177 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7178 int num_steps = (i == Ydrip_s1 ? 16 :
7179 i == Ydrip_s1B ? 16 :
7180 i == Ydrip_s2 ? 16 :
7181 i == Ydrip_s2B ? 16 :
7182 i == Xsand_stonein_1 ? 32 :
7183 i == Xsand_stonein_2 ? 32 :
7184 i == Xsand_stonein_3 ? 32 :
7185 i == Xsand_stonein_4 ? 32 :
7186 i == Xsand_stoneout_1 ? 16 :
7187 i == Xsand_stoneout_2 ? 16 : 8);
7188 int cx = ABS(dx) * (TILEX / num_steps);
7189 int cy = ABS(dy) * (TILEY / num_steps);
7190 int step_frame = (i == Ydrip_s2 ? j + 8 :
7191 i == Ydrip_s2B ? j + 8 :
7192 i == Xsand_stonein_2 ? j + 8 :
7193 i == Xsand_stonein_3 ? j + 16 :
7194 i == Xsand_stonein_4 ? j + 24 :
7195 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7196 int step = (is_backside ? step_frame : num_steps - step_frame);
7198 if (is_backside) /* tile where movement starts */
7200 if (dx < 0 || dy < 0)
7202 g_em->src_offset_x = cx * step;
7203 g_em->src_offset_y = cy * step;
7207 g_em->dst_offset_x = cx * step;
7208 g_em->dst_offset_y = cy * step;
7211 else /* tile where movement ends */
7213 if (dx < 0 || dy < 0)
7215 g_em->dst_offset_x = cx * step;
7216 g_em->dst_offset_y = cy * step;
7220 g_em->src_offset_x = cx * step;
7221 g_em->src_offset_y = cy * step;
7225 g_em->width = TILEX - cx * step;
7226 g_em->height = TILEY - cy * step;
7229 /* create unique graphic identifier to decide if tile must be redrawn */
7230 /* bit 31 - 16 (16 bit): EM style graphic
7231 bit 15 - 12 ( 4 bit): EM style frame
7232 bit 11 - 6 ( 6 bit): graphic width
7233 bit 5 - 0 ( 6 bit): graphic height */
7234 g_em->unique_identifier =
7235 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7241 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7242 int player_nr, int anim, int frame_em)
7244 int element = player_mapping[player_nr][anim].element_rnd;
7245 int action = player_mapping[player_nr][anim].action;
7246 int direction = player_mapping[player_nr][anim].direction;
7247 int graphic = (direction == MV_NONE ?
7248 el_act2img(element, action) :
7249 el_act_dir2img(element, action, direction));
7250 struct GraphicInfo *g = &graphic_info[graphic];
7253 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7255 stored_player[player_nr].StepFrame = frame_em;
7257 sync_frame = stored_player[player_nr].Frame;
7259 int frame = getAnimationFrame(g->anim_frames,
7262 g->anim_start_frame,
7265 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7266 &g_em->src_x, &g_em->src_y, FALSE);
7269 printf("::: %d: %d, %d [%d]\n",
7271 stored_player[player_nr].Frame,
7272 stored_player[player_nr].StepFrame,
7277 void InitGraphicInfo_EM(void)
7280 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7281 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7286 int num_em_gfx_errors = 0;
7288 if (graphic_info_em_object[0][0].bitmap == NULL)
7290 /* EM graphics not yet initialized in em_open_all() */
7295 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7298 /* always start with reliable default values */
7299 for (i = 0; i < TILE_MAX; i++)
7301 object_mapping[i].element_rnd = EL_UNKNOWN;
7302 object_mapping[i].is_backside = FALSE;
7303 object_mapping[i].action = ACTION_DEFAULT;
7304 object_mapping[i].direction = MV_NONE;
7307 /* always start with reliable default values */
7308 for (p = 0; p < MAX_PLAYERS; p++)
7310 for (i = 0; i < SPR_MAX; i++)
7312 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7313 player_mapping[p][i].action = ACTION_DEFAULT;
7314 player_mapping[p][i].direction = MV_NONE;
7318 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7320 int e = em_object_mapping_list[i].element_em;
7322 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7323 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7325 if (em_object_mapping_list[i].action != -1)
7326 object_mapping[e].action = em_object_mapping_list[i].action;
7328 if (em_object_mapping_list[i].direction != -1)
7329 object_mapping[e].direction =
7330 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7333 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7335 int a = em_player_mapping_list[i].action_em;
7336 int p = em_player_mapping_list[i].player_nr;
7338 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7340 if (em_player_mapping_list[i].action != -1)
7341 player_mapping[p][a].action = em_player_mapping_list[i].action;
7343 if (em_player_mapping_list[i].direction != -1)
7344 player_mapping[p][a].direction =
7345 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7348 for (i = 0; i < TILE_MAX; i++)
7350 int element = object_mapping[i].element_rnd;
7351 int action = object_mapping[i].action;
7352 int direction = object_mapping[i].direction;
7353 boolean is_backside = object_mapping[i].is_backside;
7355 boolean action_removing = (action == ACTION_DIGGING ||
7356 action == ACTION_SNAPPING ||
7357 action == ACTION_COLLECTING);
7359 boolean action_exploding = ((action == ACTION_EXPLODING ||
7360 action == ACTION_SMASHED_BY_ROCK ||
7361 action == ACTION_SMASHED_BY_SPRING) &&
7362 element != EL_DIAMOND);
7363 boolean action_active = (action == ACTION_ACTIVE);
7364 boolean action_other = (action == ACTION_OTHER);
7366 for (j = 0; j < 8; j++)
7369 int effective_element = get_effective_element_EM(i, j);
7371 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7372 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7374 i == Xdrip_stretch ? element :
7375 i == Xdrip_stretchB ? element :
7376 i == Ydrip_s1 ? element :
7377 i == Ydrip_s1B ? element :
7378 i == Xball_1B ? element :
7379 i == Xball_2 ? element :
7380 i == Xball_2B ? element :
7381 i == Yball_eat ? element :
7382 i == Ykey_1_eat ? element :
7383 i == Ykey_2_eat ? element :
7384 i == Ykey_3_eat ? element :
7385 i == Ykey_4_eat ? element :
7386 i == Ykey_5_eat ? element :
7387 i == Ykey_6_eat ? element :
7388 i == Ykey_7_eat ? element :
7389 i == Ykey_8_eat ? element :
7390 i == Ylenses_eat ? element :
7391 i == Ymagnify_eat ? element :
7392 i == Ygrass_eat ? element :
7393 i == Ydirt_eat ? element :
7394 i == Yemerald_stone ? EL_EMERALD :
7395 i == Ydiamond_stone ? EL_ROCK :
7396 i == Xsand_stonein_1 ? element :
7397 i == Xsand_stonein_2 ? element :
7398 i == Xsand_stonein_3 ? element :
7399 i == Xsand_stonein_4 ? element :
7400 is_backside ? EL_EMPTY :
7401 action_removing ? EL_EMPTY :
7404 int effective_action = (j < 7 ? action :
7405 i == Xdrip_stretch ? action :
7406 i == Xdrip_stretchB ? action :
7407 i == Ydrip_s1 ? action :
7408 i == Ydrip_s1B ? action :
7409 i == Xball_1B ? action :
7410 i == Xball_2 ? action :
7411 i == Xball_2B ? action :
7412 i == Yball_eat ? action :
7413 i == Ykey_1_eat ? action :
7414 i == Ykey_2_eat ? action :
7415 i == Ykey_3_eat ? action :
7416 i == Ykey_4_eat ? action :
7417 i == Ykey_5_eat ? action :
7418 i == Ykey_6_eat ? action :
7419 i == Ykey_7_eat ? action :
7420 i == Ykey_8_eat ? action :
7421 i == Ylenses_eat ? action :
7422 i == Ymagnify_eat ? action :
7423 i == Ygrass_eat ? action :
7424 i == Ydirt_eat ? action :
7425 i == Xsand_stonein_1 ? action :
7426 i == Xsand_stonein_2 ? action :
7427 i == Xsand_stonein_3 ? action :
7428 i == Xsand_stonein_4 ? action :
7429 i == Xsand_stoneout_1 ? action :
7430 i == Xsand_stoneout_2 ? action :
7431 i == Xboom_android ? ACTION_EXPLODING :
7432 action_exploding ? ACTION_EXPLODING :
7433 action_active ? action :
7434 action_other ? action :
7436 int graphic = (el_act_dir2img(effective_element, effective_action,
7438 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7440 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7441 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7442 boolean has_action_graphics = (graphic != base_graphic);
7443 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7444 struct GraphicInfo *g = &graphic_info[graphic];
7446 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7448 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7451 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7452 boolean special_animation = (action != ACTION_DEFAULT &&
7453 g->anim_frames == 3 &&
7454 g->anim_delay == 2 &&
7455 g->anim_mode & ANIM_LINEAR);
7456 int sync_frame = (i == Xdrip_stretch ? 7 :
7457 i == Xdrip_stretchB ? 7 :
7458 i == Ydrip_s2 ? j + 8 :
7459 i == Ydrip_s2B ? j + 8 :
7468 i == Xfake_acid_1 ? 0 :
7469 i == Xfake_acid_2 ? 10 :
7470 i == Xfake_acid_3 ? 20 :
7471 i == Xfake_acid_4 ? 30 :
7472 i == Xfake_acid_5 ? 40 :
7473 i == Xfake_acid_6 ? 50 :
7474 i == Xfake_acid_7 ? 60 :
7475 i == Xfake_acid_8 ? 70 :
7477 i == Xball_2B ? j + 8 :
7478 i == Yball_eat ? j + 1 :
7479 i == Ykey_1_eat ? j + 1 :
7480 i == Ykey_2_eat ? j + 1 :
7481 i == Ykey_3_eat ? j + 1 :
7482 i == Ykey_4_eat ? j + 1 :
7483 i == Ykey_5_eat ? j + 1 :
7484 i == Ykey_6_eat ? j + 1 :
7485 i == Ykey_7_eat ? j + 1 :
7486 i == Ykey_8_eat ? j + 1 :
7487 i == Ylenses_eat ? j + 1 :
7488 i == Ymagnify_eat ? j + 1 :
7489 i == Ygrass_eat ? j + 1 :
7490 i == Ydirt_eat ? j + 1 :
7491 i == Xamoeba_1 ? 0 :
7492 i == Xamoeba_2 ? 1 :
7493 i == Xamoeba_3 ? 2 :
7494 i == Xamoeba_4 ? 3 :
7495 i == Xamoeba_5 ? 0 :
7496 i == Xamoeba_6 ? 1 :
7497 i == Xamoeba_7 ? 2 :
7498 i == Xamoeba_8 ? 3 :
7499 i == Xexit_2 ? j + 8 :
7500 i == Xexit_3 ? j + 16 :
7501 i == Xdynamite_1 ? 0 :
7502 i == Xdynamite_2 ? 8 :
7503 i == Xdynamite_3 ? 16 :
7504 i == Xdynamite_4 ? 24 :
7505 i == Xsand_stonein_1 ? j + 1 :
7506 i == Xsand_stonein_2 ? j + 9 :
7507 i == Xsand_stonein_3 ? j + 17 :
7508 i == Xsand_stonein_4 ? j + 25 :
7509 i == Xsand_stoneout_1 && j == 0 ? 0 :
7510 i == Xsand_stoneout_1 && j == 1 ? 0 :
7511 i == Xsand_stoneout_1 && j == 2 ? 1 :
7512 i == Xsand_stoneout_1 && j == 3 ? 2 :
7513 i == Xsand_stoneout_1 && j == 4 ? 2 :
7514 i == Xsand_stoneout_1 && j == 5 ? 3 :
7515 i == Xsand_stoneout_1 && j == 6 ? 4 :
7516 i == Xsand_stoneout_1 && j == 7 ? 4 :
7517 i == Xsand_stoneout_2 && j == 0 ? 5 :
7518 i == Xsand_stoneout_2 && j == 1 ? 6 :
7519 i == Xsand_stoneout_2 && j == 2 ? 7 :
7520 i == Xsand_stoneout_2 && j == 3 ? 8 :
7521 i == Xsand_stoneout_2 && j == 4 ? 9 :
7522 i == Xsand_stoneout_2 && j == 5 ? 11 :
7523 i == Xsand_stoneout_2 && j == 6 ? 13 :
7524 i == Xsand_stoneout_2 && j == 7 ? 15 :
7525 i == Xboom_bug && j == 1 ? 2 :
7526 i == Xboom_bug && j == 2 ? 2 :
7527 i == Xboom_bug && j == 3 ? 4 :
7528 i == Xboom_bug && j == 4 ? 4 :
7529 i == Xboom_bug && j == 5 ? 2 :
7530 i == Xboom_bug && j == 6 ? 2 :
7531 i == Xboom_bug && j == 7 ? 0 :
7532 i == Xboom_bomb && j == 1 ? 2 :
7533 i == Xboom_bomb && j == 2 ? 2 :
7534 i == Xboom_bomb && j == 3 ? 4 :
7535 i == Xboom_bomb && j == 4 ? 4 :
7536 i == Xboom_bomb && j == 5 ? 2 :
7537 i == Xboom_bomb && j == 6 ? 2 :
7538 i == Xboom_bomb && j == 7 ? 0 :
7539 i == Xboom_android && j == 7 ? 6 :
7540 i == Xboom_1 && j == 1 ? 2 :
7541 i == Xboom_1 && j == 2 ? 2 :
7542 i == Xboom_1 && j == 3 ? 4 :
7543 i == Xboom_1 && j == 4 ? 4 :
7544 i == Xboom_1 && j == 5 ? 6 :
7545 i == Xboom_1 && j == 6 ? 6 :
7546 i == Xboom_1 && j == 7 ? 8 :
7547 i == Xboom_2 && j == 0 ? 8 :
7548 i == Xboom_2 && j == 1 ? 8 :
7549 i == Xboom_2 && j == 2 ? 10 :
7550 i == Xboom_2 && j == 3 ? 10 :
7551 i == Xboom_2 && j == 4 ? 10 :
7552 i == Xboom_2 && j == 5 ? 12 :
7553 i == Xboom_2 && j == 6 ? 12 :
7554 i == Xboom_2 && j == 7 ? 12 :
7555 special_animation && j == 4 ? 3 :
7556 effective_action != action ? 0 :
7560 Bitmap *debug_bitmap = g_em->bitmap;
7561 int debug_src_x = g_em->src_x;
7562 int debug_src_y = g_em->src_y;
7565 int frame = getAnimationFrame(g->anim_frames,
7568 g->anim_start_frame,
7571 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7572 g->double_movement && is_backside);
7574 g_em->bitmap = src_bitmap;
7575 g_em->src_x = src_x;
7576 g_em->src_y = src_y;
7577 g_em->src_offset_x = 0;
7578 g_em->src_offset_y = 0;
7579 g_em->dst_offset_x = 0;
7580 g_em->dst_offset_y = 0;
7581 g_em->width = TILEX;
7582 g_em->height = TILEY;
7584 g_em->preserve_background = FALSE;
7587 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7592 g_em->crumbled_bitmap = NULL;
7593 g_em->crumbled_src_x = 0;
7594 g_em->crumbled_src_y = 0;
7595 g_em->crumbled_border_size = 0;
7597 g_em->has_crumbled_graphics = FALSE;
7600 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
7601 printf("::: empty crumbled: %d [%s], %d, %d\n",
7602 effective_element, element_info[effective_element].token_name,
7603 effective_action, direction);
7606 /* if element can be crumbled, but certain action graphics are just empty
7607 space (like instantly snapping sand to empty space in 1 frame), do not
7608 treat these empty space graphics as crumbled graphics in EMC engine */
7609 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7611 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7612 g_crumbled->anim_delay,
7613 g_crumbled->anim_mode,
7614 g_crumbled->anim_start_frame,
7617 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
7619 g_em->has_crumbled_graphics = TRUE;
7620 g_em->crumbled_bitmap = src_bitmap;
7621 g_em->crumbled_src_x = src_x;
7622 g_em->crumbled_src_y = src_y;
7623 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7627 if (g_em == &graphic_info_em_object[207][0])
7628 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
7629 graphic_info_em_object[207][0].crumbled_src_x,
7630 graphic_info_em_object[207][0].crumbled_src_y,
7632 crumbled, frame, src_x, src_y,
7637 g->anim_start_frame,
7639 gfx.anim_random_frame,
7644 printf("::: EMC tile %d is crumbled\n", i);
7650 if (element == EL_ROCK &&
7651 effective_action == ACTION_FILLING)
7652 printf("::: has_action_graphics == %d\n", has_action_graphics);
7655 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7656 effective_action == ACTION_MOVING ||
7657 effective_action == ACTION_PUSHING ||
7658 effective_action == ACTION_EATING)) ||
7659 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7660 effective_action == ACTION_EMPTYING)))
7663 (effective_action == ACTION_FALLING ||
7664 effective_action == ACTION_FILLING ||
7665 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7666 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7667 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7668 int num_steps = (i == Ydrip_s1 ? 16 :
7669 i == Ydrip_s1B ? 16 :
7670 i == Ydrip_s2 ? 16 :
7671 i == Ydrip_s2B ? 16 :
7672 i == Xsand_stonein_1 ? 32 :
7673 i == Xsand_stonein_2 ? 32 :
7674 i == Xsand_stonein_3 ? 32 :
7675 i == Xsand_stonein_4 ? 32 :
7676 i == Xsand_stoneout_1 ? 16 :
7677 i == Xsand_stoneout_2 ? 16 : 8);
7678 int cx = ABS(dx) * (TILEX / num_steps);
7679 int cy = ABS(dy) * (TILEY / num_steps);
7680 int step_frame = (i == Ydrip_s2 ? j + 8 :
7681 i == Ydrip_s2B ? j + 8 :
7682 i == Xsand_stonein_2 ? j + 8 :
7683 i == Xsand_stonein_3 ? j + 16 :
7684 i == Xsand_stonein_4 ? j + 24 :
7685 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7686 int step = (is_backside ? step_frame : num_steps - step_frame);
7688 if (is_backside) /* tile where movement starts */
7690 if (dx < 0 || dy < 0)
7692 g_em->src_offset_x = cx * step;
7693 g_em->src_offset_y = cy * step;
7697 g_em->dst_offset_x = cx * step;
7698 g_em->dst_offset_y = cy * step;
7701 else /* tile where movement ends */
7703 if (dx < 0 || dy < 0)
7705 g_em->dst_offset_x = cx * step;
7706 g_em->dst_offset_y = cy * step;
7710 g_em->src_offset_x = cx * step;
7711 g_em->src_offset_y = cy * step;
7715 g_em->width = TILEX - cx * step;
7716 g_em->height = TILEY - cy * step;
7719 /* create unique graphic identifier to decide if tile must be redrawn */
7720 /* bit 31 - 16 (16 bit): EM style graphic
7721 bit 15 - 12 ( 4 bit): EM style frame
7722 bit 11 - 6 ( 6 bit): graphic width
7723 bit 5 - 0 ( 6 bit): graphic height */
7724 g_em->unique_identifier =
7725 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7729 /* skip check for EMC elements not contained in original EMC artwork */
7730 if (element == EL_EMC_FAKE_ACID)
7733 if (g_em->bitmap != debug_bitmap ||
7734 g_em->src_x != debug_src_x ||
7735 g_em->src_y != debug_src_y ||
7736 g_em->src_offset_x != 0 ||
7737 g_em->src_offset_y != 0 ||
7738 g_em->dst_offset_x != 0 ||
7739 g_em->dst_offset_y != 0 ||
7740 g_em->width != TILEX ||
7741 g_em->height != TILEY)
7743 static int last_i = -1;
7751 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7752 i, element, element_info[element].token_name,
7753 element_action_info[effective_action].suffix, direction);
7755 if (element != effective_element)
7756 printf(" [%d ('%s')]",
7758 element_info[effective_element].token_name);
7762 if (g_em->bitmap != debug_bitmap)
7763 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7764 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7766 if (g_em->src_x != debug_src_x ||
7767 g_em->src_y != debug_src_y)
7768 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7769 j, (is_backside ? 'B' : 'F'),
7770 g_em->src_x, g_em->src_y,
7771 g_em->src_x / 32, g_em->src_y / 32,
7772 debug_src_x, debug_src_y,
7773 debug_src_x / 32, debug_src_y / 32);
7775 if (g_em->src_offset_x != 0 ||
7776 g_em->src_offset_y != 0 ||
7777 g_em->dst_offset_x != 0 ||
7778 g_em->dst_offset_y != 0)
7779 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7781 g_em->src_offset_x, g_em->src_offset_y,
7782 g_em->dst_offset_x, g_em->dst_offset_y);
7784 if (g_em->width != TILEX ||
7785 g_em->height != TILEY)
7786 printf(" %d (%d): size %d,%d should be %d,%d\n",
7788 g_em->width, g_em->height, TILEX, TILEY);
7790 num_em_gfx_errors++;
7797 for (i = 0; i < TILE_MAX; i++)
7799 for (j = 0; j < 8; j++)
7801 int element = object_mapping[i].element_rnd;
7802 int action = object_mapping[i].action;
7803 int direction = object_mapping[i].direction;
7804 boolean is_backside = object_mapping[i].is_backside;
7805 int graphic_action = el_act_dir2img(element, action, direction);
7806 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7808 if ((action == ACTION_SMASHED_BY_ROCK ||
7809 action == ACTION_SMASHED_BY_SPRING ||
7810 action == ACTION_EATING) &&
7811 graphic_action == graphic_default)
7813 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7814 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7815 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7816 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7819 /* no separate animation for "smashed by rock" -- use rock instead */
7820 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7821 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7823 g_em->bitmap = g_xx->bitmap;
7824 g_em->src_x = g_xx->src_x;
7825 g_em->src_y = g_xx->src_y;
7826 g_em->src_offset_x = g_xx->src_offset_x;
7827 g_em->src_offset_y = g_xx->src_offset_y;
7828 g_em->dst_offset_x = g_xx->dst_offset_x;
7829 g_em->dst_offset_y = g_xx->dst_offset_y;
7830 g_em->width = g_xx->width;
7831 g_em->height = g_xx->height;
7832 g_em->unique_identifier = g_xx->unique_identifier;
7835 g_em->preserve_background = TRUE;
7840 for (p = 0; p < MAX_PLAYERS; p++)
7842 for (i = 0; i < SPR_MAX; i++)
7844 int element = player_mapping[p][i].element_rnd;
7845 int action = player_mapping[p][i].action;
7846 int direction = player_mapping[p][i].direction;
7848 for (j = 0; j < 8; j++)
7850 int effective_element = element;
7851 int effective_action = action;
7852 int graphic = (direction == MV_NONE ?
7853 el_act2img(effective_element, effective_action) :
7854 el_act_dir2img(effective_element, effective_action,
7856 struct GraphicInfo *g = &graphic_info[graphic];
7857 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7863 Bitmap *debug_bitmap = g_em->bitmap;
7864 int debug_src_x = g_em->src_x;
7865 int debug_src_y = g_em->src_y;
7868 int frame = getAnimationFrame(g->anim_frames,
7871 g->anim_start_frame,
7874 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7876 g_em->bitmap = src_bitmap;
7877 g_em->src_x = src_x;
7878 g_em->src_y = src_y;
7879 g_em->src_offset_x = 0;
7880 g_em->src_offset_y = 0;
7881 g_em->dst_offset_x = 0;
7882 g_em->dst_offset_y = 0;
7883 g_em->width = TILEX;
7884 g_em->height = TILEY;
7888 /* skip check for EMC elements not contained in original EMC artwork */
7889 if (element == EL_PLAYER_3 ||
7890 element == EL_PLAYER_4)
7893 if (g_em->bitmap != debug_bitmap ||
7894 g_em->src_x != debug_src_x ||
7895 g_em->src_y != debug_src_y)
7897 static int last_i = -1;
7905 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7906 p, i, element, element_info[element].token_name,
7907 element_action_info[effective_action].suffix, direction);
7909 if (element != effective_element)
7910 printf(" [%d ('%s')]",
7912 element_info[effective_element].token_name);
7916 if (g_em->bitmap != debug_bitmap)
7917 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7918 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7920 if (g_em->src_x != debug_src_x ||
7921 g_em->src_y != debug_src_y)
7922 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7924 g_em->src_x, g_em->src_y,
7925 g_em->src_x / 32, g_em->src_y / 32,
7926 debug_src_x, debug_src_y,
7927 debug_src_x / 32, debug_src_y / 32);
7929 num_em_gfx_errors++;
7939 printf("::: [%d errors found]\n", num_em_gfx_errors);
7945 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7946 int graphic, int sync_frame, int x, int y)
7948 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7950 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7953 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7955 return (IS_NEXT_FRAME(sync_frame, graphic));
7958 int getGraphicInfo_Delay(int graphic)
7960 return graphic_info[graphic].anim_delay;
7963 void PlayMenuSoundExt(int sound)
7965 if (sound == SND_UNDEFINED)
7968 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7969 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7972 if (IS_LOOP_SOUND(sound))
7973 PlaySoundLoop(sound);
7978 void PlayMenuSound()
7980 PlayMenuSoundExt(menu.sound[game_status]);
7983 void PlayMenuSoundStereo(int sound, int stereo_position)
7985 if (sound == SND_UNDEFINED)
7988 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7989 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7992 if (IS_LOOP_SOUND(sound))
7993 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7995 PlaySoundStereo(sound, stereo_position);
7998 void PlayMenuSoundIfLoopExt(int sound)
8000 if (sound == SND_UNDEFINED)
8003 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8004 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8007 if (IS_LOOP_SOUND(sound))
8008 PlaySoundLoop(sound);
8011 void PlayMenuSoundIfLoop()
8013 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8016 void PlayMenuMusicExt(int music)
8018 if (music == MUS_UNDEFINED)
8021 if (!setup.sound_music)
8027 void PlayMenuMusic()
8029 PlayMenuMusicExt(menu.music[game_status]);
8032 void PlaySoundActivating()
8035 PlaySound(SND_MENU_ITEM_ACTIVATING);
8039 void PlaySoundSelecting()
8042 PlaySound(SND_MENU_ITEM_SELECTING);
8046 void ToggleFullscreenIfNeeded()
8048 boolean change_fullscreen = (setup.fullscreen !=
8049 video.fullscreen_enabled);
8050 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8051 !strEqual(setup.fullscreen_mode,
8052 video.fullscreen_mode_current));
8054 if (!video.fullscreen_available)
8057 if (change_fullscreen || change_fullscreen_mode)
8059 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8061 /* save backbuffer content which gets lost when toggling fullscreen mode */
8062 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8064 if (change_fullscreen_mode)
8066 /* keep fullscreen, but change fullscreen mode (screen resolution) */
8067 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
8070 /* toggle fullscreen */
8071 ChangeVideoModeIfNeeded(setup.fullscreen);
8073 setup.fullscreen = video.fullscreen_enabled;
8075 /* restore backbuffer content from temporary backbuffer backup bitmap */
8076 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8078 FreeBitmap(tmp_backbuffer);
8081 /* update visible window/screen */
8082 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8084 redraw_mask = REDRAW_ALL;
8089 void ChangeViewportPropertiesIfNeeded()
8091 int *door_1_x = &DX;
8092 int *door_1_y = &DY;
8093 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
8094 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
8095 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
8096 game_status == GAME_MODE_EDITOR ? game_status :
8098 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8099 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8100 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
8101 int border_size = vp_playfield->border_size;
8102 int new_sx = vp_playfield->x + border_size;
8103 int new_sy = vp_playfield->y + border_size;
8104 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
8105 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
8108 /* !!! TEST ONLY !!! */
8109 // InitGfxBuffers();
8113 if (viewport.window.width != WIN_XSIZE ||
8114 viewport.window.height != WIN_YSIZE)
8116 WIN_XSIZE = viewport.window.width;
8117 WIN_YSIZE = viewport.window.height;
8119 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8123 SetDrawDeactivationMask(REDRAW_NONE);
8124 SetDrawBackgroundMask(REDRAW_FIELD);
8126 // RedrawBackground();
8130 if (new_scr_fieldx != SCR_FIELDX ||
8131 new_scr_fieldy != SCR_FIELDY ||
8134 vp_playfield->x != REAL_SX ||
8135 vp_playfield->y != REAL_SY ||
8136 vp_door_1->x != *door_1_x ||
8137 vp_door_1->y != *door_1_y ||
8138 vp_door_2->x != *door_2_x ||
8139 vp_door_2->y != *door_2_y)
8141 SCR_FIELDX = new_scr_fieldx;
8142 SCR_FIELDY = new_scr_fieldy;
8145 REAL_SX = vp_playfield->x;
8146 REAL_SY = vp_playfield->y;
8148 *door_1_x = vp_door_1->x;
8149 *door_1_y = vp_door_1->y;
8150 *door_2_x = vp_door_2->x;
8151 *door_2_y = vp_door_2->y;
8155 if (gfx_game_mode == GAME_MODE_MAIN)
8163 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);