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 AnimateEnvelopeDoor(char *text, int anim_mode, int action)
2121 int envelope_nr = 0;
2123 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2124 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2125 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2126 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2127 boolean no_delay = (tape.warp_forward);
2128 unsigned long anim_delay = 0;
2129 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2130 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2131 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2132 int font_width = getFontWidth(font_nr);
2133 int font_height = getFontHeight(font_nr);
2135 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2136 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
2138 int max_xsize = level.envelope[envelope_nr].xsize;
2139 int max_ysize = level.envelope[envelope_nr].ysize;
2141 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2142 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2143 int xend = max_xsize;
2144 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2145 int xstep = (xstart < xend ? 1 : 0);
2146 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2150 int max_word_len = 0;
2152 char *text_copy = getStringCopy(text);
2154 font_nr = FONT_TEXT_2;
2156 for (text_ptr = text; *text_ptr; text_ptr++)
2158 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2160 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2162 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2163 font_nr = FONT_TEXT_1;
2169 for (text_ptr = text_copy; *text_ptr; text_ptr++)
2170 if (*text_ptr == ' ')
2174 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2176 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2177 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2178 int sx = (SXSIZE - xsize * font_width) / 2;
2179 int sy = (SYSIZE - ysize * font_height) / 2;
2183 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2185 SetDrawtoField(DRAW_BUFFERED);
2187 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2189 SetDrawtoField(DRAW_BACKBUFFER);
2192 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2193 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2198 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2199 text_copy, font_nr, max_xsize,
2200 xsize - 2, ysize - 2, mask_mode,
2201 FALSE, TRUE, FALSE);
2203 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2204 level.envelope[envelope_nr].text, font_nr, max_xsize,
2205 xsize - 2, ysize - 2, mask_mode,
2206 level.envelope[envelope_nr].autowrap,
2207 level.envelope[envelope_nr].centered, FALSE);
2211 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2212 level.envelope[envelope_nr].text, font_nr, max_xsize,
2213 xsize - 2, ysize - 2, mask_mode);
2217 redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2219 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2229 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2235 void ShowEnvelope(int envelope_nr)
2237 int element = EL_ENVELOPE_1 + envelope_nr;
2238 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2239 int sound_opening = element_info[element].sound[ACTION_OPENING];
2240 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2241 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2242 boolean no_delay = (tape.warp_forward);
2243 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2244 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2245 int anim_mode = graphic_info[graphic].anim_mode;
2246 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2247 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2249 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2251 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2253 if (anim_mode == ANIM_DEFAULT)
2254 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2256 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2259 Delay(wait_delay_value);
2261 WaitForEventToContinue();
2263 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2265 if (anim_mode != ANIM_NONE)
2266 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2268 if (anim_mode == ANIM_DEFAULT)
2269 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2271 game.envelope_active = FALSE;
2273 SetDrawtoField(DRAW_BUFFERED);
2275 redraw_mask |= REDRAW_FIELD;
2279 void ShowEnvelopeDoor(char *text)
2282 int last_game_status = game_status; /* save current game status */
2283 int envelope_nr = 0;
2285 int element = EL_ENVELOPE_1 + envelope_nr;
2286 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2287 int sound_opening = element_info[element].sound[ACTION_OPENING];
2288 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2289 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2290 boolean no_delay = (tape.warp_forward);
2291 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2292 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2293 int anim_mode = graphic_info[graphic].anim_mode;
2294 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2295 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2298 if (game_status == GAME_MODE_PLAYING)
2300 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2301 BlitScreenToBitmap_EM(backbuffer);
2302 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2303 BlitScreenToBitmap_SP(backbuffer);
2306 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2310 SetDrawtoField(DRAW_BACKBUFFER);
2312 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2314 if (game_status != GAME_MODE_MAIN)
2317 /* force DOOR font inside door area */
2318 game_status = GAME_MODE_PSEUDO_DOOR;
2321 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2323 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2325 if (anim_mode == ANIM_DEFAULT)
2326 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING);
2328 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING);
2331 Delay(wait_delay_value);
2333 WaitForEventToContinue();
2335 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2337 if (anim_mode != ANIM_NONE)
2338 AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING);
2340 if (anim_mode == ANIM_DEFAULT)
2341 AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING);
2343 game.envelope_active = FALSE;
2346 game_status = last_game_status; /* restore current game status */
2348 if (game_status != GAME_MODE_MAIN)
2351 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2353 SetDrawtoField(DRAW_BUFFERED);
2357 redraw_mask |= REDRAW_ALL;
2359 redraw_mask |= REDRAW_FIELD;
2363 if (game_status == GAME_MODE_MAIN)
2368 if (game_status == GAME_MODE_PLAYING &&
2369 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2370 SetDrawtoField(DRAW_BUFFERED);
2376 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2380 int graphic = el2preimg(element);
2382 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2383 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2391 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2392 SetDrawBackgroundMask(REDRAW_FIELD);
2394 SetDrawBackgroundMask(REDRAW_NONE);
2399 for (x = BX1; x <= BX2; x++)
2400 for (y = BY1; y <= BY2; y++)
2401 DrawScreenField(x, y);
2403 redraw_mask |= REDRAW_FIELD;
2406 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2410 for (x = 0; x < size_x; x++)
2411 for (y = 0; y < size_y; y++)
2412 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2414 redraw_mask |= REDRAW_FIELD;
2417 static void DrawPreviewLevelExt(int from_x, int from_y)
2419 boolean show_level_border = (BorderElement != EL_EMPTY);
2420 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2421 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2422 int tile_size = preview.tile_size;
2423 int preview_width = preview.xsize * tile_size;
2424 int preview_height = preview.ysize * tile_size;
2425 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2426 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2427 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2428 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2431 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2433 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2434 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2436 for (x = 0; x < real_preview_xsize; x++)
2438 for (y = 0; y < real_preview_ysize; y++)
2440 int lx = from_x + x + (show_level_border ? -1 : 0);
2441 int ly = from_y + y + (show_level_border ? -1 : 0);
2442 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2443 getBorderElement(lx, ly));
2445 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2446 element, tile_size);
2450 redraw_mask |= REDRAW_MICROLEVEL;
2453 #define MICROLABEL_EMPTY 0
2454 #define MICROLABEL_LEVEL_NAME 1
2455 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2456 #define MICROLABEL_LEVEL_AUTHOR 3
2457 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2458 #define MICROLABEL_IMPORTED_FROM 5
2459 #define MICROLABEL_IMPORTED_BY_HEAD 6
2460 #define MICROLABEL_IMPORTED_BY 7
2462 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2464 int max_text_width = SXSIZE;
2465 int font_width = getFontWidth(font_nr);
2467 if (pos->align == ALIGN_CENTER)
2468 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2469 else if (pos->align == ALIGN_RIGHT)
2470 max_text_width = pos->x;
2472 max_text_width = SXSIZE - pos->x;
2474 return max_text_width / font_width;
2477 static void DrawPreviewLevelLabelExt(int mode)
2479 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2480 char label_text[MAX_OUTPUT_LINESIZE + 1];
2481 int max_len_label_text;
2483 int font_nr = pos->font;
2486 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2487 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2488 mode == MICROLABEL_IMPORTED_BY_HEAD)
2489 font_nr = pos->font_alt;
2491 int font_nr = FONT_TEXT_2;
2494 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2495 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2496 mode == MICROLABEL_IMPORTED_BY_HEAD)
2497 font_nr = FONT_TEXT_3;
2501 max_len_label_text = getMaxTextLength(pos, font_nr);
2503 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2507 if (pos->size != -1)
2508 max_len_label_text = pos->size;
2511 for (i = 0; i < max_len_label_text; i++)
2512 label_text[i] = ' ';
2513 label_text[max_len_label_text] = '\0';
2515 if (strlen(label_text) > 0)
2518 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2520 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2521 int lypos = MICROLABEL2_YPOS;
2523 DrawText(lxpos, lypos, label_text, font_nr);
2528 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2529 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2530 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2531 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2532 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2533 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2534 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2535 max_len_label_text);
2536 label_text[max_len_label_text] = '\0';
2538 if (strlen(label_text) > 0)
2541 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2543 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2544 int lypos = MICROLABEL2_YPOS;
2546 DrawText(lxpos, lypos, label_text, font_nr);
2550 redraw_mask |= REDRAW_MICROLEVEL;
2553 void DrawPreviewLevel(boolean restart)
2555 static unsigned long scroll_delay = 0;
2556 static unsigned long label_delay = 0;
2557 static int from_x, from_y, scroll_direction;
2558 static int label_state, label_counter;
2559 unsigned long scroll_delay_value = preview.step_delay;
2560 boolean show_level_border = (BorderElement != EL_EMPTY);
2561 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2562 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2563 int last_game_status = game_status; /* save current game status */
2566 /* force PREVIEW font on preview level */
2567 game_status = GAME_MODE_PSEUDO_PREVIEW;
2575 if (preview.anim_mode == ANIM_CENTERED)
2577 if (level_xsize > preview.xsize)
2578 from_x = (level_xsize - preview.xsize) / 2;
2579 if (level_ysize > preview.ysize)
2580 from_y = (level_ysize - preview.ysize) / 2;
2583 from_x += preview.xoffset;
2584 from_y += preview.yoffset;
2586 scroll_direction = MV_RIGHT;
2590 DrawPreviewLevelExt(from_x, from_y);
2591 DrawPreviewLevelLabelExt(label_state);
2593 /* initialize delay counters */
2594 DelayReached(&scroll_delay, 0);
2595 DelayReached(&label_delay, 0);
2597 if (leveldir_current->name)
2599 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2600 char label_text[MAX_OUTPUT_LINESIZE + 1];
2602 int font_nr = pos->font;
2604 int font_nr = FONT_TEXT_1;
2607 int max_len_label_text = getMaxTextLength(pos, font_nr);
2609 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2617 if (pos->size != -1)
2618 max_len_label_text = pos->size;
2621 strncpy(label_text, leveldir_current->name, max_len_label_text);
2622 label_text[max_len_label_text] = '\0';
2625 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2627 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2628 lypos = SY + MICROLABEL1_YPOS;
2630 DrawText(lxpos, lypos, label_text, font_nr);
2634 game_status = last_game_status; /* restore current game status */
2639 /* scroll preview level, if needed */
2640 if (preview.anim_mode != ANIM_NONE &&
2641 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2642 DelayReached(&scroll_delay, scroll_delay_value))
2644 switch (scroll_direction)
2649 from_x -= preview.step_offset;
2650 from_x = (from_x < 0 ? 0 : from_x);
2653 scroll_direction = MV_UP;
2657 if (from_x < level_xsize - preview.xsize)
2659 from_x += preview.step_offset;
2660 from_x = (from_x > level_xsize - preview.xsize ?
2661 level_xsize - preview.xsize : from_x);
2664 scroll_direction = MV_DOWN;
2670 from_y -= preview.step_offset;
2671 from_y = (from_y < 0 ? 0 : from_y);
2674 scroll_direction = MV_RIGHT;
2678 if (from_y < level_ysize - preview.ysize)
2680 from_y += preview.step_offset;
2681 from_y = (from_y > level_ysize - preview.ysize ?
2682 level_ysize - preview.ysize : from_y);
2685 scroll_direction = MV_LEFT;
2692 DrawPreviewLevelExt(from_x, from_y);
2695 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2696 /* redraw micro level label, if needed */
2697 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2698 !strEqual(level.author, ANONYMOUS_NAME) &&
2699 !strEqual(level.author, leveldir_current->name) &&
2700 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2702 int max_label_counter = 23;
2704 if (leveldir_current->imported_from != NULL &&
2705 strlen(leveldir_current->imported_from) > 0)
2706 max_label_counter += 14;
2707 if (leveldir_current->imported_by != NULL &&
2708 strlen(leveldir_current->imported_by) > 0)
2709 max_label_counter += 14;
2711 label_counter = (label_counter + 1) % max_label_counter;
2712 label_state = (label_counter >= 0 && label_counter <= 7 ?
2713 MICROLABEL_LEVEL_NAME :
2714 label_counter >= 9 && label_counter <= 12 ?
2715 MICROLABEL_LEVEL_AUTHOR_HEAD :
2716 label_counter >= 14 && label_counter <= 21 ?
2717 MICROLABEL_LEVEL_AUTHOR :
2718 label_counter >= 23 && label_counter <= 26 ?
2719 MICROLABEL_IMPORTED_FROM_HEAD :
2720 label_counter >= 28 && label_counter <= 35 ?
2721 MICROLABEL_IMPORTED_FROM :
2722 label_counter >= 37 && label_counter <= 40 ?
2723 MICROLABEL_IMPORTED_BY_HEAD :
2724 label_counter >= 42 && label_counter <= 49 ?
2725 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2727 if (leveldir_current->imported_from == NULL &&
2728 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2729 label_state == MICROLABEL_IMPORTED_FROM))
2730 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2731 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2733 DrawPreviewLevelLabelExt(label_state);
2736 game_status = last_game_status; /* restore current game status */
2739 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2740 int graphic, int sync_frame, int mask_mode)
2742 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2744 if (mask_mode == USE_MASKING)
2745 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2747 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2750 inline void DrawGraphicAnimation(int x, int y, int graphic)
2752 int lx = LEVELX(x), ly = LEVELY(y);
2754 if (!IN_SCR_FIELD(x, y))
2757 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2758 graphic, GfxFrame[lx][ly], NO_MASKING);
2759 MarkTileDirty(x, y);
2762 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2764 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2767 void DrawLevelElementAnimation(int x, int y, int element)
2769 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2771 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2774 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2776 int sx = SCREENX(x), sy = SCREENY(y);
2778 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2781 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2784 DrawGraphicAnimation(sx, sy, graphic);
2787 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2788 DrawLevelFieldCrumbled(x, y);
2790 if (GFX_CRUMBLED(Feld[x][y]))
2791 DrawLevelFieldCrumbled(x, y);
2795 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2797 int sx = SCREENX(x), sy = SCREENY(y);
2800 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2803 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2805 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2808 DrawGraphicAnimation(sx, sy, graphic);
2810 if (GFX_CRUMBLED(element))
2811 DrawLevelFieldCrumbled(x, y);
2814 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2816 if (player->use_murphy)
2818 /* this works only because currently only one player can be "murphy" ... */
2819 static int last_horizontal_dir = MV_LEFT;
2820 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2822 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2823 last_horizontal_dir = move_dir;
2825 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2827 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2829 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2835 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2838 static boolean equalGraphics(int graphic1, int graphic2)
2840 struct GraphicInfo *g1 = &graphic_info[graphic1];
2841 struct GraphicInfo *g2 = &graphic_info[graphic2];
2843 return (g1->bitmap == g2->bitmap &&
2844 g1->src_x == g2->src_x &&
2845 g1->src_y == g2->src_y &&
2846 g1->anim_frames == g2->anim_frames &&
2847 g1->anim_delay == g2->anim_delay &&
2848 g1->anim_mode == g2->anim_mode);
2851 void DrawAllPlayers()
2855 for (i = 0; i < MAX_PLAYERS; i++)
2856 if (stored_player[i].active)
2857 DrawPlayer(&stored_player[i]);
2860 void DrawPlayerField(int x, int y)
2862 if (!IS_PLAYER(x, y))
2865 DrawPlayer(PLAYERINFO(x, y));
2868 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2870 void DrawPlayer(struct PlayerInfo *player)
2872 int jx = player->jx;
2873 int jy = player->jy;
2874 int move_dir = player->MovDir;
2875 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2876 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2877 int last_jx = (player->is_moving ? jx - dx : jx);
2878 int last_jy = (player->is_moving ? jy - dy : jy);
2879 int next_jx = jx + dx;
2880 int next_jy = jy + dy;
2881 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2882 boolean player_is_opaque = FALSE;
2883 int sx = SCREENX(jx), sy = SCREENY(jy);
2884 int sxx = 0, syy = 0;
2885 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2887 int action = ACTION_DEFAULT;
2888 int last_player_graphic = getPlayerGraphic(player, move_dir);
2889 int last_player_frame = player->Frame;
2892 /* GfxElement[][] is set to the element the player is digging or collecting;
2893 remove also for off-screen player if the player is not moving anymore */
2894 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2895 GfxElement[jx][jy] = EL_UNDEFINED;
2897 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2901 if (!IN_LEV_FIELD(jx, jy))
2903 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2904 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2905 printf("DrawPlayerField(): This should never happen!\n");
2910 if (element == EL_EXPLOSION)
2913 action = (player->is_pushing ? ACTION_PUSHING :
2914 player->is_digging ? ACTION_DIGGING :
2915 player->is_collecting ? ACTION_COLLECTING :
2916 player->is_moving ? ACTION_MOVING :
2917 player->is_snapping ? ACTION_SNAPPING :
2918 player->is_dropping ? ACTION_DROPPING :
2919 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2921 if (player->is_waiting)
2922 move_dir = player->dir_waiting;
2924 InitPlayerGfxAnimation(player, action, move_dir);
2926 /* ----------------------------------------------------------------------- */
2927 /* draw things in the field the player is leaving, if needed */
2928 /* ----------------------------------------------------------------------- */
2930 if (player->is_moving)
2932 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2934 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2936 if (last_element == EL_DYNAMITE_ACTIVE ||
2937 last_element == EL_EM_DYNAMITE_ACTIVE ||
2938 last_element == EL_SP_DISK_RED_ACTIVE)
2939 DrawDynamite(last_jx, last_jy);
2941 DrawLevelFieldThruMask(last_jx, last_jy);
2943 else if (last_element == EL_DYNAMITE_ACTIVE ||
2944 last_element == EL_EM_DYNAMITE_ACTIVE ||
2945 last_element == EL_SP_DISK_RED_ACTIVE)
2946 DrawDynamite(last_jx, last_jy);
2948 /* !!! this is not enough to prevent flickering of players which are
2949 moving next to each others without a free tile between them -- this
2950 can only be solved by drawing all players layer by layer (first the
2951 background, then the foreground etc.) !!! => TODO */
2952 else if (!IS_PLAYER(last_jx, last_jy))
2953 DrawLevelField(last_jx, last_jy);
2956 DrawLevelField(last_jx, last_jy);
2959 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2960 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2963 if (!IN_SCR_FIELD(sx, sy))
2966 /* ----------------------------------------------------------------------- */
2967 /* draw things behind the player, if needed */
2968 /* ----------------------------------------------------------------------- */
2971 DrawLevelElement(jx, jy, Back[jx][jy]);
2972 else if (IS_ACTIVE_BOMB(element))
2973 DrawLevelElement(jx, jy, EL_EMPTY);
2976 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2978 int old_element = GfxElement[jx][jy];
2979 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2980 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2982 if (GFX_CRUMBLED(old_element))
2983 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
2985 DrawGraphic(sx, sy, old_graphic, frame);
2987 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2988 player_is_opaque = TRUE;
2992 GfxElement[jx][jy] = EL_UNDEFINED;
2994 /* make sure that pushed elements are drawn with correct frame rate */
2996 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2998 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2999 GfxFrame[jx][jy] = player->StepFrame;
3001 if (player->is_pushing && player->is_moving)
3002 GfxFrame[jx][jy] = player->StepFrame;
3005 DrawLevelField(jx, jy);
3009 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3010 /* ----------------------------------------------------------------------- */
3011 /* draw player himself */
3012 /* ----------------------------------------------------------------------- */
3014 graphic = getPlayerGraphic(player, move_dir);
3016 /* in the case of changed player action or direction, prevent the current
3017 animation frame from being restarted for identical animations */
3018 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3019 player->Frame = last_player_frame;
3021 frame = getGraphicAnimationFrame(graphic, player->Frame);
3025 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3026 sxx = player->GfxPos;
3028 syy = player->GfxPos;
3031 if (!setup.soft_scrolling && ScreenMovPos)
3034 if (player_is_opaque)
3035 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3037 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3039 if (SHIELD_ON(player))
3041 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3042 IMG_SHIELD_NORMAL_ACTIVE);
3043 int frame = getGraphicAnimationFrame(graphic, -1);
3045 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3049 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3052 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3053 sxx = player->GfxPos;
3055 syy = player->GfxPos;
3059 /* ----------------------------------------------------------------------- */
3060 /* draw things the player is pushing, if needed */
3061 /* ----------------------------------------------------------------------- */
3064 printf("::: %d, %d [%d, %d] [%d]\n",
3065 player->is_pushing, player_is_moving, player->GfxAction,
3066 player->is_moving, player_is_moving);
3070 if (player->is_pushing && player->is_moving)
3072 int px = SCREENX(jx), py = SCREENY(jy);
3073 int pxx = (TILEX - ABS(sxx)) * dx;
3074 int pyy = (TILEY - ABS(syy)) * dy;
3075 int gfx_frame = GfxFrame[jx][jy];
3081 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3083 element = Feld[next_jx][next_jy];
3084 gfx_frame = GfxFrame[next_jx][next_jy];
3087 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3090 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3091 frame = getGraphicAnimationFrame(graphic, sync_frame);
3093 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3096 /* draw background element under pushed element (like the Sokoban field) */
3098 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3100 /* this allows transparent pushing animation over non-black background */
3103 DrawLevelElement(jx, jy, Back[jx][jy]);
3105 DrawLevelElement(jx, jy, EL_EMPTY);
3107 if (Back[next_jx][next_jy])
3108 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3110 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3112 else if (Back[next_jx][next_jy])
3113 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3115 if (Back[next_jx][next_jy])
3116 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3120 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3121 jx, px, player->GfxPos, player->StepFrame,
3126 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3130 /* do not draw (EM style) pushing animation when pushing is finished */
3131 /* (two-tile animations usually do not contain start and end frame) */
3132 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3133 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3135 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3137 /* masked drawing is needed for EMC style (double) movement graphics */
3138 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3139 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3144 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3145 /* ----------------------------------------------------------------------- */
3146 /* draw player himself */
3147 /* ----------------------------------------------------------------------- */
3149 graphic = getPlayerGraphic(player, move_dir);
3151 /* in the case of changed player action or direction, prevent the current
3152 animation frame from being restarted for identical animations */
3153 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3154 player->Frame = last_player_frame;
3156 frame = getGraphicAnimationFrame(graphic, player->Frame);
3160 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3161 sxx = player->GfxPos;
3163 syy = player->GfxPos;
3166 if (!setup.soft_scrolling && ScreenMovPos)
3169 if (player_is_opaque)
3170 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3172 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3174 if (SHIELD_ON(player))
3176 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3177 IMG_SHIELD_NORMAL_ACTIVE);
3178 int frame = getGraphicAnimationFrame(graphic, -1);
3180 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3184 /* ----------------------------------------------------------------------- */
3185 /* draw things in front of player (active dynamite or dynabombs) */
3186 /* ----------------------------------------------------------------------- */
3188 if (IS_ACTIVE_BOMB(element))
3190 graphic = el2img(element);
3191 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3193 if (game.emulation == EMU_SUPAPLEX)
3194 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3196 DrawGraphicThruMask(sx, sy, graphic, frame);
3199 if (player_is_moving && last_element == EL_EXPLOSION)
3201 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3202 GfxElement[last_jx][last_jy] : EL_EMPTY);
3203 int graphic = el_act2img(element, ACTION_EXPLODING);
3204 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3205 int phase = ExplodePhase[last_jx][last_jy] - 1;
3206 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3209 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3212 /* ----------------------------------------------------------------------- */
3213 /* draw elements the player is just walking/passing through/under */
3214 /* ----------------------------------------------------------------------- */
3216 if (player_is_moving)
3218 /* handle the field the player is leaving ... */
3219 if (IS_ACCESSIBLE_INSIDE(last_element))
3220 DrawLevelField(last_jx, last_jy);
3221 else if (IS_ACCESSIBLE_UNDER(last_element))
3222 DrawLevelFieldThruMask(last_jx, last_jy);
3225 /* do not redraw accessible elements if the player is just pushing them */
3226 if (!player_is_moving || !player->is_pushing)
3228 /* ... and the field the player is entering */
3229 if (IS_ACCESSIBLE_INSIDE(element))
3230 DrawLevelField(jx, jy);
3231 else if (IS_ACCESSIBLE_UNDER(element))
3232 DrawLevelFieldThruMask(jx, jy);
3235 MarkTileDirty(sx, sy);
3238 /* ------------------------------------------------------------------------- */
3240 void WaitForEventToContinue()
3242 boolean still_wait = TRUE;
3244 /* simulate releasing mouse button over last gadget, if still pressed */
3246 HandleGadgets(-1, -1, 0);
3248 button_status = MB_RELEASED;
3264 case EVENT_BUTTONPRESS:
3265 case EVENT_KEYPRESS:
3269 case EVENT_KEYRELEASE:
3270 ClearPlayerAction();
3274 HandleOtherEvents(&event);
3278 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3285 /* don't eat all CPU time */
3290 #define MAX_REQUEST_LINES 13
3291 #define MAX_REQUEST_LINE_FONT1_LEN 7
3292 #define MAX_REQUEST_LINE_FONT2_LEN 10
3294 boolean Request(char *text, unsigned int req_state)
3296 int mx, my, ty, result = -1;
3297 unsigned int old_door_state;
3298 int last_game_status = game_status; /* save current game status */
3299 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3300 int font_nr = FONT_TEXT_2;
3301 int max_word_len = 0;
3305 ShowEnvelopeDoor(text);
3308 for (text_ptr = text; *text_ptr; text_ptr++)
3310 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3312 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3314 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3316 font_nr = FONT_TEXT_1;
3318 font_nr = FONT_LEVEL_NUMBER;
3325 if (game_status == GAME_MODE_PLAYING)
3327 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3328 BlitScreenToBitmap_EM(backbuffer);
3329 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3330 BlitScreenToBitmap_SP(backbuffer);
3333 /* disable deactivated drawing when quick-loading level tape recording */
3334 if (tape.playing && tape.deactivate_display)
3335 TapeDeactivateDisplayOff(TRUE);
3337 SetMouseCursor(CURSOR_DEFAULT);
3339 #if defined(NETWORK_AVALIABLE)
3340 /* pause network game while waiting for request to answer */
3341 if (options.network &&
3342 game_status == GAME_MODE_PLAYING &&
3343 req_state & REQUEST_WAIT_FOR_INPUT)
3344 SendToServer_PausePlaying();
3347 old_door_state = GetDoorState();
3349 /* simulate releasing mouse button over last gadget, if still pressed */
3351 HandleGadgets(-1, -1, 0);
3355 if (old_door_state & DOOR_OPEN_1)
3357 CloseDoor(DOOR_CLOSE_1);
3359 /* save old door content */
3360 BlitBitmap(bitmap_db_door, bitmap_db_door,
3361 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3362 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3366 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3369 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3371 /* clear door drawing field */
3372 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3374 /* force DOOR font inside door area */
3375 game_status = GAME_MODE_PSEUDO_DOOR;
3377 /* write text for request */
3378 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
3380 char text_line[max_request_line_len + 1];
3386 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3389 if (!tc || tc == ' ')
3400 strncpy(text_line, text, tl);
3403 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3404 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3405 text_line, font_nr);
3407 text += tl + (tc == ' ' ? 1 : 0);
3410 game_status = last_game_status; /* restore current game status */
3412 if (req_state & REQ_ASK)
3414 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3415 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3417 else if (req_state & REQ_CONFIRM)
3419 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3421 else if (req_state & REQ_PLAYER)
3423 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3424 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3425 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3426 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3429 /* copy request gadgets to door backbuffer */
3430 BlitBitmap(drawto, bitmap_db_door,
3431 DX, DY, DXSIZE, DYSIZE,
3432 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3434 OpenDoor(DOOR_OPEN_1);
3436 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3438 if (game_status == GAME_MODE_PLAYING)
3440 SetPanelBackground();
3441 SetDrawBackgroundMask(REDRAW_DOOR_1);
3445 SetDrawBackgroundMask(REDRAW_FIELD);
3451 if (game_status != GAME_MODE_MAIN)
3454 button_status = MB_RELEASED;
3456 request_gadget_id = -1;
3458 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3470 case EVENT_BUTTONPRESS:
3471 case EVENT_BUTTONRELEASE:
3472 case EVENT_MOTIONNOTIFY:
3474 if (event.type == EVENT_MOTIONNOTIFY)
3476 if (!PointerInWindow(window))
3477 continue; /* window and pointer are on different screens */
3482 motion_status = TRUE;
3483 mx = ((MotionEvent *) &event)->x;
3484 my = ((MotionEvent *) &event)->y;
3488 motion_status = FALSE;
3489 mx = ((ButtonEvent *) &event)->x;
3490 my = ((ButtonEvent *) &event)->y;
3491 if (event.type == EVENT_BUTTONPRESS)
3492 button_status = ((ButtonEvent *) &event)->button;
3494 button_status = MB_RELEASED;
3497 /* this sets 'request_gadget_id' */
3498 HandleGadgets(mx, my, button_status);
3500 switch (request_gadget_id)
3502 case TOOL_CTRL_ID_YES:
3505 case TOOL_CTRL_ID_NO:
3508 case TOOL_CTRL_ID_CONFIRM:
3509 result = TRUE | FALSE;
3512 case TOOL_CTRL_ID_PLAYER_1:
3515 case TOOL_CTRL_ID_PLAYER_2:
3518 case TOOL_CTRL_ID_PLAYER_3:
3521 case TOOL_CTRL_ID_PLAYER_4:
3532 case EVENT_KEYPRESS:
3533 switch (GetEventKey((KeyEvent *)&event, TRUE))
3536 if (req_state & REQ_CONFIRM)
3552 if (req_state & REQ_PLAYER)
3556 case EVENT_KEYRELEASE:
3557 ClearPlayerAction();
3561 HandleOtherEvents(&event);
3565 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3567 int joy = AnyJoystick();
3569 if (joy & JOY_BUTTON_1)
3571 else if (joy & JOY_BUTTON_2)
3577 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3579 HandleGameActions();
3585 if (!PendingEvent()) /* delay only if no pending events */
3596 if (!PendingEvent()) /* delay only if no pending events */
3599 /* don't eat all CPU time */
3606 if (game_status != GAME_MODE_MAIN)
3611 if (!(req_state & REQ_STAY_OPEN))
3613 CloseDoor(DOOR_CLOSE_1);
3615 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3616 (req_state & REQ_REOPEN))
3617 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3622 if (game_status == GAME_MODE_PLAYING)
3624 SetPanelBackground();
3625 SetDrawBackgroundMask(REDRAW_DOOR_1);
3629 SetDrawBackgroundMask(REDRAW_FIELD);
3632 #if defined(NETWORK_AVALIABLE)
3633 /* continue network game after request */
3634 if (options.network &&
3635 game_status == GAME_MODE_PLAYING &&
3636 req_state & REQUEST_WAIT_FOR_INPUT)
3637 SendToServer_ContinuePlaying();
3640 /* restore deactivated drawing when quick-loading level tape recording */
3641 if (tape.playing && tape.deactivate_display)
3642 TapeDeactivateDisplayOn();
3647 unsigned int OpenDoor(unsigned int door_state)
3649 if (door_state & DOOR_COPY_BACK)
3651 if (door_state & DOOR_OPEN_1)
3652 BlitBitmap(bitmap_db_door, bitmap_db_door,
3653 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3654 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3656 if (door_state & DOOR_OPEN_2)
3657 BlitBitmap(bitmap_db_door, bitmap_db_door,
3658 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3659 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3661 door_state &= ~DOOR_COPY_BACK;
3664 return MoveDoor(door_state);
3667 unsigned int CloseDoor(unsigned int door_state)
3669 unsigned int old_door_state = GetDoorState();
3671 if (!(door_state & DOOR_NO_COPY_BACK))
3673 if (old_door_state & DOOR_OPEN_1)
3674 BlitBitmap(backbuffer, bitmap_db_door,
3675 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3677 if (old_door_state & DOOR_OPEN_2)
3678 BlitBitmap(backbuffer, bitmap_db_door,
3679 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3681 door_state &= ~DOOR_NO_COPY_BACK;
3684 return MoveDoor(door_state);
3687 unsigned int GetDoorState()
3689 return MoveDoor(DOOR_GET_STATE);
3692 unsigned int SetDoorState(unsigned int door_state)
3694 return MoveDoor(door_state | DOOR_SET_STATE);
3697 unsigned int MoveDoor(unsigned int door_state)
3699 static int door1 = DOOR_OPEN_1;
3700 static int door2 = DOOR_CLOSE_2;
3701 unsigned long door_delay = 0;
3702 unsigned long door_delay_value;
3705 if (door_1.width < 0 || door_1.width > DXSIZE)
3706 door_1.width = DXSIZE;
3707 if (door_1.height < 0 || door_1.height > DYSIZE)
3708 door_1.height = DYSIZE;
3709 if (door_2.width < 0 || door_2.width > VXSIZE)
3710 door_2.width = VXSIZE;
3711 if (door_2.height < 0 || door_2.height > VYSIZE)
3712 door_2.height = VYSIZE;
3714 if (door_state == DOOR_GET_STATE)
3715 return (door1 | door2);
3717 if (door_state & DOOR_SET_STATE)
3719 if (door_state & DOOR_ACTION_1)
3720 door1 = door_state & DOOR_ACTION_1;
3721 if (door_state & DOOR_ACTION_2)
3722 door2 = door_state & DOOR_ACTION_2;
3724 return (door1 | door2);
3727 if (!(door_state & DOOR_FORCE_REDRAW))
3729 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3730 door_state &= ~DOOR_OPEN_1;
3731 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3732 door_state &= ~DOOR_CLOSE_1;
3733 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3734 door_state &= ~DOOR_OPEN_2;
3735 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3736 door_state &= ~DOOR_CLOSE_2;
3739 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3742 if (setup.quick_doors)
3744 stepsize = 20; /* must be chosen to always draw last frame */
3745 door_delay_value = 0;
3748 if (global.autoplay_leveldir)
3750 door_state |= DOOR_NO_DELAY;
3751 door_state &= ~DOOR_CLOSE_ALL;
3755 if (game_status == GAME_MODE_EDITOR)
3756 door_state |= DOOR_NO_DELAY;
3759 if (door_state & DOOR_ACTION)
3761 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3762 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3763 boolean door_1_done = (!handle_door_1);
3764 boolean door_2_done = (!handle_door_2);
3765 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3766 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3767 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3768 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3769 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3770 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3771 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3772 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3773 int door_skip = max_door_size - door_size;
3774 int end = door_size;
3775 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3778 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3780 /* opening door sound has priority over simultaneously closing door */
3781 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3782 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3783 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3784 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3787 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3790 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3791 GC gc = bitmap->stored_clip_gc;
3793 if (door_state & DOOR_ACTION_1)
3795 int a = MIN(x * door_1.step_offset, end);
3796 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3797 int i = p + door_skip;
3799 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3801 BlitBitmap(bitmap_db_door, drawto,
3802 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3803 DXSIZE, DYSIZE, DX, DY);
3807 BlitBitmap(bitmap_db_door, drawto,
3808 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3809 DXSIZE, DYSIZE - p / 2, DX, DY);
3811 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3814 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3816 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3817 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3818 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3819 int dst2_x = DX, dst2_y = DY;
3820 int width = i, height = DYSIZE;
3822 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3823 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3826 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3827 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3830 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3832 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3833 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3834 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3835 int dst2_x = DX, dst2_y = DY;
3836 int width = DXSIZE, height = i;
3838 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3839 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3842 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3843 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3846 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3848 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3850 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3851 BlitBitmapMasked(bitmap, drawto,
3852 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3853 DX + DXSIZE - i, DY + j);
3854 BlitBitmapMasked(bitmap, drawto,
3855 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3856 DX + DXSIZE - i, DY + 140 + j);
3857 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3858 DY - (DOOR_GFX_PAGEY1 + j));
3859 BlitBitmapMasked(bitmap, drawto,
3860 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3862 BlitBitmapMasked(bitmap, drawto,
3863 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3866 BlitBitmapMasked(bitmap, drawto,
3867 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3869 BlitBitmapMasked(bitmap, drawto,
3870 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3872 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3873 BlitBitmapMasked(bitmap, drawto,
3874 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3875 DX + DXSIZE - i, DY + 77 + j);
3876 BlitBitmapMasked(bitmap, drawto,
3877 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3878 DX + DXSIZE - i, DY + 203 + j);
3881 redraw_mask |= REDRAW_DOOR_1;
3882 door_1_done = (a == end);
3885 if (door_state & DOOR_ACTION_2)
3887 int a = MIN(x * door_2.step_offset, door_size);
3888 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3889 int i = p + door_skip;
3891 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3893 BlitBitmap(bitmap_db_door, drawto,
3894 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3895 VXSIZE, VYSIZE, VX, VY);
3897 else if (x <= VYSIZE)
3899 BlitBitmap(bitmap_db_door, drawto,
3900 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3901 VXSIZE, VYSIZE - p / 2, VX, VY);
3903 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3906 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3908 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3909 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3910 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3911 int dst2_x = VX, dst2_y = VY;
3912 int width = i, height = VYSIZE;
3914 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3915 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3918 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3919 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3922 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3924 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3925 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3926 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3927 int dst2_x = VX, dst2_y = VY;
3928 int width = VXSIZE, height = i;
3930 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3931 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3934 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3935 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3938 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3940 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3942 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3943 BlitBitmapMasked(bitmap, drawto,
3944 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3945 VX + VXSIZE - i, VY + j);
3946 SetClipOrigin(bitmap, gc,
3947 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3948 BlitBitmapMasked(bitmap, drawto,
3949 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3952 BlitBitmapMasked(bitmap, drawto,
3953 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3954 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3955 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3956 BlitBitmapMasked(bitmap, drawto,
3957 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3959 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3962 redraw_mask |= REDRAW_DOOR_2;
3963 door_2_done = (a == VXSIZE);
3966 if (!(door_state & DOOR_NO_DELAY))
3970 if (game_status == GAME_MODE_MAIN)
3973 WaitUntilDelayReached(&door_delay, door_delay_value);
3978 if (door_state & DOOR_ACTION_1)
3979 door1 = door_state & DOOR_ACTION_1;
3980 if (door_state & DOOR_ACTION_2)
3981 door2 = door_state & DOOR_ACTION_2;
3983 return (door1 | door2);
3986 void DrawSpecialEditorDoor()
3988 /* draw bigger toolbox window */
3989 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3990 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3992 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3993 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3996 redraw_mask |= REDRAW_ALL;
3999 void UndrawSpecialEditorDoor()
4001 /* draw normal tape recorder window */
4002 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4003 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4006 redraw_mask |= REDRAW_ALL;
4010 /* ---------- new tool button stuff ---------------------------------------- */
4012 /* graphic position values for tool buttons */
4013 #define TOOL_BUTTON_YES_XPOS 2
4014 #define TOOL_BUTTON_YES_YPOS 250
4015 #define TOOL_BUTTON_YES_GFX_YPOS 0
4016 #define TOOL_BUTTON_YES_XSIZE 46
4017 #define TOOL_BUTTON_YES_YSIZE 28
4018 #define TOOL_BUTTON_NO_XPOS 52
4019 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
4020 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
4021 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
4022 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
4023 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
4024 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
4025 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
4026 #define TOOL_BUTTON_CONFIRM_XSIZE 96
4027 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
4028 #define TOOL_BUTTON_PLAYER_XSIZE 30
4029 #define TOOL_BUTTON_PLAYER_YSIZE 30
4030 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
4031 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
4032 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4033 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4034 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4035 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4036 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4037 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4038 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4039 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4040 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
4041 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4042 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4043 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4044 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4045 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4046 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4047 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4048 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
4049 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4058 } toolbutton_info[NUM_TOOL_BUTTONS] =
4061 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
4062 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
4063 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
4068 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
4069 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
4070 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
4075 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
4076 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
4077 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
4078 TOOL_CTRL_ID_CONFIRM,
4082 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4083 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
4084 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4085 TOOL_CTRL_ID_PLAYER_1,
4089 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4090 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
4091 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4092 TOOL_CTRL_ID_PLAYER_2,
4096 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4097 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
4098 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4099 TOOL_CTRL_ID_PLAYER_3,
4103 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4104 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
4105 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
4106 TOOL_CTRL_ID_PLAYER_4,
4111 void CreateToolButtons()
4115 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4117 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4118 Bitmap *deco_bitmap = None;
4119 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4120 struct GadgetInfo *gi;
4121 unsigned long event_mask;
4122 int gd_xoffset, gd_yoffset;
4123 int gd_x1, gd_x2, gd_y;
4126 event_mask = GD_EVENT_RELEASED;
4128 gd_xoffset = toolbutton_info[i].xpos;
4129 gd_yoffset = toolbutton_info[i].ypos;
4130 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4131 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4132 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4134 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4136 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4138 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4139 &deco_bitmap, &deco_x, &deco_y);
4140 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4141 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4144 gi = CreateGadget(GDI_CUSTOM_ID, id,
4145 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4146 GDI_X, DX + toolbutton_info[i].x,
4147 GDI_Y, DY + toolbutton_info[i].y,
4148 GDI_WIDTH, toolbutton_info[i].width,
4149 GDI_HEIGHT, toolbutton_info[i].height,
4150 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4151 GDI_STATE, GD_BUTTON_UNPRESSED,
4152 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4153 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4154 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4155 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4156 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4157 GDI_DECORATION_SHIFTING, 1, 1,
4158 GDI_DIRECT_DRAW, FALSE,
4159 GDI_EVENT_MASK, event_mask,
4160 GDI_CALLBACK_ACTION, HandleToolButtons,
4164 Error(ERR_EXIT, "cannot create gadget");
4166 tool_gadget[id] = gi;
4170 void FreeToolButtons()
4174 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4175 FreeGadget(tool_gadget[i]);
4178 static void UnmapToolButtons()
4182 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4183 UnmapGadget(tool_gadget[i]);
4186 static void HandleToolButtons(struct GadgetInfo *gi)
4188 request_gadget_id = gi->custom_id;
4191 static struct Mapping_EM_to_RND_object
4194 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4195 boolean is_backside; /* backside of moving element */
4201 em_object_mapping_list[] =
4204 Xblank, TRUE, FALSE,
4208 Yacid_splash_eB, FALSE, FALSE,
4209 EL_ACID_SPLASH_RIGHT, -1, -1
4212 Yacid_splash_wB, FALSE, FALSE,
4213 EL_ACID_SPLASH_LEFT, -1, -1
4216 #ifdef EM_ENGINE_BAD_ROLL
4218 Xstone_force_e, FALSE, FALSE,
4219 EL_ROCK, -1, MV_BIT_RIGHT
4222 Xstone_force_w, FALSE, FALSE,
4223 EL_ROCK, -1, MV_BIT_LEFT
4226 Xnut_force_e, FALSE, FALSE,
4227 EL_NUT, -1, MV_BIT_RIGHT
4230 Xnut_force_w, FALSE, FALSE,
4231 EL_NUT, -1, MV_BIT_LEFT
4234 Xspring_force_e, FALSE, FALSE,
4235 EL_SPRING, -1, MV_BIT_RIGHT
4238 Xspring_force_w, FALSE, FALSE,
4239 EL_SPRING, -1, MV_BIT_LEFT
4242 Xemerald_force_e, FALSE, FALSE,
4243 EL_EMERALD, -1, MV_BIT_RIGHT
4246 Xemerald_force_w, FALSE, FALSE,
4247 EL_EMERALD, -1, MV_BIT_LEFT
4250 Xdiamond_force_e, FALSE, FALSE,
4251 EL_DIAMOND, -1, MV_BIT_RIGHT
4254 Xdiamond_force_w, FALSE, FALSE,
4255 EL_DIAMOND, -1, MV_BIT_LEFT
4258 Xbomb_force_e, FALSE, FALSE,
4259 EL_BOMB, -1, MV_BIT_RIGHT
4262 Xbomb_force_w, FALSE, FALSE,
4263 EL_BOMB, -1, MV_BIT_LEFT
4265 #endif /* EM_ENGINE_BAD_ROLL */
4268 Xstone, TRUE, FALSE,
4272 Xstone_pause, FALSE, FALSE,
4276 Xstone_fall, FALSE, FALSE,
4280 Ystone_s, FALSE, FALSE,
4281 EL_ROCK, ACTION_FALLING, -1
4284 Ystone_sB, FALSE, TRUE,
4285 EL_ROCK, ACTION_FALLING, -1
4288 Ystone_e, FALSE, FALSE,
4289 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4292 Ystone_eB, FALSE, TRUE,
4293 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4296 Ystone_w, FALSE, FALSE,
4297 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4300 Ystone_wB, FALSE, TRUE,
4301 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4308 Xnut_pause, FALSE, FALSE,
4312 Xnut_fall, FALSE, FALSE,
4316 Ynut_s, FALSE, FALSE,
4317 EL_NUT, ACTION_FALLING, -1
4320 Ynut_sB, FALSE, TRUE,
4321 EL_NUT, ACTION_FALLING, -1
4324 Ynut_e, FALSE, FALSE,
4325 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4328 Ynut_eB, FALSE, TRUE,
4329 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4332 Ynut_w, FALSE, FALSE,
4333 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4336 Ynut_wB, FALSE, TRUE,
4337 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4340 Xbug_n, TRUE, FALSE,
4344 Xbug_e, TRUE, FALSE,
4345 EL_BUG_RIGHT, -1, -1
4348 Xbug_s, TRUE, FALSE,
4352 Xbug_w, TRUE, FALSE,
4356 Xbug_gon, FALSE, FALSE,
4360 Xbug_goe, FALSE, FALSE,
4361 EL_BUG_RIGHT, -1, -1
4364 Xbug_gos, FALSE, FALSE,
4368 Xbug_gow, FALSE, FALSE,
4372 Ybug_n, FALSE, FALSE,
4373 EL_BUG, ACTION_MOVING, MV_BIT_UP
4376 Ybug_nB, FALSE, TRUE,
4377 EL_BUG, ACTION_MOVING, MV_BIT_UP
4380 Ybug_e, FALSE, FALSE,
4381 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4384 Ybug_eB, FALSE, TRUE,
4385 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4388 Ybug_s, FALSE, FALSE,
4389 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4392 Ybug_sB, FALSE, TRUE,
4393 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4396 Ybug_w, FALSE, FALSE,
4397 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4400 Ybug_wB, FALSE, TRUE,
4401 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4404 Ybug_w_n, FALSE, FALSE,
4405 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4408 Ybug_n_e, FALSE, FALSE,
4409 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4412 Ybug_e_s, FALSE, FALSE,
4413 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4416 Ybug_s_w, FALSE, FALSE,
4417 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4420 Ybug_e_n, FALSE, FALSE,
4421 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4424 Ybug_s_e, FALSE, FALSE,
4425 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4428 Ybug_w_s, FALSE, FALSE,
4429 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4432 Ybug_n_w, FALSE, FALSE,
4433 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4436 Ybug_stone, FALSE, FALSE,
4437 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4440 Ybug_spring, FALSE, FALSE,
4441 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4444 Xtank_n, TRUE, FALSE,
4445 EL_SPACESHIP_UP, -1, -1
4448 Xtank_e, TRUE, FALSE,
4449 EL_SPACESHIP_RIGHT, -1, -1
4452 Xtank_s, TRUE, FALSE,
4453 EL_SPACESHIP_DOWN, -1, -1
4456 Xtank_w, TRUE, FALSE,
4457 EL_SPACESHIP_LEFT, -1, -1
4460 Xtank_gon, FALSE, FALSE,
4461 EL_SPACESHIP_UP, -1, -1
4464 Xtank_goe, FALSE, FALSE,
4465 EL_SPACESHIP_RIGHT, -1, -1
4468 Xtank_gos, FALSE, FALSE,
4469 EL_SPACESHIP_DOWN, -1, -1
4472 Xtank_gow, FALSE, FALSE,
4473 EL_SPACESHIP_LEFT, -1, -1
4476 Ytank_n, FALSE, FALSE,
4477 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4480 Ytank_nB, FALSE, TRUE,
4481 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4484 Ytank_e, FALSE, FALSE,
4485 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4488 Ytank_eB, FALSE, TRUE,
4489 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4492 Ytank_s, FALSE, FALSE,
4493 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4496 Ytank_sB, FALSE, TRUE,
4497 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4500 Ytank_w, FALSE, FALSE,
4501 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4504 Ytank_wB, FALSE, TRUE,
4505 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4508 Ytank_w_n, FALSE, FALSE,
4509 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4512 Ytank_n_e, FALSE, FALSE,
4513 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4516 Ytank_e_s, FALSE, FALSE,
4517 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4520 Ytank_s_w, FALSE, FALSE,
4521 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4524 Ytank_e_n, FALSE, FALSE,
4525 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4528 Ytank_s_e, FALSE, FALSE,
4529 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4532 Ytank_w_s, FALSE, FALSE,
4533 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4536 Ytank_n_w, FALSE, FALSE,
4537 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4540 Ytank_stone, FALSE, FALSE,
4541 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4544 Ytank_spring, FALSE, FALSE,
4545 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4548 Xandroid, TRUE, FALSE,
4549 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4552 Xandroid_1_n, FALSE, FALSE,
4553 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4556 Xandroid_2_n, FALSE, FALSE,
4557 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4560 Xandroid_1_e, FALSE, FALSE,
4561 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4564 Xandroid_2_e, FALSE, FALSE,
4565 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4568 Xandroid_1_w, FALSE, FALSE,
4569 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4572 Xandroid_2_w, FALSE, FALSE,
4573 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4576 Xandroid_1_s, FALSE, FALSE,
4577 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4580 Xandroid_2_s, FALSE, FALSE,
4581 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4584 Yandroid_n, FALSE, FALSE,
4585 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4588 Yandroid_nB, FALSE, TRUE,
4589 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4592 Yandroid_ne, FALSE, FALSE,
4593 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4596 Yandroid_neB, FALSE, TRUE,
4597 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4600 Yandroid_e, FALSE, FALSE,
4601 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4604 Yandroid_eB, FALSE, TRUE,
4605 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4608 Yandroid_se, FALSE, FALSE,
4609 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4612 Yandroid_seB, FALSE, TRUE,
4613 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4616 Yandroid_s, FALSE, FALSE,
4617 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4620 Yandroid_sB, FALSE, TRUE,
4621 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4624 Yandroid_sw, FALSE, FALSE,
4625 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4628 Yandroid_swB, FALSE, TRUE,
4629 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4632 Yandroid_w, FALSE, FALSE,
4633 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4636 Yandroid_wB, FALSE, TRUE,
4637 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4640 Yandroid_nw, FALSE, FALSE,
4641 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4644 Yandroid_nwB, FALSE, TRUE,
4645 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4648 Xspring, TRUE, FALSE,
4652 Xspring_pause, FALSE, FALSE,
4656 Xspring_e, FALSE, FALSE,
4660 Xspring_w, FALSE, FALSE,
4664 Xspring_fall, FALSE, FALSE,
4668 Yspring_s, FALSE, FALSE,
4669 EL_SPRING, ACTION_FALLING, -1
4672 Yspring_sB, FALSE, TRUE,
4673 EL_SPRING, ACTION_FALLING, -1
4676 Yspring_e, FALSE, FALSE,
4677 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4680 Yspring_eB, FALSE, TRUE,
4681 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4684 Yspring_w, FALSE, FALSE,
4685 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4688 Yspring_wB, FALSE, TRUE,
4689 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4692 Yspring_kill_e, FALSE, FALSE,
4693 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4696 Yspring_kill_eB, FALSE, TRUE,
4697 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4700 Yspring_kill_w, FALSE, FALSE,
4701 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4704 Yspring_kill_wB, FALSE, TRUE,
4705 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4708 Xeater_n, TRUE, FALSE,
4709 EL_YAMYAM_UP, -1, -1
4712 Xeater_e, TRUE, FALSE,
4713 EL_YAMYAM_RIGHT, -1, -1
4716 Xeater_w, TRUE, FALSE,
4717 EL_YAMYAM_LEFT, -1, -1
4720 Xeater_s, TRUE, FALSE,
4721 EL_YAMYAM_DOWN, -1, -1
4724 Yeater_n, FALSE, FALSE,
4725 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4728 Yeater_nB, FALSE, TRUE,
4729 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4732 Yeater_e, FALSE, FALSE,
4733 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4736 Yeater_eB, FALSE, TRUE,
4737 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4740 Yeater_s, FALSE, FALSE,
4741 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4744 Yeater_sB, FALSE, TRUE,
4745 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4748 Yeater_w, FALSE, FALSE,
4749 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4752 Yeater_wB, FALSE, TRUE,
4753 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4756 Yeater_stone, FALSE, FALSE,
4757 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4760 Yeater_spring, FALSE, FALSE,
4761 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4764 Xalien, TRUE, FALSE,
4768 Xalien_pause, FALSE, FALSE,
4772 Yalien_n, FALSE, FALSE,
4773 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4776 Yalien_nB, FALSE, TRUE,
4777 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4780 Yalien_e, FALSE, FALSE,
4781 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4784 Yalien_eB, FALSE, TRUE,
4785 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4788 Yalien_s, FALSE, FALSE,
4789 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4792 Yalien_sB, FALSE, TRUE,
4793 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4796 Yalien_w, FALSE, FALSE,
4797 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4800 Yalien_wB, FALSE, TRUE,
4801 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4804 Yalien_stone, FALSE, FALSE,
4805 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4808 Yalien_spring, FALSE, FALSE,
4809 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4812 Xemerald, TRUE, FALSE,
4816 Xemerald_pause, FALSE, FALSE,
4820 Xemerald_fall, FALSE, FALSE,
4824 Xemerald_shine, FALSE, FALSE,
4825 EL_EMERALD, ACTION_TWINKLING, -1
4828 Yemerald_s, FALSE, FALSE,
4829 EL_EMERALD, ACTION_FALLING, -1
4832 Yemerald_sB, FALSE, TRUE,
4833 EL_EMERALD, ACTION_FALLING, -1
4836 Yemerald_e, FALSE, FALSE,
4837 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4840 Yemerald_eB, FALSE, TRUE,
4841 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4844 Yemerald_w, FALSE, FALSE,
4845 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4848 Yemerald_wB, FALSE, TRUE,
4849 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4852 Yemerald_eat, FALSE, FALSE,
4853 EL_EMERALD, ACTION_COLLECTING, -1
4856 Yemerald_stone, FALSE, FALSE,
4857 EL_NUT, ACTION_BREAKING, -1
4860 Xdiamond, TRUE, FALSE,
4864 Xdiamond_pause, FALSE, FALSE,
4868 Xdiamond_fall, FALSE, FALSE,
4872 Xdiamond_shine, FALSE, FALSE,
4873 EL_DIAMOND, ACTION_TWINKLING, -1
4876 Ydiamond_s, FALSE, FALSE,
4877 EL_DIAMOND, ACTION_FALLING, -1
4880 Ydiamond_sB, FALSE, TRUE,
4881 EL_DIAMOND, ACTION_FALLING, -1
4884 Ydiamond_e, FALSE, FALSE,
4885 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4888 Ydiamond_eB, FALSE, TRUE,
4889 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4892 Ydiamond_w, FALSE, FALSE,
4893 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4896 Ydiamond_wB, FALSE, TRUE,
4897 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4900 Ydiamond_eat, FALSE, FALSE,
4901 EL_DIAMOND, ACTION_COLLECTING, -1
4904 Ydiamond_stone, FALSE, FALSE,
4905 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4908 Xdrip_fall, TRUE, FALSE,
4909 EL_AMOEBA_DROP, -1, -1
4912 Xdrip_stretch, FALSE, FALSE,
4913 EL_AMOEBA_DROP, ACTION_FALLING, -1
4916 Xdrip_stretchB, FALSE, TRUE,
4917 EL_AMOEBA_DROP, ACTION_FALLING, -1
4920 Xdrip_eat, FALSE, FALSE,
4921 EL_AMOEBA_DROP, ACTION_GROWING, -1
4924 Ydrip_s1, FALSE, FALSE,
4925 EL_AMOEBA_DROP, ACTION_FALLING, -1
4928 Ydrip_s1B, FALSE, TRUE,
4929 EL_AMOEBA_DROP, ACTION_FALLING, -1
4932 Ydrip_s2, FALSE, FALSE,
4933 EL_AMOEBA_DROP, ACTION_FALLING, -1
4936 Ydrip_s2B, FALSE, TRUE,
4937 EL_AMOEBA_DROP, ACTION_FALLING, -1
4944 Xbomb_pause, FALSE, FALSE,
4948 Xbomb_fall, FALSE, FALSE,
4952 Ybomb_s, FALSE, FALSE,
4953 EL_BOMB, ACTION_FALLING, -1
4956 Ybomb_sB, FALSE, TRUE,
4957 EL_BOMB, ACTION_FALLING, -1
4960 Ybomb_e, FALSE, FALSE,
4961 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4964 Ybomb_eB, FALSE, TRUE,
4965 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4968 Ybomb_w, FALSE, FALSE,
4969 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4972 Ybomb_wB, FALSE, TRUE,
4973 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4976 Ybomb_eat, FALSE, FALSE,
4977 EL_BOMB, ACTION_ACTIVATING, -1
4980 Xballoon, TRUE, FALSE,
4984 Yballoon_n, FALSE, FALSE,
4985 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4988 Yballoon_nB, FALSE, TRUE,
4989 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4992 Yballoon_e, FALSE, FALSE,
4993 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4996 Yballoon_eB, FALSE, TRUE,
4997 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5000 Yballoon_s, FALSE, FALSE,
5001 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5004 Yballoon_sB, FALSE, TRUE,
5005 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5008 Yballoon_w, FALSE, FALSE,
5009 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5012 Yballoon_wB, FALSE, TRUE,
5013 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5016 Xgrass, TRUE, FALSE,
5017 EL_EMC_GRASS, -1, -1
5020 Ygrass_nB, FALSE, FALSE,
5021 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5024 Ygrass_eB, FALSE, FALSE,
5025 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5028 Ygrass_sB, FALSE, FALSE,
5029 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5032 Ygrass_wB, FALSE, FALSE,
5033 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5040 Ydirt_nB, FALSE, FALSE,
5041 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5044 Ydirt_eB, FALSE, FALSE,
5045 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5048 Ydirt_sB, FALSE, FALSE,
5049 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5052 Ydirt_wB, FALSE, FALSE,
5053 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5056 Xacid_ne, TRUE, FALSE,
5057 EL_ACID_POOL_TOPRIGHT, -1, -1
5060 Xacid_se, TRUE, FALSE,
5061 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5064 Xacid_s, TRUE, FALSE,
5065 EL_ACID_POOL_BOTTOM, -1, -1
5068 Xacid_sw, TRUE, FALSE,
5069 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5072 Xacid_nw, TRUE, FALSE,
5073 EL_ACID_POOL_TOPLEFT, -1, -1
5076 Xacid_1, TRUE, FALSE,
5080 Xacid_2, FALSE, FALSE,
5084 Xacid_3, FALSE, FALSE,
5088 Xacid_4, FALSE, FALSE,
5092 Xacid_5, FALSE, FALSE,
5096 Xacid_6, FALSE, FALSE,
5100 Xacid_7, FALSE, FALSE,
5104 Xacid_8, FALSE, FALSE,
5108 Xball_1, TRUE, FALSE,
5109 EL_EMC_MAGIC_BALL, -1, -1
5112 Xball_1B, FALSE, FALSE,
5113 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5116 Xball_2, FALSE, FALSE,
5117 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5120 Xball_2B, FALSE, FALSE,
5121 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5124 Yball_eat, FALSE, FALSE,
5125 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5128 Ykey_1_eat, FALSE, FALSE,
5129 EL_EM_KEY_1, ACTION_COLLECTING, -1
5132 Ykey_2_eat, FALSE, FALSE,
5133 EL_EM_KEY_2, ACTION_COLLECTING, -1
5136 Ykey_3_eat, FALSE, FALSE,
5137 EL_EM_KEY_3, ACTION_COLLECTING, -1
5140 Ykey_4_eat, FALSE, FALSE,
5141 EL_EM_KEY_4, ACTION_COLLECTING, -1
5144 Ykey_5_eat, FALSE, FALSE,
5145 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5148 Ykey_6_eat, FALSE, FALSE,
5149 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5152 Ykey_7_eat, FALSE, FALSE,
5153 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5156 Ykey_8_eat, FALSE, FALSE,
5157 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5160 Ylenses_eat, FALSE, FALSE,
5161 EL_EMC_LENSES, ACTION_COLLECTING, -1
5164 Ymagnify_eat, FALSE, FALSE,
5165 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5168 Ygrass_eat, FALSE, FALSE,
5169 EL_EMC_GRASS, ACTION_SNAPPING, -1
5172 Ydirt_eat, FALSE, FALSE,
5173 EL_SAND, ACTION_SNAPPING, -1
5176 Xgrow_ns, TRUE, FALSE,
5177 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5180 Ygrow_ns_eat, FALSE, FALSE,
5181 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5184 Xgrow_ew, TRUE, FALSE,
5185 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5188 Ygrow_ew_eat, FALSE, FALSE,
5189 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5192 Xwonderwall, TRUE, FALSE,
5193 EL_MAGIC_WALL, -1, -1
5196 XwonderwallB, FALSE, FALSE,
5197 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5200 Xamoeba_1, TRUE, FALSE,
5201 EL_AMOEBA_DRY, ACTION_OTHER, -1
5204 Xamoeba_2, FALSE, FALSE,
5205 EL_AMOEBA_DRY, ACTION_OTHER, -1
5208 Xamoeba_3, FALSE, FALSE,
5209 EL_AMOEBA_DRY, ACTION_OTHER, -1
5212 Xamoeba_4, FALSE, FALSE,
5213 EL_AMOEBA_DRY, ACTION_OTHER, -1
5216 Xamoeba_5, TRUE, FALSE,
5217 EL_AMOEBA_WET, ACTION_OTHER, -1
5220 Xamoeba_6, FALSE, FALSE,
5221 EL_AMOEBA_WET, ACTION_OTHER, -1
5224 Xamoeba_7, FALSE, FALSE,
5225 EL_AMOEBA_WET, ACTION_OTHER, -1
5228 Xamoeba_8, FALSE, FALSE,
5229 EL_AMOEBA_WET, ACTION_OTHER, -1
5232 Xdoor_1, TRUE, FALSE,
5233 EL_EM_GATE_1, -1, -1
5236 Xdoor_2, TRUE, FALSE,
5237 EL_EM_GATE_2, -1, -1
5240 Xdoor_3, TRUE, FALSE,
5241 EL_EM_GATE_3, -1, -1
5244 Xdoor_4, TRUE, FALSE,
5245 EL_EM_GATE_4, -1, -1
5248 Xdoor_5, TRUE, FALSE,
5249 EL_EMC_GATE_5, -1, -1
5252 Xdoor_6, TRUE, FALSE,
5253 EL_EMC_GATE_6, -1, -1
5256 Xdoor_7, TRUE, FALSE,
5257 EL_EMC_GATE_7, -1, -1
5260 Xdoor_8, TRUE, FALSE,
5261 EL_EMC_GATE_8, -1, -1
5264 Xkey_1, TRUE, FALSE,
5268 Xkey_2, TRUE, FALSE,
5272 Xkey_3, TRUE, FALSE,
5276 Xkey_4, TRUE, FALSE,
5280 Xkey_5, TRUE, FALSE,
5281 EL_EMC_KEY_5, -1, -1
5284 Xkey_6, TRUE, FALSE,
5285 EL_EMC_KEY_6, -1, -1
5288 Xkey_7, TRUE, FALSE,
5289 EL_EMC_KEY_7, -1, -1
5292 Xkey_8, TRUE, FALSE,
5293 EL_EMC_KEY_8, -1, -1
5296 Xwind_n, TRUE, FALSE,
5297 EL_BALLOON_SWITCH_UP, -1, -1
5300 Xwind_e, TRUE, FALSE,
5301 EL_BALLOON_SWITCH_RIGHT, -1, -1
5304 Xwind_s, TRUE, FALSE,
5305 EL_BALLOON_SWITCH_DOWN, -1, -1
5308 Xwind_w, TRUE, FALSE,
5309 EL_BALLOON_SWITCH_LEFT, -1, -1
5312 Xwind_nesw, TRUE, FALSE,
5313 EL_BALLOON_SWITCH_ANY, -1, -1
5316 Xwind_stop, TRUE, FALSE,
5317 EL_BALLOON_SWITCH_NONE, -1, -1
5321 EL_EM_EXIT_CLOSED, -1, -1
5324 Xexit_1, TRUE, FALSE,
5325 EL_EM_EXIT_OPEN, -1, -1
5328 Xexit_2, FALSE, FALSE,
5329 EL_EM_EXIT_OPEN, -1, -1
5332 Xexit_3, FALSE, FALSE,
5333 EL_EM_EXIT_OPEN, -1, -1
5336 Xdynamite, TRUE, FALSE,
5337 EL_EM_DYNAMITE, -1, -1
5340 Ydynamite_eat, FALSE, FALSE,
5341 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5344 Xdynamite_1, TRUE, FALSE,
5345 EL_EM_DYNAMITE_ACTIVE, -1, -1
5348 Xdynamite_2, FALSE, FALSE,
5349 EL_EM_DYNAMITE_ACTIVE, -1, -1
5352 Xdynamite_3, FALSE, FALSE,
5353 EL_EM_DYNAMITE_ACTIVE, -1, -1
5356 Xdynamite_4, FALSE, FALSE,
5357 EL_EM_DYNAMITE_ACTIVE, -1, -1
5360 Xbumper, TRUE, FALSE,
5361 EL_EMC_SPRING_BUMPER, -1, -1
5364 XbumperB, FALSE, FALSE,
5365 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5368 Xwheel, TRUE, FALSE,
5369 EL_ROBOT_WHEEL, -1, -1
5372 XwheelB, FALSE, FALSE,
5373 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5376 Xswitch, TRUE, FALSE,
5377 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5380 XswitchB, FALSE, FALSE,
5381 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5385 EL_QUICKSAND_EMPTY, -1, -1
5388 Xsand_stone, TRUE, FALSE,
5389 EL_QUICKSAND_FULL, -1, -1
5392 Xsand_stonein_1, FALSE, TRUE,
5393 EL_ROCK, ACTION_FILLING, -1
5396 Xsand_stonein_2, FALSE, TRUE,
5397 EL_ROCK, ACTION_FILLING, -1
5400 Xsand_stonein_3, FALSE, TRUE,
5401 EL_ROCK, ACTION_FILLING, -1
5404 Xsand_stonein_4, FALSE, TRUE,
5405 EL_ROCK, ACTION_FILLING, -1
5409 Xsand_stonesand_1, FALSE, FALSE,
5410 EL_QUICKSAND_EMPTYING, -1, -1
5413 Xsand_stonesand_2, FALSE, FALSE,
5414 EL_QUICKSAND_EMPTYING, -1, -1
5417 Xsand_stonesand_3, FALSE, FALSE,
5418 EL_QUICKSAND_EMPTYING, -1, -1
5421 Xsand_stonesand_4, FALSE, FALSE,
5422 EL_QUICKSAND_EMPTYING, -1, -1
5425 Xsand_stonesand_quickout_1, FALSE, FALSE,
5426 EL_QUICKSAND_EMPTYING, -1, -1
5429 Xsand_stonesand_quickout_2, FALSE, FALSE,
5430 EL_QUICKSAND_EMPTYING, -1, -1
5434 Xsand_stonesand_1, FALSE, FALSE,
5435 EL_QUICKSAND_FULL, -1, -1
5438 Xsand_stonesand_2, FALSE, FALSE,
5439 EL_QUICKSAND_FULL, -1, -1
5442 Xsand_stonesand_3, FALSE, FALSE,
5443 EL_QUICKSAND_FULL, -1, -1
5446 Xsand_stonesand_4, FALSE, FALSE,
5447 EL_QUICKSAND_FULL, -1, -1
5451 Xsand_stoneout_1, FALSE, FALSE,
5452 EL_ROCK, ACTION_EMPTYING, -1
5455 Xsand_stoneout_2, FALSE, FALSE,
5456 EL_ROCK, ACTION_EMPTYING, -1
5460 Xsand_sandstone_1, FALSE, FALSE,
5461 EL_QUICKSAND_FILLING, -1, -1
5464 Xsand_sandstone_2, FALSE, FALSE,
5465 EL_QUICKSAND_FILLING, -1, -1
5468 Xsand_sandstone_3, FALSE, FALSE,
5469 EL_QUICKSAND_FILLING, -1, -1
5472 Xsand_sandstone_4, FALSE, FALSE,
5473 EL_QUICKSAND_FILLING, -1, -1
5477 Xsand_sandstone_1, FALSE, FALSE,
5478 EL_QUICKSAND_FULL, -1, -1
5481 Xsand_sandstone_2, FALSE, FALSE,
5482 EL_QUICKSAND_FULL, -1, -1
5485 Xsand_sandstone_3, FALSE, FALSE,
5486 EL_QUICKSAND_FULL, -1, -1
5489 Xsand_sandstone_4, FALSE, FALSE,
5490 EL_QUICKSAND_FULL, -1, -1
5494 Xplant, TRUE, FALSE,
5495 EL_EMC_PLANT, -1, -1
5498 Yplant, FALSE, FALSE,
5499 EL_EMC_PLANT, -1, -1
5502 Xlenses, TRUE, FALSE,
5503 EL_EMC_LENSES, -1, -1
5506 Xmagnify, TRUE, FALSE,
5507 EL_EMC_MAGNIFIER, -1, -1
5510 Xdripper, TRUE, FALSE,
5511 EL_EMC_DRIPPER, -1, -1
5514 XdripperB, FALSE, FALSE,
5515 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5518 Xfake_blank, TRUE, FALSE,
5519 EL_INVISIBLE_WALL, -1, -1
5522 Xfake_blankB, FALSE, FALSE,
5523 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5526 Xfake_grass, TRUE, FALSE,
5527 EL_EMC_FAKE_GRASS, -1, -1
5530 Xfake_grassB, FALSE, FALSE,
5531 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5534 Xfake_door_1, TRUE, FALSE,
5535 EL_EM_GATE_1_GRAY, -1, -1
5538 Xfake_door_2, TRUE, FALSE,
5539 EL_EM_GATE_2_GRAY, -1, -1
5542 Xfake_door_3, TRUE, FALSE,
5543 EL_EM_GATE_3_GRAY, -1, -1
5546 Xfake_door_4, TRUE, FALSE,
5547 EL_EM_GATE_4_GRAY, -1, -1
5550 Xfake_door_5, TRUE, FALSE,
5551 EL_EMC_GATE_5_GRAY, -1, -1
5554 Xfake_door_6, TRUE, FALSE,
5555 EL_EMC_GATE_6_GRAY, -1, -1
5558 Xfake_door_7, TRUE, FALSE,
5559 EL_EMC_GATE_7_GRAY, -1, -1
5562 Xfake_door_8, TRUE, FALSE,
5563 EL_EMC_GATE_8_GRAY, -1, -1
5566 Xfake_acid_1, TRUE, FALSE,
5567 EL_EMC_FAKE_ACID, -1, -1
5570 Xfake_acid_2, FALSE, FALSE,
5571 EL_EMC_FAKE_ACID, -1, -1
5574 Xfake_acid_3, FALSE, FALSE,
5575 EL_EMC_FAKE_ACID, -1, -1
5578 Xfake_acid_4, FALSE, FALSE,
5579 EL_EMC_FAKE_ACID, -1, -1
5582 Xfake_acid_5, FALSE, FALSE,
5583 EL_EMC_FAKE_ACID, -1, -1
5586 Xfake_acid_6, FALSE, FALSE,
5587 EL_EMC_FAKE_ACID, -1, -1
5590 Xfake_acid_7, FALSE, FALSE,
5591 EL_EMC_FAKE_ACID, -1, -1
5594 Xfake_acid_8, FALSE, FALSE,
5595 EL_EMC_FAKE_ACID, -1, -1
5598 Xsteel_1, TRUE, FALSE,
5599 EL_STEELWALL, -1, -1
5602 Xsteel_2, TRUE, FALSE,
5603 EL_EMC_STEELWALL_2, -1, -1
5606 Xsteel_3, TRUE, FALSE,
5607 EL_EMC_STEELWALL_3, -1, -1
5610 Xsteel_4, TRUE, FALSE,
5611 EL_EMC_STEELWALL_4, -1, -1
5614 Xwall_1, TRUE, FALSE,
5618 Xwall_2, TRUE, FALSE,
5619 EL_EMC_WALL_14, -1, -1
5622 Xwall_3, TRUE, FALSE,
5623 EL_EMC_WALL_15, -1, -1
5626 Xwall_4, TRUE, FALSE,
5627 EL_EMC_WALL_16, -1, -1
5630 Xround_wall_1, TRUE, FALSE,
5631 EL_WALL_SLIPPERY, -1, -1
5634 Xround_wall_2, TRUE, FALSE,
5635 EL_EMC_WALL_SLIPPERY_2, -1, -1
5638 Xround_wall_3, TRUE, FALSE,
5639 EL_EMC_WALL_SLIPPERY_3, -1, -1
5642 Xround_wall_4, TRUE, FALSE,
5643 EL_EMC_WALL_SLIPPERY_4, -1, -1
5646 Xdecor_1, TRUE, FALSE,
5647 EL_EMC_WALL_8, -1, -1
5650 Xdecor_2, TRUE, FALSE,
5651 EL_EMC_WALL_6, -1, -1
5654 Xdecor_3, TRUE, FALSE,
5655 EL_EMC_WALL_4, -1, -1
5658 Xdecor_4, TRUE, FALSE,
5659 EL_EMC_WALL_7, -1, -1
5662 Xdecor_5, TRUE, FALSE,
5663 EL_EMC_WALL_5, -1, -1
5666 Xdecor_6, TRUE, FALSE,
5667 EL_EMC_WALL_9, -1, -1
5670 Xdecor_7, TRUE, FALSE,
5671 EL_EMC_WALL_10, -1, -1
5674 Xdecor_8, TRUE, FALSE,
5675 EL_EMC_WALL_1, -1, -1
5678 Xdecor_9, TRUE, FALSE,
5679 EL_EMC_WALL_2, -1, -1
5682 Xdecor_10, TRUE, FALSE,
5683 EL_EMC_WALL_3, -1, -1
5686 Xdecor_11, TRUE, FALSE,
5687 EL_EMC_WALL_11, -1, -1
5690 Xdecor_12, TRUE, FALSE,
5691 EL_EMC_WALL_12, -1, -1
5694 Xalpha_0, TRUE, FALSE,
5695 EL_CHAR('0'), -1, -1
5698 Xalpha_1, TRUE, FALSE,
5699 EL_CHAR('1'), -1, -1
5702 Xalpha_2, TRUE, FALSE,
5703 EL_CHAR('2'), -1, -1
5706 Xalpha_3, TRUE, FALSE,
5707 EL_CHAR('3'), -1, -1
5710 Xalpha_4, TRUE, FALSE,
5711 EL_CHAR('4'), -1, -1
5714 Xalpha_5, TRUE, FALSE,
5715 EL_CHAR('5'), -1, -1
5718 Xalpha_6, TRUE, FALSE,
5719 EL_CHAR('6'), -1, -1
5722 Xalpha_7, TRUE, FALSE,
5723 EL_CHAR('7'), -1, -1
5726 Xalpha_8, TRUE, FALSE,
5727 EL_CHAR('8'), -1, -1
5730 Xalpha_9, TRUE, FALSE,
5731 EL_CHAR('9'), -1, -1
5734 Xalpha_excla, TRUE, FALSE,
5735 EL_CHAR('!'), -1, -1
5738 Xalpha_quote, TRUE, FALSE,
5739 EL_CHAR('"'), -1, -1
5742 Xalpha_comma, TRUE, FALSE,
5743 EL_CHAR(','), -1, -1
5746 Xalpha_minus, TRUE, FALSE,
5747 EL_CHAR('-'), -1, -1
5750 Xalpha_perio, TRUE, FALSE,
5751 EL_CHAR('.'), -1, -1
5754 Xalpha_colon, TRUE, FALSE,
5755 EL_CHAR(':'), -1, -1
5758 Xalpha_quest, TRUE, FALSE,
5759 EL_CHAR('?'), -1, -1
5762 Xalpha_a, TRUE, FALSE,
5763 EL_CHAR('A'), -1, -1
5766 Xalpha_b, TRUE, FALSE,
5767 EL_CHAR('B'), -1, -1
5770 Xalpha_c, TRUE, FALSE,
5771 EL_CHAR('C'), -1, -1
5774 Xalpha_d, TRUE, FALSE,
5775 EL_CHAR('D'), -1, -1
5778 Xalpha_e, TRUE, FALSE,
5779 EL_CHAR('E'), -1, -1
5782 Xalpha_f, TRUE, FALSE,
5783 EL_CHAR('F'), -1, -1
5786 Xalpha_g, TRUE, FALSE,
5787 EL_CHAR('G'), -1, -1
5790 Xalpha_h, TRUE, FALSE,
5791 EL_CHAR('H'), -1, -1
5794 Xalpha_i, TRUE, FALSE,
5795 EL_CHAR('I'), -1, -1
5798 Xalpha_j, TRUE, FALSE,
5799 EL_CHAR('J'), -1, -1
5802 Xalpha_k, TRUE, FALSE,
5803 EL_CHAR('K'), -1, -1
5806 Xalpha_l, TRUE, FALSE,
5807 EL_CHAR('L'), -1, -1
5810 Xalpha_m, TRUE, FALSE,
5811 EL_CHAR('M'), -1, -1
5814 Xalpha_n, TRUE, FALSE,
5815 EL_CHAR('N'), -1, -1
5818 Xalpha_o, TRUE, FALSE,
5819 EL_CHAR('O'), -1, -1
5822 Xalpha_p, TRUE, FALSE,
5823 EL_CHAR('P'), -1, -1
5826 Xalpha_q, TRUE, FALSE,
5827 EL_CHAR('Q'), -1, -1
5830 Xalpha_r, TRUE, FALSE,
5831 EL_CHAR('R'), -1, -1
5834 Xalpha_s, TRUE, FALSE,
5835 EL_CHAR('S'), -1, -1
5838 Xalpha_t, TRUE, FALSE,
5839 EL_CHAR('T'), -1, -1
5842 Xalpha_u, TRUE, FALSE,
5843 EL_CHAR('U'), -1, -1
5846 Xalpha_v, TRUE, FALSE,
5847 EL_CHAR('V'), -1, -1
5850 Xalpha_w, TRUE, FALSE,
5851 EL_CHAR('W'), -1, -1
5854 Xalpha_x, TRUE, FALSE,
5855 EL_CHAR('X'), -1, -1
5858 Xalpha_y, TRUE, FALSE,
5859 EL_CHAR('Y'), -1, -1
5862 Xalpha_z, TRUE, FALSE,
5863 EL_CHAR('Z'), -1, -1
5866 Xalpha_arrow_e, TRUE, FALSE,
5867 EL_CHAR('>'), -1, -1
5870 Xalpha_arrow_w, TRUE, FALSE,
5871 EL_CHAR('<'), -1, -1
5874 Xalpha_copyr, TRUE, FALSE,
5875 EL_CHAR('©'), -1, -1
5879 Xboom_bug, FALSE, FALSE,
5880 EL_BUG, ACTION_EXPLODING, -1
5883 Xboom_bomb, FALSE, FALSE,
5884 EL_BOMB, ACTION_EXPLODING, -1
5887 Xboom_android, FALSE, FALSE,
5888 EL_EMC_ANDROID, ACTION_OTHER, -1
5891 Xboom_1, FALSE, FALSE,
5892 EL_DEFAULT, ACTION_EXPLODING, -1
5895 Xboom_2, FALSE, FALSE,
5896 EL_DEFAULT, ACTION_EXPLODING, -1
5899 Znormal, FALSE, FALSE,
5903 Zdynamite, FALSE, FALSE,
5907 Zplayer, FALSE, FALSE,
5911 ZBORDER, FALSE, FALSE,
5921 static struct Mapping_EM_to_RND_player
5930 em_player_mapping_list[] =
5934 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5938 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5942 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5946 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5950 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5954 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5958 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5962 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5966 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5970 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5974 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5978 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5982 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5986 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5990 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5994 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5998 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6002 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6006 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6010 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6014 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6018 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6022 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6026 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6030 EL_PLAYER_1, ACTION_DEFAULT, -1,
6034 EL_PLAYER_2, ACTION_DEFAULT, -1,
6038 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6042 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6046 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6050 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6054 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6058 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6062 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6066 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6070 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6074 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6078 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6082 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6086 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6090 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6094 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6098 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6102 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6106 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6110 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6114 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6118 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6122 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6126 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6130 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6134 EL_PLAYER_3, ACTION_DEFAULT, -1,
6138 EL_PLAYER_4, ACTION_DEFAULT, -1,
6147 int map_element_RND_to_EM(int element_rnd)
6149 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6150 static boolean mapping_initialized = FALSE;
6152 if (!mapping_initialized)
6156 /* return "Xalpha_quest" for all undefined elements in mapping array */
6157 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6158 mapping_RND_to_EM[i] = Xalpha_quest;
6160 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6161 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6162 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6163 em_object_mapping_list[i].element_em;
6165 mapping_initialized = TRUE;
6168 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6169 return mapping_RND_to_EM[element_rnd];
6171 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6176 int map_element_EM_to_RND(int element_em)
6178 static unsigned short mapping_EM_to_RND[TILE_MAX];
6179 static boolean mapping_initialized = FALSE;
6181 if (!mapping_initialized)
6185 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6186 for (i = 0; i < TILE_MAX; i++)
6187 mapping_EM_to_RND[i] = EL_UNKNOWN;
6189 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6190 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6191 em_object_mapping_list[i].element_rnd;
6193 mapping_initialized = TRUE;
6196 if (element_em >= 0 && element_em < TILE_MAX)
6197 return mapping_EM_to_RND[element_em];
6199 Error(ERR_WARN, "invalid EM level element %d", element_em);
6204 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6206 struct LevelInfo_EM *level_em = level->native_em_level;
6207 struct LEVEL *lev = level_em->lev;
6210 for (i = 0; i < TILE_MAX; i++)
6211 lev->android_array[i] = Xblank;
6213 for (i = 0; i < level->num_android_clone_elements; i++)
6215 int element_rnd = level->android_clone_element[i];
6216 int element_em = map_element_RND_to_EM(element_rnd);
6218 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6219 if (em_object_mapping_list[j].element_rnd == element_rnd)
6220 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6224 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6226 struct LevelInfo_EM *level_em = level->native_em_level;
6227 struct LEVEL *lev = level_em->lev;
6230 level->num_android_clone_elements = 0;
6232 for (i = 0; i < TILE_MAX; i++)
6234 int element_em = lev->android_array[i];
6236 boolean element_found = FALSE;
6238 if (element_em == Xblank)
6241 element_rnd = map_element_EM_to_RND(element_em);
6243 for (j = 0; j < level->num_android_clone_elements; j++)
6244 if (level->android_clone_element[j] == element_rnd)
6245 element_found = TRUE;
6249 level->android_clone_element[level->num_android_clone_elements++] =
6252 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6257 if (level->num_android_clone_elements == 0)
6259 level->num_android_clone_elements = 1;
6260 level->android_clone_element[0] = EL_EMPTY;
6264 int map_direction_RND_to_EM(int direction)
6266 return (direction == MV_UP ? 0 :
6267 direction == MV_RIGHT ? 1 :
6268 direction == MV_DOWN ? 2 :
6269 direction == MV_LEFT ? 3 :
6273 int map_direction_EM_to_RND(int direction)
6275 return (direction == 0 ? MV_UP :
6276 direction == 1 ? MV_RIGHT :
6277 direction == 2 ? MV_DOWN :
6278 direction == 3 ? MV_LEFT :
6282 int map_element_RND_to_SP(int element_rnd)
6284 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6286 if (element_rnd >= EL_SP_START &&
6287 element_rnd <= EL_SP_END)
6288 element_sp = element_rnd - EL_SP_START;
6289 else if (element_rnd == EL_EMPTY_SPACE)
6291 else if (element_rnd == EL_INVISIBLE_WALL)
6297 int map_element_SP_to_RND(int element_sp)
6299 int element_rnd = EL_UNKNOWN;
6301 if (element_sp >= 0x00 &&
6303 element_rnd = EL_SP_START + element_sp;
6304 else if (element_sp == 0x28)
6305 element_rnd = EL_INVISIBLE_WALL;
6310 int map_action_SP_to_RND(int action_sp)
6314 case actActive: return ACTION_ACTIVE;
6315 case actImpact: return ACTION_IMPACT;
6316 case actExploding: return ACTION_EXPLODING;
6317 case actDigging: return ACTION_DIGGING;
6318 case actSnapping: return ACTION_SNAPPING;
6319 case actCollecting: return ACTION_COLLECTING;
6320 case actPassing: return ACTION_PASSING;
6321 case actPushing: return ACTION_PUSHING;
6322 case actDropping: return ACTION_DROPPING;
6324 default: return ACTION_DEFAULT;
6328 int get_next_element(int element)
6332 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6333 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6334 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6335 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6336 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6337 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6338 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6339 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6340 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6341 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6342 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6344 default: return element;
6349 int el_act_dir2img(int element, int action, int direction)
6351 element = GFX_ELEMENT(element);
6353 if (direction == MV_NONE)
6354 return element_info[element].graphic[action];
6356 direction = MV_DIR_TO_BIT(direction);
6358 return element_info[element].direction_graphic[action][direction];
6361 int el_act_dir2img(int element, int action, int direction)
6363 element = GFX_ELEMENT(element);
6364 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6366 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6367 return element_info[element].direction_graphic[action][direction];
6372 static int el_act_dir2crm(int element, int action, int direction)
6374 element = GFX_ELEMENT(element);
6376 if (direction == MV_NONE)
6377 return element_info[element].crumbled[action];
6379 direction = MV_DIR_TO_BIT(direction);
6381 return element_info[element].direction_crumbled[action][direction];
6384 static int el_act_dir2crm(int element, int action, int direction)
6386 element = GFX_ELEMENT(element);
6387 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6389 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6390 return element_info[element].direction_crumbled[action][direction];
6394 int el_act2img(int element, int action)
6396 element = GFX_ELEMENT(element);
6398 return element_info[element].graphic[action];
6401 int el_act2crm(int element, int action)
6403 element = GFX_ELEMENT(element);
6405 return element_info[element].crumbled[action];
6408 int el_dir2img(int element, int direction)
6410 element = GFX_ELEMENT(element);
6412 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6415 int el2baseimg(int element)
6417 return element_info[element].graphic[ACTION_DEFAULT];
6420 int el2img(int element)
6422 element = GFX_ELEMENT(element);
6424 return element_info[element].graphic[ACTION_DEFAULT];
6427 int el2edimg(int element)
6429 element = GFX_ELEMENT(element);
6431 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6434 int el2preimg(int element)
6436 element = GFX_ELEMENT(element);
6438 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6441 int el2panelimg(int element)
6443 element = GFX_ELEMENT(element);
6445 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6448 int font2baseimg(int font_nr)
6450 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6453 int getBeltNrFromBeltElement(int element)
6455 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6456 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6457 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6460 int getBeltNrFromBeltActiveElement(int element)
6462 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6463 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6464 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6467 int getBeltNrFromBeltSwitchElement(int element)
6469 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6470 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6471 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6474 int getBeltDirNrFromBeltElement(int element)
6476 static int belt_base_element[4] =
6478 EL_CONVEYOR_BELT_1_LEFT,
6479 EL_CONVEYOR_BELT_2_LEFT,
6480 EL_CONVEYOR_BELT_3_LEFT,
6481 EL_CONVEYOR_BELT_4_LEFT
6484 int belt_nr = getBeltNrFromBeltElement(element);
6485 int belt_dir_nr = element - belt_base_element[belt_nr];
6487 return (belt_dir_nr % 3);
6490 int getBeltDirNrFromBeltSwitchElement(int element)
6492 static int belt_base_element[4] =
6494 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6495 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6496 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6497 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6500 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6501 int belt_dir_nr = element - belt_base_element[belt_nr];
6503 return (belt_dir_nr % 3);
6506 int getBeltDirFromBeltElement(int element)
6508 static int belt_move_dir[3] =
6515 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6517 return belt_move_dir[belt_dir_nr];
6520 int getBeltDirFromBeltSwitchElement(int element)
6522 static int belt_move_dir[3] =
6529 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6531 return belt_move_dir[belt_dir_nr];
6534 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6536 static int belt_base_element[4] =
6538 EL_CONVEYOR_BELT_1_LEFT,
6539 EL_CONVEYOR_BELT_2_LEFT,
6540 EL_CONVEYOR_BELT_3_LEFT,
6541 EL_CONVEYOR_BELT_4_LEFT
6544 return belt_base_element[belt_nr] + belt_dir_nr;
6547 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6549 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6551 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6554 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6556 static int belt_base_element[4] =
6558 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6559 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6560 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6561 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6564 return belt_base_element[belt_nr] + belt_dir_nr;
6567 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6569 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6571 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6574 int getNumActivePlayers_EM()
6576 int num_players = 0;
6582 for (i = 0; i < MAX_PLAYERS; i++)
6583 if (tape.player_participates[i])
6589 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6591 int game_frame_delay_value;
6593 game_frame_delay_value =
6594 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6595 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6598 if (tape.playing && tape.warp_forward && !tape.pausing)
6599 game_frame_delay_value = 0;
6601 return game_frame_delay_value;
6604 unsigned int InitRND(long seed)
6606 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6607 return InitEngineRandom_EM(seed);
6608 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6609 return InitEngineRandom_SP(seed);
6611 return InitEngineRandom_RND(seed);
6615 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6616 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6619 inline static int get_effective_element_EM(int tile, int frame_em)
6621 int element = object_mapping[tile].element_rnd;
6622 int action = object_mapping[tile].action;
6623 boolean is_backside = object_mapping[tile].is_backside;
6624 boolean action_removing = (action == ACTION_DIGGING ||
6625 action == ACTION_SNAPPING ||
6626 action == ACTION_COLLECTING);
6632 case Yacid_splash_eB:
6633 case Yacid_splash_wB:
6634 return (frame_em > 5 ? EL_EMPTY : element);
6640 else /* frame_em == 7 */
6644 case Yacid_splash_eB:
6645 case Yacid_splash_wB:
6648 case Yemerald_stone:
6651 case Ydiamond_stone:
6655 case Xdrip_stretchB:
6674 case Xsand_stonein_1:
6675 case Xsand_stonein_2:
6676 case Xsand_stonein_3:
6677 case Xsand_stonein_4:
6681 return (is_backside || action_removing ? EL_EMPTY : element);
6686 inline static boolean check_linear_animation_EM(int tile)
6690 case Xsand_stonesand_1:
6691 case Xsand_stonesand_quickout_1:
6692 case Xsand_sandstone_1:
6693 case Xsand_stonein_1:
6694 case Xsand_stoneout_1:
6719 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6720 boolean has_crumbled_graphics,
6721 int crumbled, int sync_frame)
6723 /* if element can be crumbled, but certain action graphics are just empty
6724 space (like instantly snapping sand to empty space in 1 frame), do not
6725 treat these empty space graphics as crumbled graphics in EMC engine */
6726 if (crumbled == IMG_EMPTY_SPACE)
6727 has_crumbled_graphics = FALSE;
6729 if (has_crumbled_graphics)
6731 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6732 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6733 g_crumbled->anim_delay,
6734 g_crumbled->anim_mode,
6735 g_crumbled->anim_start_frame,
6738 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6739 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6741 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6743 g_em->has_crumbled_graphics = TRUE;
6747 g_em->crumbled_bitmap = NULL;
6748 g_em->crumbled_src_x = 0;
6749 g_em->crumbled_src_y = 0;
6750 g_em->crumbled_border_size = 0;
6752 g_em->has_crumbled_graphics = FALSE;
6756 void ResetGfxAnimation_EM(int x, int y, int tile)
6761 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6762 int tile, int frame_em, int x, int y)
6764 int action = object_mapping[tile].action;
6766 int direction = object_mapping[tile].direction;
6767 int effective_element = get_effective_element_EM(tile, frame_em);
6768 int graphic = (direction == MV_NONE ?
6769 el_act2img(effective_element, action) :
6770 el_act_dir2img(effective_element, action, direction));
6771 struct GraphicInfo *g = &graphic_info[graphic];
6774 boolean action_removing = (action == ACTION_DIGGING ||
6775 action == ACTION_SNAPPING ||
6776 action == ACTION_COLLECTING);
6777 boolean action_moving = (action == ACTION_FALLING ||
6778 action == ACTION_MOVING ||
6779 action == ACTION_PUSHING ||
6780 action == ACTION_EATING ||
6781 action == ACTION_FILLING ||
6782 action == ACTION_EMPTYING);
6783 boolean action_falling = (action == ACTION_FALLING ||
6784 action == ACTION_FILLING ||
6785 action == ACTION_EMPTYING);
6787 /* special case: graphic uses "2nd movement tile" and has defined
6788 7 frames for movement animation (or less) => use default graphic
6789 for last (8th) frame which ends the movement animation */
6790 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6792 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6793 graphic = (direction == MV_NONE ?
6794 el_act2img(effective_element, action) :
6795 el_act_dir2img(effective_element, action, direction));
6797 g = &graphic_info[graphic];
6801 if (tile == Xsand_stonesand_1 ||
6802 tile == Xsand_stonesand_2 ||
6803 tile == Xsand_stonesand_3 ||
6804 tile == Xsand_stonesand_4)
6805 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6809 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6813 // printf("::: resetting... [%d]\n", tile);
6816 if (action_removing || check_linear_animation_EM(tile))
6818 GfxFrame[x][y] = frame_em;
6820 // printf("::: resetting... [%d]\n", tile);
6823 else if (action_moving)
6825 boolean is_backside = object_mapping[tile].is_backside;
6829 int direction = object_mapping[tile].direction;
6830 int move_dir = (action_falling ? MV_DOWN : direction);
6835 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6836 if (g->double_movement && frame_em == 0)
6840 // printf("::: resetting... [%d]\n", tile);
6844 if (move_dir == MV_LEFT)
6845 GfxFrame[x - 1][y] = GfxFrame[x][y];
6846 else if (move_dir == MV_RIGHT)
6847 GfxFrame[x + 1][y] = GfxFrame[x][y];
6848 else if (move_dir == MV_UP)
6849 GfxFrame[x][y - 1] = GfxFrame[x][y];
6850 else if (move_dir == MV_DOWN)
6851 GfxFrame[x][y + 1] = GfxFrame[x][y];
6858 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6859 if (tile == Xsand_stonesand_quickout_1 ||
6860 tile == Xsand_stonesand_quickout_2)
6865 if (tile == Xsand_stonesand_1 ||
6866 tile == Xsand_stonesand_2 ||
6867 tile == Xsand_stonesand_3 ||
6868 tile == Xsand_stonesand_4)
6869 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6873 if (graphic_info[graphic].anim_global_sync)
6874 sync_frame = FrameCounter;
6875 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6876 sync_frame = GfxFrame[x][y];
6878 sync_frame = 0; /* playfield border (pseudo steel) */
6880 SetRandomAnimationValue(x, y);
6882 int frame = getAnimationFrame(g->anim_frames,
6885 g->anim_start_frame,
6888 g_em->unique_identifier =
6889 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6893 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6894 int tile, int frame_em, int x, int y)
6896 int action = object_mapping[tile].action;
6897 int direction = object_mapping[tile].direction;
6898 boolean is_backside = object_mapping[tile].is_backside;
6899 int effective_element = get_effective_element_EM(tile, frame_em);
6901 int effective_action = action;
6903 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
6905 int graphic = (direction == MV_NONE ?
6906 el_act2img(effective_element, effective_action) :
6907 el_act_dir2img(effective_element, effective_action,
6909 int crumbled = (direction == MV_NONE ?
6910 el_act2crm(effective_element, effective_action) :
6911 el_act_dir2crm(effective_element, effective_action,
6913 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6914 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6915 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6916 struct GraphicInfo *g = &graphic_info[graphic];
6918 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6922 /* special case: graphic uses "2nd movement tile" and has defined
6923 7 frames for movement animation (or less) => use default graphic
6924 for last (8th) frame which ends the movement animation */
6925 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6927 effective_action = ACTION_DEFAULT;
6928 graphic = (direction == MV_NONE ?
6929 el_act2img(effective_element, effective_action) :
6930 el_act_dir2img(effective_element, effective_action,
6932 crumbled = (direction == MV_NONE ?
6933 el_act2crm(effective_element, effective_action) :
6934 el_act_dir2crm(effective_element, effective_action,
6937 g = &graphic_info[graphic];
6947 if (frame_em == 0) /* reset animation frame for certain elements */
6949 if (check_linear_animation_EM(tile))
6954 if (graphic_info[graphic].anim_global_sync)
6955 sync_frame = FrameCounter;
6956 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6957 sync_frame = GfxFrame[x][y];
6959 sync_frame = 0; /* playfield border (pseudo steel) */
6961 SetRandomAnimationValue(x, y);
6966 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6967 i == Xdrip_stretchB ? 7 :
6968 i == Ydrip_s2 ? j + 8 :
6969 i == Ydrip_s2B ? j + 8 :
6978 i == Xfake_acid_1 ? 0 :
6979 i == Xfake_acid_2 ? 10 :
6980 i == Xfake_acid_3 ? 20 :
6981 i == Xfake_acid_4 ? 30 :
6982 i == Xfake_acid_5 ? 40 :
6983 i == Xfake_acid_6 ? 50 :
6984 i == Xfake_acid_7 ? 60 :
6985 i == Xfake_acid_8 ? 70 :
6987 i == Xball_2B ? j + 8 :
6988 i == Yball_eat ? j + 1 :
6989 i == Ykey_1_eat ? j + 1 :
6990 i == Ykey_2_eat ? j + 1 :
6991 i == Ykey_3_eat ? j + 1 :
6992 i == Ykey_4_eat ? j + 1 :
6993 i == Ykey_5_eat ? j + 1 :
6994 i == Ykey_6_eat ? j + 1 :
6995 i == Ykey_7_eat ? j + 1 :
6996 i == Ykey_8_eat ? j + 1 :
6997 i == Ylenses_eat ? j + 1 :
6998 i == Ymagnify_eat ? j + 1 :
6999 i == Ygrass_eat ? j + 1 :
7000 i == Ydirt_eat ? j + 1 :
7001 i == Xamoeba_1 ? 0 :
7002 i == Xamoeba_2 ? 1 :
7003 i == Xamoeba_3 ? 2 :
7004 i == Xamoeba_4 ? 3 :
7005 i == Xamoeba_5 ? 0 :
7006 i == Xamoeba_6 ? 1 :
7007 i == Xamoeba_7 ? 2 :
7008 i == Xamoeba_8 ? 3 :
7009 i == Xexit_2 ? j + 8 :
7010 i == Xexit_3 ? j + 16 :
7011 i == Xdynamite_1 ? 0 :
7012 i == Xdynamite_2 ? 8 :
7013 i == Xdynamite_3 ? 16 :
7014 i == Xdynamite_4 ? 24 :
7015 i == Xsand_stonein_1 ? j + 1 :
7016 i == Xsand_stonein_2 ? j + 9 :
7017 i == Xsand_stonein_3 ? j + 17 :
7018 i == Xsand_stonein_4 ? j + 25 :
7019 i == Xsand_stoneout_1 && j == 0 ? 0 :
7020 i == Xsand_stoneout_1 && j == 1 ? 0 :
7021 i == Xsand_stoneout_1 && j == 2 ? 1 :
7022 i == Xsand_stoneout_1 && j == 3 ? 2 :
7023 i == Xsand_stoneout_1 && j == 4 ? 2 :
7024 i == Xsand_stoneout_1 && j == 5 ? 3 :
7025 i == Xsand_stoneout_1 && j == 6 ? 4 :
7026 i == Xsand_stoneout_1 && j == 7 ? 4 :
7027 i == Xsand_stoneout_2 && j == 0 ? 5 :
7028 i == Xsand_stoneout_2 && j == 1 ? 6 :
7029 i == Xsand_stoneout_2 && j == 2 ? 7 :
7030 i == Xsand_stoneout_2 && j == 3 ? 8 :
7031 i == Xsand_stoneout_2 && j == 4 ? 9 :
7032 i == Xsand_stoneout_2 && j == 5 ? 11 :
7033 i == Xsand_stoneout_2 && j == 6 ? 13 :
7034 i == Xsand_stoneout_2 && j == 7 ? 15 :
7035 i == Xboom_bug && j == 1 ? 2 :
7036 i == Xboom_bug && j == 2 ? 2 :
7037 i == Xboom_bug && j == 3 ? 4 :
7038 i == Xboom_bug && j == 4 ? 4 :
7039 i == Xboom_bug && j == 5 ? 2 :
7040 i == Xboom_bug && j == 6 ? 2 :
7041 i == Xboom_bug && j == 7 ? 0 :
7042 i == Xboom_bomb && j == 1 ? 2 :
7043 i == Xboom_bomb && j == 2 ? 2 :
7044 i == Xboom_bomb && j == 3 ? 4 :
7045 i == Xboom_bomb && j == 4 ? 4 :
7046 i == Xboom_bomb && j == 5 ? 2 :
7047 i == Xboom_bomb && j == 6 ? 2 :
7048 i == Xboom_bomb && j == 7 ? 0 :
7049 i == Xboom_android && j == 7 ? 6 :
7050 i == Xboom_1 && j == 1 ? 2 :
7051 i == Xboom_1 && j == 2 ? 2 :
7052 i == Xboom_1 && j == 3 ? 4 :
7053 i == Xboom_1 && j == 4 ? 4 :
7054 i == Xboom_1 && j == 5 ? 6 :
7055 i == Xboom_1 && j == 6 ? 6 :
7056 i == Xboom_1 && j == 7 ? 8 :
7057 i == Xboom_2 && j == 0 ? 8 :
7058 i == Xboom_2 && j == 1 ? 8 :
7059 i == Xboom_2 && j == 2 ? 10 :
7060 i == Xboom_2 && j == 3 ? 10 :
7061 i == Xboom_2 && j == 4 ? 10 :
7062 i == Xboom_2 && j == 5 ? 12 :
7063 i == Xboom_2 && j == 6 ? 12 :
7064 i == Xboom_2 && j == 7 ? 12 :
7066 special_animation && j == 4 ? 3 :
7067 effective_action != action ? 0 :
7073 int xxx_effective_action;
7074 int xxx_has_action_graphics;
7077 int element = object_mapping[i].element_rnd;
7078 int action = object_mapping[i].action;
7079 int direction = object_mapping[i].direction;
7080 boolean is_backside = object_mapping[i].is_backside;
7082 boolean action_removing = (action == ACTION_DIGGING ||
7083 action == ACTION_SNAPPING ||
7084 action == ACTION_COLLECTING);
7086 boolean action_exploding = ((action == ACTION_EXPLODING ||
7087 action == ACTION_SMASHED_BY_ROCK ||
7088 action == ACTION_SMASHED_BY_SPRING) &&
7089 element != EL_DIAMOND);
7090 boolean action_active = (action == ACTION_ACTIVE);
7091 boolean action_other = (action == ACTION_OTHER);
7095 int effective_element = get_effective_element_EM(i, j);
7097 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7098 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7100 i == Xdrip_stretch ? element :
7101 i == Xdrip_stretchB ? element :
7102 i == Ydrip_s1 ? element :
7103 i == Ydrip_s1B ? element :
7104 i == Xball_1B ? element :
7105 i == Xball_2 ? element :
7106 i == Xball_2B ? element :
7107 i == Yball_eat ? element :
7108 i == Ykey_1_eat ? element :
7109 i == Ykey_2_eat ? element :
7110 i == Ykey_3_eat ? element :
7111 i == Ykey_4_eat ? element :
7112 i == Ykey_5_eat ? element :
7113 i == Ykey_6_eat ? element :
7114 i == Ykey_7_eat ? element :
7115 i == Ykey_8_eat ? element :
7116 i == Ylenses_eat ? element :
7117 i == Ymagnify_eat ? element :
7118 i == Ygrass_eat ? element :
7119 i == Ydirt_eat ? element :
7120 i == Yemerald_stone ? EL_EMERALD :
7121 i == Ydiamond_stone ? EL_ROCK :
7122 i == Xsand_stonein_1 ? element :
7123 i == Xsand_stonein_2 ? element :
7124 i == Xsand_stonein_3 ? element :
7125 i == Xsand_stonein_4 ? element :
7126 is_backside ? EL_EMPTY :
7127 action_removing ? EL_EMPTY :
7130 int effective_action = (j < 7 ? action :
7131 i == Xdrip_stretch ? action :
7132 i == Xdrip_stretchB ? action :
7133 i == Ydrip_s1 ? action :
7134 i == Ydrip_s1B ? action :
7135 i == Xball_1B ? action :
7136 i == Xball_2 ? action :
7137 i == Xball_2B ? action :
7138 i == Yball_eat ? action :
7139 i == Ykey_1_eat ? action :
7140 i == Ykey_2_eat ? action :
7141 i == Ykey_3_eat ? action :
7142 i == Ykey_4_eat ? action :
7143 i == Ykey_5_eat ? action :
7144 i == Ykey_6_eat ? action :
7145 i == Ykey_7_eat ? action :
7146 i == Ykey_8_eat ? action :
7147 i == Ylenses_eat ? action :
7148 i == Ymagnify_eat ? action :
7149 i == Ygrass_eat ? action :
7150 i == Ydirt_eat ? action :
7151 i == Xsand_stonein_1 ? action :
7152 i == Xsand_stonein_2 ? action :
7153 i == Xsand_stonein_3 ? action :
7154 i == Xsand_stonein_4 ? action :
7155 i == Xsand_stoneout_1 ? action :
7156 i == Xsand_stoneout_2 ? action :
7157 i == Xboom_android ? ACTION_EXPLODING :
7158 action_exploding ? ACTION_EXPLODING :
7159 action_active ? action :
7160 action_other ? action :
7162 int graphic = (el_act_dir2img(effective_element, effective_action,
7164 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7166 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7167 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7168 boolean has_action_graphics = (graphic != base_graphic);
7169 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7170 struct GraphicInfo *g = &graphic_info[graphic];
7172 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7174 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7177 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7178 boolean special_animation = (action != ACTION_DEFAULT &&
7179 g->anim_frames == 3 &&
7180 g->anim_delay == 2 &&
7181 g->anim_mode & ANIM_LINEAR);
7182 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7183 i == Xdrip_stretchB ? 7 :
7184 i == Ydrip_s2 ? j + 8 :
7185 i == Ydrip_s2B ? j + 8 :
7194 i == Xfake_acid_1 ? 0 :
7195 i == Xfake_acid_2 ? 10 :
7196 i == Xfake_acid_3 ? 20 :
7197 i == Xfake_acid_4 ? 30 :
7198 i == Xfake_acid_5 ? 40 :
7199 i == Xfake_acid_6 ? 50 :
7200 i == Xfake_acid_7 ? 60 :
7201 i == Xfake_acid_8 ? 70 :
7203 i == Xball_2B ? j + 8 :
7204 i == Yball_eat ? j + 1 :
7205 i == Ykey_1_eat ? j + 1 :
7206 i == Ykey_2_eat ? j + 1 :
7207 i == Ykey_3_eat ? j + 1 :
7208 i == Ykey_4_eat ? j + 1 :
7209 i == Ykey_5_eat ? j + 1 :
7210 i == Ykey_6_eat ? j + 1 :
7211 i == Ykey_7_eat ? j + 1 :
7212 i == Ykey_8_eat ? j + 1 :
7213 i == Ylenses_eat ? j + 1 :
7214 i == Ymagnify_eat ? j + 1 :
7215 i == Ygrass_eat ? j + 1 :
7216 i == Ydirt_eat ? j + 1 :
7217 i == Xamoeba_1 ? 0 :
7218 i == Xamoeba_2 ? 1 :
7219 i == Xamoeba_3 ? 2 :
7220 i == Xamoeba_4 ? 3 :
7221 i == Xamoeba_5 ? 0 :
7222 i == Xamoeba_6 ? 1 :
7223 i == Xamoeba_7 ? 2 :
7224 i == Xamoeba_8 ? 3 :
7225 i == Xexit_2 ? j + 8 :
7226 i == Xexit_3 ? j + 16 :
7227 i == Xdynamite_1 ? 0 :
7228 i == Xdynamite_2 ? 8 :
7229 i == Xdynamite_3 ? 16 :
7230 i == Xdynamite_4 ? 24 :
7231 i == Xsand_stonein_1 ? j + 1 :
7232 i == Xsand_stonein_2 ? j + 9 :
7233 i == Xsand_stonein_3 ? j + 17 :
7234 i == Xsand_stonein_4 ? j + 25 :
7235 i == Xsand_stoneout_1 && j == 0 ? 0 :
7236 i == Xsand_stoneout_1 && j == 1 ? 0 :
7237 i == Xsand_stoneout_1 && j == 2 ? 1 :
7238 i == Xsand_stoneout_1 && j == 3 ? 2 :
7239 i == Xsand_stoneout_1 && j == 4 ? 2 :
7240 i == Xsand_stoneout_1 && j == 5 ? 3 :
7241 i == Xsand_stoneout_1 && j == 6 ? 4 :
7242 i == Xsand_stoneout_1 && j == 7 ? 4 :
7243 i == Xsand_stoneout_2 && j == 0 ? 5 :
7244 i == Xsand_stoneout_2 && j == 1 ? 6 :
7245 i == Xsand_stoneout_2 && j == 2 ? 7 :
7246 i == Xsand_stoneout_2 && j == 3 ? 8 :
7247 i == Xsand_stoneout_2 && j == 4 ? 9 :
7248 i == Xsand_stoneout_2 && j == 5 ? 11 :
7249 i == Xsand_stoneout_2 && j == 6 ? 13 :
7250 i == Xsand_stoneout_2 && j == 7 ? 15 :
7251 i == Xboom_bug && j == 1 ? 2 :
7252 i == Xboom_bug && j == 2 ? 2 :
7253 i == Xboom_bug && j == 3 ? 4 :
7254 i == Xboom_bug && j == 4 ? 4 :
7255 i == Xboom_bug && j == 5 ? 2 :
7256 i == Xboom_bug && j == 6 ? 2 :
7257 i == Xboom_bug && j == 7 ? 0 :
7258 i == Xboom_bomb && j == 1 ? 2 :
7259 i == Xboom_bomb && j == 2 ? 2 :
7260 i == Xboom_bomb && j == 3 ? 4 :
7261 i == Xboom_bomb && j == 4 ? 4 :
7262 i == Xboom_bomb && j == 5 ? 2 :
7263 i == Xboom_bomb && j == 6 ? 2 :
7264 i == Xboom_bomb && j == 7 ? 0 :
7265 i == Xboom_android && j == 7 ? 6 :
7266 i == Xboom_1 && j == 1 ? 2 :
7267 i == Xboom_1 && j == 2 ? 2 :
7268 i == Xboom_1 && j == 3 ? 4 :
7269 i == Xboom_1 && j == 4 ? 4 :
7270 i == Xboom_1 && j == 5 ? 6 :
7271 i == Xboom_1 && j == 6 ? 6 :
7272 i == Xboom_1 && j == 7 ? 8 :
7273 i == Xboom_2 && j == 0 ? 8 :
7274 i == Xboom_2 && j == 1 ? 8 :
7275 i == Xboom_2 && j == 2 ? 10 :
7276 i == Xboom_2 && j == 3 ? 10 :
7277 i == Xboom_2 && j == 4 ? 10 :
7278 i == Xboom_2 && j == 5 ? 12 :
7279 i == Xboom_2 && j == 6 ? 12 :
7280 i == Xboom_2 && j == 7 ? 12 :
7281 special_animation && j == 4 ? 3 :
7282 effective_action != action ? 0 :
7285 xxx_effective_action = effective_action;
7286 xxx_has_action_graphics = has_action_graphics;
7291 int frame = getAnimationFrame(g->anim_frames,
7294 g->anim_start_frame,
7308 int old_src_x = g_em->src_x;
7309 int old_src_y = g_em->src_y;
7313 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7314 g->double_movement && is_backside);
7316 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7317 &g_em->src_x, &g_em->src_y, FALSE);
7328 if (graphic == IMG_BUG_MOVING_RIGHT)
7329 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7330 g->double_movement, is_backside,
7331 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7339 g_em->src_offset_x = 0;
7340 g_em->src_offset_y = 0;
7341 g_em->dst_offset_x = 0;
7342 g_em->dst_offset_y = 0;
7343 g_em->width = TILEX;
7344 g_em->height = TILEY;
7346 g_em->preserve_background = FALSE;
7349 /* (updating the "crumbled" graphic definitions is probably not really needed,
7350 as animations for crumbled graphics can't be longer than one EMC cycle) */
7352 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7357 g_em->crumbled_bitmap = NULL;
7358 g_em->crumbled_src_x = 0;
7359 g_em->crumbled_src_y = 0;
7361 g_em->has_crumbled_graphics = FALSE;
7363 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7365 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7366 g_crumbled->anim_delay,
7367 g_crumbled->anim_mode,
7368 g_crumbled->anim_start_frame,
7371 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7372 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7374 g_em->has_crumbled_graphics = TRUE;
7380 int effective_action = xxx_effective_action;
7381 int has_action_graphics = xxx_has_action_graphics;
7383 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7384 effective_action == ACTION_MOVING ||
7385 effective_action == ACTION_PUSHING ||
7386 effective_action == ACTION_EATING)) ||
7387 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7388 effective_action == ACTION_EMPTYING)))
7391 (effective_action == ACTION_FALLING ||
7392 effective_action == ACTION_FILLING ||
7393 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7394 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7395 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7396 int num_steps = (i == Ydrip_s1 ? 16 :
7397 i == Ydrip_s1B ? 16 :
7398 i == Ydrip_s2 ? 16 :
7399 i == Ydrip_s2B ? 16 :
7400 i == Xsand_stonein_1 ? 32 :
7401 i == Xsand_stonein_2 ? 32 :
7402 i == Xsand_stonein_3 ? 32 :
7403 i == Xsand_stonein_4 ? 32 :
7404 i == Xsand_stoneout_1 ? 16 :
7405 i == Xsand_stoneout_2 ? 16 : 8);
7406 int cx = ABS(dx) * (TILEX / num_steps);
7407 int cy = ABS(dy) * (TILEY / num_steps);
7408 int step_frame = (i == Ydrip_s2 ? j + 8 :
7409 i == Ydrip_s2B ? j + 8 :
7410 i == Xsand_stonein_2 ? j + 8 :
7411 i == Xsand_stonein_3 ? j + 16 :
7412 i == Xsand_stonein_4 ? j + 24 :
7413 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7414 int step = (is_backside ? step_frame : num_steps - step_frame);
7416 if (is_backside) /* tile where movement starts */
7418 if (dx < 0 || dy < 0)
7420 g_em->src_offset_x = cx * step;
7421 g_em->src_offset_y = cy * step;
7425 g_em->dst_offset_x = cx * step;
7426 g_em->dst_offset_y = cy * step;
7429 else /* tile where movement ends */
7431 if (dx < 0 || dy < 0)
7433 g_em->dst_offset_x = cx * step;
7434 g_em->dst_offset_y = cy * step;
7438 g_em->src_offset_x = cx * step;
7439 g_em->src_offset_y = cy * step;
7443 g_em->width = TILEX - cx * step;
7444 g_em->height = TILEY - cy * step;
7447 /* create unique graphic identifier to decide if tile must be redrawn */
7448 /* bit 31 - 16 (16 bit): EM style graphic
7449 bit 15 - 12 ( 4 bit): EM style frame
7450 bit 11 - 6 ( 6 bit): graphic width
7451 bit 5 - 0 ( 6 bit): graphic height */
7452 g_em->unique_identifier =
7453 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7459 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7460 int player_nr, int anim, int frame_em)
7462 int element = player_mapping[player_nr][anim].element_rnd;
7463 int action = player_mapping[player_nr][anim].action;
7464 int direction = player_mapping[player_nr][anim].direction;
7465 int graphic = (direction == MV_NONE ?
7466 el_act2img(element, action) :
7467 el_act_dir2img(element, action, direction));
7468 struct GraphicInfo *g = &graphic_info[graphic];
7471 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7473 stored_player[player_nr].StepFrame = frame_em;
7475 sync_frame = stored_player[player_nr].Frame;
7477 int frame = getAnimationFrame(g->anim_frames,
7480 g->anim_start_frame,
7483 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7484 &g_em->src_x, &g_em->src_y, FALSE);
7487 printf("::: %d: %d, %d [%d]\n",
7489 stored_player[player_nr].Frame,
7490 stored_player[player_nr].StepFrame,
7495 void InitGraphicInfo_EM(void)
7498 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7499 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7504 int num_em_gfx_errors = 0;
7506 if (graphic_info_em_object[0][0].bitmap == NULL)
7508 /* EM graphics not yet initialized in em_open_all() */
7513 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7516 /* always start with reliable default values */
7517 for (i = 0; i < TILE_MAX; i++)
7519 object_mapping[i].element_rnd = EL_UNKNOWN;
7520 object_mapping[i].is_backside = FALSE;
7521 object_mapping[i].action = ACTION_DEFAULT;
7522 object_mapping[i].direction = MV_NONE;
7525 /* always start with reliable default values */
7526 for (p = 0; p < MAX_PLAYERS; p++)
7528 for (i = 0; i < SPR_MAX; i++)
7530 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7531 player_mapping[p][i].action = ACTION_DEFAULT;
7532 player_mapping[p][i].direction = MV_NONE;
7536 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7538 int e = em_object_mapping_list[i].element_em;
7540 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7541 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7543 if (em_object_mapping_list[i].action != -1)
7544 object_mapping[e].action = em_object_mapping_list[i].action;
7546 if (em_object_mapping_list[i].direction != -1)
7547 object_mapping[e].direction =
7548 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7551 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7553 int a = em_player_mapping_list[i].action_em;
7554 int p = em_player_mapping_list[i].player_nr;
7556 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7558 if (em_player_mapping_list[i].action != -1)
7559 player_mapping[p][a].action = em_player_mapping_list[i].action;
7561 if (em_player_mapping_list[i].direction != -1)
7562 player_mapping[p][a].direction =
7563 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7566 for (i = 0; i < TILE_MAX; i++)
7568 int element = object_mapping[i].element_rnd;
7569 int action = object_mapping[i].action;
7570 int direction = object_mapping[i].direction;
7571 boolean is_backside = object_mapping[i].is_backside;
7573 boolean action_removing = (action == ACTION_DIGGING ||
7574 action == ACTION_SNAPPING ||
7575 action == ACTION_COLLECTING);
7577 boolean action_exploding = ((action == ACTION_EXPLODING ||
7578 action == ACTION_SMASHED_BY_ROCK ||
7579 action == ACTION_SMASHED_BY_SPRING) &&
7580 element != EL_DIAMOND);
7581 boolean action_active = (action == ACTION_ACTIVE);
7582 boolean action_other = (action == ACTION_OTHER);
7584 for (j = 0; j < 8; j++)
7587 int effective_element = get_effective_element_EM(i, j);
7589 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7590 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7592 i == Xdrip_stretch ? element :
7593 i == Xdrip_stretchB ? element :
7594 i == Ydrip_s1 ? element :
7595 i == Ydrip_s1B ? element :
7596 i == Xball_1B ? element :
7597 i == Xball_2 ? element :
7598 i == Xball_2B ? element :
7599 i == Yball_eat ? element :
7600 i == Ykey_1_eat ? element :
7601 i == Ykey_2_eat ? element :
7602 i == Ykey_3_eat ? element :
7603 i == Ykey_4_eat ? element :
7604 i == Ykey_5_eat ? element :
7605 i == Ykey_6_eat ? element :
7606 i == Ykey_7_eat ? element :
7607 i == Ykey_8_eat ? element :
7608 i == Ylenses_eat ? element :
7609 i == Ymagnify_eat ? element :
7610 i == Ygrass_eat ? element :
7611 i == Ydirt_eat ? element :
7612 i == Yemerald_stone ? EL_EMERALD :
7613 i == Ydiamond_stone ? EL_ROCK :
7614 i == Xsand_stonein_1 ? element :
7615 i == Xsand_stonein_2 ? element :
7616 i == Xsand_stonein_3 ? element :
7617 i == Xsand_stonein_4 ? element :
7618 is_backside ? EL_EMPTY :
7619 action_removing ? EL_EMPTY :
7622 int effective_action = (j < 7 ? action :
7623 i == Xdrip_stretch ? action :
7624 i == Xdrip_stretchB ? action :
7625 i == Ydrip_s1 ? action :
7626 i == Ydrip_s1B ? action :
7627 i == Xball_1B ? action :
7628 i == Xball_2 ? action :
7629 i == Xball_2B ? action :
7630 i == Yball_eat ? action :
7631 i == Ykey_1_eat ? action :
7632 i == Ykey_2_eat ? action :
7633 i == Ykey_3_eat ? action :
7634 i == Ykey_4_eat ? action :
7635 i == Ykey_5_eat ? action :
7636 i == Ykey_6_eat ? action :
7637 i == Ykey_7_eat ? action :
7638 i == Ykey_8_eat ? action :
7639 i == Ylenses_eat ? action :
7640 i == Ymagnify_eat ? action :
7641 i == Ygrass_eat ? action :
7642 i == Ydirt_eat ? action :
7643 i == Xsand_stonein_1 ? action :
7644 i == Xsand_stonein_2 ? action :
7645 i == Xsand_stonein_3 ? action :
7646 i == Xsand_stonein_4 ? action :
7647 i == Xsand_stoneout_1 ? action :
7648 i == Xsand_stoneout_2 ? action :
7649 i == Xboom_android ? ACTION_EXPLODING :
7650 action_exploding ? ACTION_EXPLODING :
7651 action_active ? action :
7652 action_other ? action :
7654 int graphic = (el_act_dir2img(effective_element, effective_action,
7656 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7658 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7659 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7660 boolean has_action_graphics = (graphic != base_graphic);
7661 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7662 struct GraphicInfo *g = &graphic_info[graphic];
7664 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7666 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7669 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7670 boolean special_animation = (action != ACTION_DEFAULT &&
7671 g->anim_frames == 3 &&
7672 g->anim_delay == 2 &&
7673 g->anim_mode & ANIM_LINEAR);
7674 int sync_frame = (i == Xdrip_stretch ? 7 :
7675 i == Xdrip_stretchB ? 7 :
7676 i == Ydrip_s2 ? j + 8 :
7677 i == Ydrip_s2B ? j + 8 :
7686 i == Xfake_acid_1 ? 0 :
7687 i == Xfake_acid_2 ? 10 :
7688 i == Xfake_acid_3 ? 20 :
7689 i == Xfake_acid_4 ? 30 :
7690 i == Xfake_acid_5 ? 40 :
7691 i == Xfake_acid_6 ? 50 :
7692 i == Xfake_acid_7 ? 60 :
7693 i == Xfake_acid_8 ? 70 :
7695 i == Xball_2B ? j + 8 :
7696 i == Yball_eat ? j + 1 :
7697 i == Ykey_1_eat ? j + 1 :
7698 i == Ykey_2_eat ? j + 1 :
7699 i == Ykey_3_eat ? j + 1 :
7700 i == Ykey_4_eat ? j + 1 :
7701 i == Ykey_5_eat ? j + 1 :
7702 i == Ykey_6_eat ? j + 1 :
7703 i == Ykey_7_eat ? j + 1 :
7704 i == Ykey_8_eat ? j + 1 :
7705 i == Ylenses_eat ? j + 1 :
7706 i == Ymagnify_eat ? j + 1 :
7707 i == Ygrass_eat ? j + 1 :
7708 i == Ydirt_eat ? j + 1 :
7709 i == Xamoeba_1 ? 0 :
7710 i == Xamoeba_2 ? 1 :
7711 i == Xamoeba_3 ? 2 :
7712 i == Xamoeba_4 ? 3 :
7713 i == Xamoeba_5 ? 0 :
7714 i == Xamoeba_6 ? 1 :
7715 i == Xamoeba_7 ? 2 :
7716 i == Xamoeba_8 ? 3 :
7717 i == Xexit_2 ? j + 8 :
7718 i == Xexit_3 ? j + 16 :
7719 i == Xdynamite_1 ? 0 :
7720 i == Xdynamite_2 ? 8 :
7721 i == Xdynamite_3 ? 16 :
7722 i == Xdynamite_4 ? 24 :
7723 i == Xsand_stonein_1 ? j + 1 :
7724 i == Xsand_stonein_2 ? j + 9 :
7725 i == Xsand_stonein_3 ? j + 17 :
7726 i == Xsand_stonein_4 ? j + 25 :
7727 i == Xsand_stoneout_1 && j == 0 ? 0 :
7728 i == Xsand_stoneout_1 && j == 1 ? 0 :
7729 i == Xsand_stoneout_1 && j == 2 ? 1 :
7730 i == Xsand_stoneout_1 && j == 3 ? 2 :
7731 i == Xsand_stoneout_1 && j == 4 ? 2 :
7732 i == Xsand_stoneout_1 && j == 5 ? 3 :
7733 i == Xsand_stoneout_1 && j == 6 ? 4 :
7734 i == Xsand_stoneout_1 && j == 7 ? 4 :
7735 i == Xsand_stoneout_2 && j == 0 ? 5 :
7736 i == Xsand_stoneout_2 && j == 1 ? 6 :
7737 i == Xsand_stoneout_2 && j == 2 ? 7 :
7738 i == Xsand_stoneout_2 && j == 3 ? 8 :
7739 i == Xsand_stoneout_2 && j == 4 ? 9 :
7740 i == Xsand_stoneout_2 && j == 5 ? 11 :
7741 i == Xsand_stoneout_2 && j == 6 ? 13 :
7742 i == Xsand_stoneout_2 && j == 7 ? 15 :
7743 i == Xboom_bug && j == 1 ? 2 :
7744 i == Xboom_bug && j == 2 ? 2 :
7745 i == Xboom_bug && j == 3 ? 4 :
7746 i == Xboom_bug && j == 4 ? 4 :
7747 i == Xboom_bug && j == 5 ? 2 :
7748 i == Xboom_bug && j == 6 ? 2 :
7749 i == Xboom_bug && j == 7 ? 0 :
7750 i == Xboom_bomb && j == 1 ? 2 :
7751 i == Xboom_bomb && j == 2 ? 2 :
7752 i == Xboom_bomb && j == 3 ? 4 :
7753 i == Xboom_bomb && j == 4 ? 4 :
7754 i == Xboom_bomb && j == 5 ? 2 :
7755 i == Xboom_bomb && j == 6 ? 2 :
7756 i == Xboom_bomb && j == 7 ? 0 :
7757 i == Xboom_android && j == 7 ? 6 :
7758 i == Xboom_1 && j == 1 ? 2 :
7759 i == Xboom_1 && j == 2 ? 2 :
7760 i == Xboom_1 && j == 3 ? 4 :
7761 i == Xboom_1 && j == 4 ? 4 :
7762 i == Xboom_1 && j == 5 ? 6 :
7763 i == Xboom_1 && j == 6 ? 6 :
7764 i == Xboom_1 && j == 7 ? 8 :
7765 i == Xboom_2 && j == 0 ? 8 :
7766 i == Xboom_2 && j == 1 ? 8 :
7767 i == Xboom_2 && j == 2 ? 10 :
7768 i == Xboom_2 && j == 3 ? 10 :
7769 i == Xboom_2 && j == 4 ? 10 :
7770 i == Xboom_2 && j == 5 ? 12 :
7771 i == Xboom_2 && j == 6 ? 12 :
7772 i == Xboom_2 && j == 7 ? 12 :
7773 special_animation && j == 4 ? 3 :
7774 effective_action != action ? 0 :
7778 Bitmap *debug_bitmap = g_em->bitmap;
7779 int debug_src_x = g_em->src_x;
7780 int debug_src_y = g_em->src_y;
7783 int frame = getAnimationFrame(g->anim_frames,
7786 g->anim_start_frame,
7789 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7790 g->double_movement && is_backside);
7792 g_em->bitmap = src_bitmap;
7793 g_em->src_x = src_x;
7794 g_em->src_y = src_y;
7795 g_em->src_offset_x = 0;
7796 g_em->src_offset_y = 0;
7797 g_em->dst_offset_x = 0;
7798 g_em->dst_offset_y = 0;
7799 g_em->width = TILEX;
7800 g_em->height = TILEY;
7802 g_em->preserve_background = FALSE;
7805 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7810 g_em->crumbled_bitmap = NULL;
7811 g_em->crumbled_src_x = 0;
7812 g_em->crumbled_src_y = 0;
7813 g_em->crumbled_border_size = 0;
7815 g_em->has_crumbled_graphics = FALSE;
7818 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
7819 printf("::: empty crumbled: %d [%s], %d, %d\n",
7820 effective_element, element_info[effective_element].token_name,
7821 effective_action, direction);
7824 /* if element can be crumbled, but certain action graphics are just empty
7825 space (like instantly snapping sand to empty space in 1 frame), do not
7826 treat these empty space graphics as crumbled graphics in EMC engine */
7827 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7829 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7830 g_crumbled->anim_delay,
7831 g_crumbled->anim_mode,
7832 g_crumbled->anim_start_frame,
7835 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
7837 g_em->has_crumbled_graphics = TRUE;
7838 g_em->crumbled_bitmap = src_bitmap;
7839 g_em->crumbled_src_x = src_x;
7840 g_em->crumbled_src_y = src_y;
7841 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7845 if (g_em == &graphic_info_em_object[207][0])
7846 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
7847 graphic_info_em_object[207][0].crumbled_src_x,
7848 graphic_info_em_object[207][0].crumbled_src_y,
7850 crumbled, frame, src_x, src_y,
7855 g->anim_start_frame,
7857 gfx.anim_random_frame,
7862 printf("::: EMC tile %d is crumbled\n", i);
7868 if (element == EL_ROCK &&
7869 effective_action == ACTION_FILLING)
7870 printf("::: has_action_graphics == %d\n", has_action_graphics);
7873 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7874 effective_action == ACTION_MOVING ||
7875 effective_action == ACTION_PUSHING ||
7876 effective_action == ACTION_EATING)) ||
7877 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7878 effective_action == ACTION_EMPTYING)))
7881 (effective_action == ACTION_FALLING ||
7882 effective_action == ACTION_FILLING ||
7883 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7884 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7885 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7886 int num_steps = (i == Ydrip_s1 ? 16 :
7887 i == Ydrip_s1B ? 16 :
7888 i == Ydrip_s2 ? 16 :
7889 i == Ydrip_s2B ? 16 :
7890 i == Xsand_stonein_1 ? 32 :
7891 i == Xsand_stonein_2 ? 32 :
7892 i == Xsand_stonein_3 ? 32 :
7893 i == Xsand_stonein_4 ? 32 :
7894 i == Xsand_stoneout_1 ? 16 :
7895 i == Xsand_stoneout_2 ? 16 : 8);
7896 int cx = ABS(dx) * (TILEX / num_steps);
7897 int cy = ABS(dy) * (TILEY / num_steps);
7898 int step_frame = (i == Ydrip_s2 ? j + 8 :
7899 i == Ydrip_s2B ? j + 8 :
7900 i == Xsand_stonein_2 ? j + 8 :
7901 i == Xsand_stonein_3 ? j + 16 :
7902 i == Xsand_stonein_4 ? j + 24 :
7903 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7904 int step = (is_backside ? step_frame : num_steps - step_frame);
7906 if (is_backside) /* tile where movement starts */
7908 if (dx < 0 || dy < 0)
7910 g_em->src_offset_x = cx * step;
7911 g_em->src_offset_y = cy * step;
7915 g_em->dst_offset_x = cx * step;
7916 g_em->dst_offset_y = cy * step;
7919 else /* tile where movement ends */
7921 if (dx < 0 || dy < 0)
7923 g_em->dst_offset_x = cx * step;
7924 g_em->dst_offset_y = cy * step;
7928 g_em->src_offset_x = cx * step;
7929 g_em->src_offset_y = cy * step;
7933 g_em->width = TILEX - cx * step;
7934 g_em->height = TILEY - cy * step;
7937 /* create unique graphic identifier to decide if tile must be redrawn */
7938 /* bit 31 - 16 (16 bit): EM style graphic
7939 bit 15 - 12 ( 4 bit): EM style frame
7940 bit 11 - 6 ( 6 bit): graphic width
7941 bit 5 - 0 ( 6 bit): graphic height */
7942 g_em->unique_identifier =
7943 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7947 /* skip check for EMC elements not contained in original EMC artwork */
7948 if (element == EL_EMC_FAKE_ACID)
7951 if (g_em->bitmap != debug_bitmap ||
7952 g_em->src_x != debug_src_x ||
7953 g_em->src_y != debug_src_y ||
7954 g_em->src_offset_x != 0 ||
7955 g_em->src_offset_y != 0 ||
7956 g_em->dst_offset_x != 0 ||
7957 g_em->dst_offset_y != 0 ||
7958 g_em->width != TILEX ||
7959 g_em->height != TILEY)
7961 static int last_i = -1;
7969 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7970 i, element, element_info[element].token_name,
7971 element_action_info[effective_action].suffix, direction);
7973 if (element != effective_element)
7974 printf(" [%d ('%s')]",
7976 element_info[effective_element].token_name);
7980 if (g_em->bitmap != debug_bitmap)
7981 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7982 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7984 if (g_em->src_x != debug_src_x ||
7985 g_em->src_y != debug_src_y)
7986 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7987 j, (is_backside ? 'B' : 'F'),
7988 g_em->src_x, g_em->src_y,
7989 g_em->src_x / 32, g_em->src_y / 32,
7990 debug_src_x, debug_src_y,
7991 debug_src_x / 32, debug_src_y / 32);
7993 if (g_em->src_offset_x != 0 ||
7994 g_em->src_offset_y != 0 ||
7995 g_em->dst_offset_x != 0 ||
7996 g_em->dst_offset_y != 0)
7997 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7999 g_em->src_offset_x, g_em->src_offset_y,
8000 g_em->dst_offset_x, g_em->dst_offset_y);
8002 if (g_em->width != TILEX ||
8003 g_em->height != TILEY)
8004 printf(" %d (%d): size %d,%d should be %d,%d\n",
8006 g_em->width, g_em->height, TILEX, TILEY);
8008 num_em_gfx_errors++;
8015 for (i = 0; i < TILE_MAX; i++)
8017 for (j = 0; j < 8; j++)
8019 int element = object_mapping[i].element_rnd;
8020 int action = object_mapping[i].action;
8021 int direction = object_mapping[i].direction;
8022 boolean is_backside = object_mapping[i].is_backside;
8023 int graphic_action = el_act_dir2img(element, action, direction);
8024 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8026 if ((action == ACTION_SMASHED_BY_ROCK ||
8027 action == ACTION_SMASHED_BY_SPRING ||
8028 action == ACTION_EATING) &&
8029 graphic_action == graphic_default)
8031 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
8032 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8033 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
8034 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8037 /* no separate animation for "smashed by rock" -- use rock instead */
8038 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8039 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8041 g_em->bitmap = g_xx->bitmap;
8042 g_em->src_x = g_xx->src_x;
8043 g_em->src_y = g_xx->src_y;
8044 g_em->src_offset_x = g_xx->src_offset_x;
8045 g_em->src_offset_y = g_xx->src_offset_y;
8046 g_em->dst_offset_x = g_xx->dst_offset_x;
8047 g_em->dst_offset_y = g_xx->dst_offset_y;
8048 g_em->width = g_xx->width;
8049 g_em->height = g_xx->height;
8050 g_em->unique_identifier = g_xx->unique_identifier;
8053 g_em->preserve_background = TRUE;
8058 for (p = 0; p < MAX_PLAYERS; p++)
8060 for (i = 0; i < SPR_MAX; i++)
8062 int element = player_mapping[p][i].element_rnd;
8063 int action = player_mapping[p][i].action;
8064 int direction = player_mapping[p][i].direction;
8066 for (j = 0; j < 8; j++)
8068 int effective_element = element;
8069 int effective_action = action;
8070 int graphic = (direction == MV_NONE ?
8071 el_act2img(effective_element, effective_action) :
8072 el_act_dir2img(effective_element, effective_action,
8074 struct GraphicInfo *g = &graphic_info[graphic];
8075 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8081 Bitmap *debug_bitmap = g_em->bitmap;
8082 int debug_src_x = g_em->src_x;
8083 int debug_src_y = g_em->src_y;
8086 int frame = getAnimationFrame(g->anim_frames,
8089 g->anim_start_frame,
8092 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8094 g_em->bitmap = src_bitmap;
8095 g_em->src_x = src_x;
8096 g_em->src_y = src_y;
8097 g_em->src_offset_x = 0;
8098 g_em->src_offset_y = 0;
8099 g_em->dst_offset_x = 0;
8100 g_em->dst_offset_y = 0;
8101 g_em->width = TILEX;
8102 g_em->height = TILEY;
8106 /* skip check for EMC elements not contained in original EMC artwork */
8107 if (element == EL_PLAYER_3 ||
8108 element == EL_PLAYER_4)
8111 if (g_em->bitmap != debug_bitmap ||
8112 g_em->src_x != debug_src_x ||
8113 g_em->src_y != debug_src_y)
8115 static int last_i = -1;
8123 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8124 p, i, element, element_info[element].token_name,
8125 element_action_info[effective_action].suffix, direction);
8127 if (element != effective_element)
8128 printf(" [%d ('%s')]",
8130 element_info[effective_element].token_name);
8134 if (g_em->bitmap != debug_bitmap)
8135 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
8136 j, (int)(g_em->bitmap), (int)(debug_bitmap));
8138 if (g_em->src_x != debug_src_x ||
8139 g_em->src_y != debug_src_y)
8140 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8142 g_em->src_x, g_em->src_y,
8143 g_em->src_x / 32, g_em->src_y / 32,
8144 debug_src_x, debug_src_y,
8145 debug_src_x / 32, debug_src_y / 32);
8147 num_em_gfx_errors++;
8157 printf("::: [%d errors found]\n", num_em_gfx_errors);
8163 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8164 int graphic, int sync_frame, int x, int y)
8166 int frame = getGraphicAnimationFrame(graphic, sync_frame);
8168 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8171 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8173 return (IS_NEXT_FRAME(sync_frame, graphic));
8176 int getGraphicInfo_Delay(int graphic)
8178 return graphic_info[graphic].anim_delay;
8181 void PlayMenuSoundExt(int sound)
8183 if (sound == SND_UNDEFINED)
8186 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8187 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8190 if (IS_LOOP_SOUND(sound))
8191 PlaySoundLoop(sound);
8196 void PlayMenuSound()
8198 PlayMenuSoundExt(menu.sound[game_status]);
8201 void PlayMenuSoundStereo(int sound, int stereo_position)
8203 if (sound == SND_UNDEFINED)
8206 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8207 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8210 if (IS_LOOP_SOUND(sound))
8211 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8213 PlaySoundStereo(sound, stereo_position);
8216 void PlayMenuSoundIfLoopExt(int sound)
8218 if (sound == SND_UNDEFINED)
8221 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8222 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8225 if (IS_LOOP_SOUND(sound))
8226 PlaySoundLoop(sound);
8229 void PlayMenuSoundIfLoop()
8231 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8234 void PlayMenuMusicExt(int music)
8236 if (music == MUS_UNDEFINED)
8239 if (!setup.sound_music)
8245 void PlayMenuMusic()
8247 PlayMenuMusicExt(menu.music[game_status]);
8250 void PlaySoundActivating()
8253 PlaySound(SND_MENU_ITEM_ACTIVATING);
8257 void PlaySoundSelecting()
8260 PlaySound(SND_MENU_ITEM_SELECTING);
8264 void ToggleFullscreenIfNeeded()
8266 boolean change_fullscreen = (setup.fullscreen !=
8267 video.fullscreen_enabled);
8268 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8269 !strEqual(setup.fullscreen_mode,
8270 video.fullscreen_mode_current));
8272 if (!video.fullscreen_available)
8275 if (change_fullscreen || change_fullscreen_mode)
8277 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8279 /* save backbuffer content which gets lost when toggling fullscreen mode */
8280 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8282 if (change_fullscreen_mode)
8284 /* keep fullscreen, but change fullscreen mode (screen resolution) */
8285 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
8288 /* toggle fullscreen */
8289 ChangeVideoModeIfNeeded(setup.fullscreen);
8291 setup.fullscreen = video.fullscreen_enabled;
8293 /* restore backbuffer content from temporary backbuffer backup bitmap */
8294 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8296 FreeBitmap(tmp_backbuffer);
8299 /* update visible window/screen */
8300 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8302 redraw_mask = REDRAW_ALL;
8307 void ChangeViewportPropertiesIfNeeded()
8309 int *door_1_x = &DX;
8310 int *door_1_y = &DY;
8311 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
8312 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
8313 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
8314 game_status == GAME_MODE_EDITOR ? game_status :
8316 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8317 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8318 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
8319 int border_size = vp_playfield->border_size;
8320 int new_sx = vp_playfield->x + border_size;
8321 int new_sy = vp_playfield->y + border_size;
8322 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
8323 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
8326 /* !!! TEST ONLY !!! */
8327 // InitGfxBuffers();
8331 if (viewport.window.width != WIN_XSIZE ||
8332 viewport.window.height != WIN_YSIZE)
8334 WIN_XSIZE = viewport.window.width;
8335 WIN_YSIZE = viewport.window.height;
8337 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8341 SetDrawDeactivationMask(REDRAW_NONE);
8342 SetDrawBackgroundMask(REDRAW_FIELD);
8344 // RedrawBackground();
8348 if (new_scr_fieldx != SCR_FIELDX ||
8349 new_scr_fieldy != SCR_FIELDY ||
8352 vp_playfield->x != REAL_SX ||
8353 vp_playfield->y != REAL_SY ||
8354 vp_door_1->x != *door_1_x ||
8355 vp_door_1->y != *door_1_y ||
8356 vp_door_2->x != *door_2_x ||
8357 vp_door_2->y != *door_2_y)
8359 SCR_FIELDX = new_scr_fieldx;
8360 SCR_FIELDY = new_scr_fieldy;
8363 REAL_SX = vp_playfield->x;
8364 REAL_SY = vp_playfield->y;
8366 *door_1_x = vp_door_1->x;
8367 *door_1_y = vp_door_1->y;
8368 *door_2_x = vp_door_2->x;
8369 *door_2_y = vp_door_2->y;
8373 if (gfx_game_mode == GAME_MODE_MAIN)
8381 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);