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"
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX 0
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES 0
30 #define TOOL_CTRL_ID_NO 1
31 #define TOOL_CTRL_ID_CONFIRM 2
32 #define TOOL_CTRL_ID_PLAYER_1 3
33 #define TOOL_CTRL_ID_PLAYER_2 4
34 #define TOOL_CTRL_ID_PLAYER_3 5
35 #define TOOL_CTRL_ID_PLAYER_4 6
37 #define NUM_TOOL_BUTTONS 7
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
48 static char *print_if_not_empty(int element)
50 static char *s = NULL;
51 char *token_name = element_info[element].token_name;
56 s = checked_malloc(strlen(token_name) + 10 + 1);
58 if (element != EL_EMPTY)
59 sprintf(s, "%d\t['%s']", element, token_name);
61 sprintf(s, "%d", element);
66 void DumpTile(int x, int y)
71 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
78 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
81 if (!IN_LEV_FIELD(x, y))
83 printf("(not in level field)\n");
89 printf(" Feld: %d\t['%s']\n", Feld[x][y],
90 element_info[Feld[x][y]].token_name);
91 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
92 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
93 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
94 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95 printf(" MovPos: %d\n", MovPos[x][y]);
96 printf(" MovDir: %d\n", MovDir[x][y]);
97 printf(" MovDelay: %d\n", MovDelay[x][y]);
98 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
99 printf(" CustomValue: %d\n", CustomValue[x][y]);
100 printf(" GfxElement: %d\n", GfxElement[x][y]);
101 printf(" GfxAction: %d\n", GfxAction[x][y]);
102 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
106 void SetDrawtoField(int mode)
108 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
119 drawto_field = fieldbuffer;
121 else /* DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = backbuffer;
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
138 if (game_status == GAME_MODE_PLAYING &&
139 level.game_engine_type == GAME_ENGINE_TYPE_EM)
141 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING &&
148 level.game_engine_type == GAME_ENGINE_TYPE_SP)
150 /* currently there is no partial redraw -- always redraw whole playfield */
151 RedrawPlayfield_SP(TRUE);
153 /* blit playfield from scroll buffer to normal back buffer for fading in */
154 BlitScreenToBitmap_SP(backbuffer);
156 else if (game_status == GAME_MODE_PLAYING &&
157 !game.envelope_active)
163 width = gfx.sxsize + 2 * TILEX;
164 height = gfx.sysize + 2 * TILEY;
170 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
171 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
173 for (xx = BX1; xx <= BX2; xx++)
174 for (yy = BY1; yy <= BY2; yy++)
175 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
176 DrawScreenField(xx, yy);
180 if (setup.soft_scrolling)
182 int fx = FX, fy = FY;
184 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
185 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
187 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
199 BlitBitmap(drawto, window, x, y, width, height, x, y);
202 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
204 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
206 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
207 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
210 void DrawMaskedBorder_FIELD()
212 if (global.border_status >= GAME_MODE_TITLE &&
213 global.border_status <= GAME_MODE_PLAYING &&
214 border.draw_masked[global.border_status])
215 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
218 void DrawMaskedBorder_DOOR_1()
220 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
221 (global.border_status != GAME_MODE_EDITOR ||
222 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
223 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
226 void DrawMaskedBorder_DOOR_2()
228 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
229 global.border_status != GAME_MODE_EDITOR)
230 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
233 void DrawMaskedBorder_DOOR_3()
235 /* currently not available */
238 void DrawMaskedBorder_ALL()
240 DrawMaskedBorder_FIELD();
241 DrawMaskedBorder_DOOR_1();
242 DrawMaskedBorder_DOOR_2();
243 DrawMaskedBorder_DOOR_3();
246 void DrawMaskedBorder(int redraw_mask)
248 /* never draw masked screen borders on borderless screens */
249 if (effectiveGameStatus() == GAME_MODE_LOADING ||
250 effectiveGameStatus() == GAME_MODE_TITLE)
253 if (redraw_mask & REDRAW_ALL)
254 DrawMaskedBorder_ALL();
257 if (redraw_mask & REDRAW_FIELD)
258 DrawMaskedBorder_FIELD();
259 if (redraw_mask & REDRAW_DOOR_1)
260 DrawMaskedBorder_DOOR_1();
261 if (redraw_mask & REDRAW_DOOR_2)
262 DrawMaskedBorder_DOOR_2();
263 if (redraw_mask & REDRAW_DOOR_3)
264 DrawMaskedBorder_DOOR_3();
271 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
274 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
275 for (x = 0; x < SCR_FIELDX; x++)
276 for (y = 0 ; y < SCR_FIELDY; y++)
277 if (redraw[redraw_x1 + x][redraw_y1 + y])
278 printf("::: - %d, %d [%s]\n",
279 LEVELX(x), LEVELY(y),
280 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
283 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
284 redraw_mask |= REDRAW_FIELD;
286 if (redraw_mask & REDRAW_FIELD)
287 redraw_mask &= ~REDRAW_TILES;
289 if (redraw_mask == REDRAW_NONE)
292 if (redraw_mask & REDRAW_TILES &&
293 game_status == GAME_MODE_PLAYING &&
294 border.draw_masked[GAME_MODE_PLAYING])
295 redraw_mask |= REDRAW_FIELD;
297 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
299 static boolean last_frame_skipped = FALSE;
300 boolean skip_even_when_not_scrolling = TRUE;
301 boolean just_scrolling = (ScreenMovDir != 0);
302 boolean verbose = FALSE;
304 if (global.fps_slowdown_factor > 1 &&
305 (FrameCounter % global.fps_slowdown_factor) &&
306 (just_scrolling || skip_even_when_not_scrolling))
308 redraw_mask &= ~REDRAW_MAIN;
310 last_frame_skipped = TRUE;
313 printf("FRAME SKIPPED\n");
317 if (last_frame_skipped)
318 redraw_mask |= REDRAW_FIELD;
320 last_frame_skipped = FALSE;
323 printf("frame not skipped\n");
327 /* synchronize X11 graphics at this point; if we would synchronize the
328 display immediately after the buffer switching (after the XFlush),
329 this could mean that we have to wait for the graphics to complete,
330 although we could go on doing calculations for the next frame */
334 /* prevent drawing masked border to backbuffer when using playfield buffer */
335 if (game_status != GAME_MODE_PLAYING ||
336 redraw_mask & REDRAW_FROM_BACKBUFFER ||
337 buffer == backbuffer)
338 DrawMaskedBorder(redraw_mask);
340 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
342 if (redraw_mask & REDRAW_ALL)
344 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
346 redraw_mask = REDRAW_NONE;
349 if (redraw_mask & REDRAW_FIELD)
351 if (game_status != GAME_MODE_PLAYING ||
352 redraw_mask & REDRAW_FROM_BACKBUFFER)
354 BlitBitmap(backbuffer, window,
355 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
359 int fx = FX, fy = FY;
361 if (setup.soft_scrolling)
363 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
364 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
367 if (setup.soft_scrolling ||
368 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
369 ABS(ScreenMovPos) == ScrollStepSize ||
370 redraw_tiles > REDRAWTILES_THRESHOLD)
372 if (border.draw_masked[GAME_MODE_PLAYING])
374 if (buffer != backbuffer)
376 /* copy playfield buffer to backbuffer to add masked border */
377 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
378 DrawMaskedBorder(REDRAW_FIELD);
381 BlitBitmap(backbuffer, window,
382 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
387 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
392 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
394 (setup.soft_scrolling ?
395 "setup.soft_scrolling" :
396 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
397 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
398 ABS(ScreenGfxPos) == ScrollStepSize ?
399 "ABS(ScreenGfxPos) == ScrollStepSize" :
400 "redraw_tiles > REDRAWTILES_THRESHOLD"));
406 redraw_mask &= ~REDRAW_MAIN;
409 if (redraw_mask & REDRAW_DOORS)
411 if (redraw_mask & REDRAW_DOOR_1)
412 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
414 if (redraw_mask & REDRAW_DOOR_2)
415 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
417 if (redraw_mask & REDRAW_DOOR_3)
418 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
420 redraw_mask &= ~REDRAW_DOORS;
423 if (redraw_mask & REDRAW_MICROLEVEL)
425 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
426 SX, SY + 10 * TILEY);
428 redraw_mask &= ~REDRAW_MICROLEVEL;
431 if (redraw_mask & REDRAW_TILES)
433 for (x = 0; x < SCR_FIELDX; x++)
434 for (y = 0 ; y < SCR_FIELDY; y++)
435 if (redraw[redraw_x1 + x][redraw_y1 + y])
436 BlitBitmap(buffer, window,
437 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
438 SX + x * TILEX, SY + y * TILEY);
441 if (redraw_mask & REDRAW_FPS) /* display frames per second */
446 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
447 if (!global.fps_slowdown)
450 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
452 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
454 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
460 for (x = 0; x < MAX_BUF_XSIZE; x++)
461 for (y = 0; y < MAX_BUF_YSIZE; y++)
464 redraw_mask = REDRAW_NONE;
467 static void FadeCrossSaveBackbuffer()
469 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
472 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
474 static int fade_type_skip = FADE_TYPE_NONE;
475 void (*draw_border_function)(void) = NULL;
476 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
477 int x, y, width, height;
478 int fade_delay, post_delay;
480 if (fade_type == FADE_TYPE_FADE_OUT)
482 if (fade_type_skip != FADE_TYPE_NONE)
485 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
488 /* skip all fade operations until specified fade operation */
489 if (fade_type & fade_type_skip)
490 fade_type_skip = FADE_TYPE_NONE;
495 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
497 FadeCrossSaveBackbuffer();
503 redraw_mask |= fade_mask;
505 if (fade_type == FADE_TYPE_SKIP)
508 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
511 fade_type_skip = fade_mode;
517 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
522 fade_delay = fading.fade_delay;
523 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
526 if (fade_type_skip != FADE_TYPE_NONE)
529 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
532 /* skip all fade operations until specified fade operation */
533 if (fade_type & fade_type_skip)
534 fade_type_skip = FADE_TYPE_NONE;
544 if (global.autoplay_leveldir)
546 // fading.fade_mode = FADE_MODE_NONE;
553 if (fading.fade_mode == FADE_MODE_NONE)
561 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
564 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
568 if (fade_mask == REDRAW_NONE)
569 fade_mask = REDRAW_FIELD;
572 // if (fade_mask & REDRAW_FIELD)
573 if (fade_mask == REDRAW_FIELD)
578 height = FULL_SYSIZE;
581 fade_delay = fading.fade_delay;
582 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
585 if (border.draw_masked_when_fading)
586 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
588 DrawMaskedBorder_FIELD(); /* draw once */
590 else /* REDRAW_ALL */
598 fade_delay = fading.fade_delay;
599 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
604 if (!setup.fade_screens ||
606 fading.fade_mode == FADE_MODE_NONE)
608 if (!setup.fade_screens || fade_delay == 0)
611 if (fade_mode == FADE_MODE_FADE_OUT)
615 if (fade_mode == FADE_MODE_FADE_OUT &&
616 fading.fade_mode != FADE_MODE_NONE)
617 ClearRectangle(backbuffer, x, y, width, height);
621 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
622 redraw_mask = REDRAW_NONE;
630 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
631 draw_border_function);
633 redraw_mask &= ~fade_mask;
636 void FadeIn(int fade_mask)
638 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
639 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
641 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
644 void FadeOut(int fade_mask)
646 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
647 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
649 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
651 global.border_status = game_status;
654 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
656 static struct TitleFadingInfo fading_leave_stored;
659 fading_leave_stored = fading_leave;
661 fading = fading_leave_stored;
664 void FadeSetEnterMenu()
666 fading = menu.enter_menu;
669 printf("::: storing enter_menu\n");
672 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
675 void FadeSetLeaveMenu()
677 fading = menu.leave_menu;
680 printf("::: storing leave_menu\n");
683 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
686 void FadeSetEnterScreen()
688 fading = menu.enter_screen[game_status];
691 printf("::: storing leave_screen[%d]\n", game_status);
694 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
697 void FadeSetNextScreen()
699 fading = menu.next_screen;
702 printf("::: storing next_screen\n");
705 // (do not overwrite fade mode set by FadeSetEnterScreen)
706 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
709 void FadeSetLeaveScreen()
712 printf("::: recalling last stored value\n");
715 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
718 void FadeSetFromType(int type)
720 if (type & TYPE_ENTER_SCREEN)
721 FadeSetEnterScreen();
722 else if (type & TYPE_ENTER)
724 else if (type & TYPE_LEAVE)
728 void FadeSetDisabled()
730 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
732 fading = fading_none;
735 void FadeSkipNextFadeIn()
737 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
740 void FadeSkipNextFadeOut()
742 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
745 void SetWindowBackgroundImageIfDefined(int graphic)
747 if (graphic_info[graphic].bitmap)
748 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
751 void SetMainBackgroundImageIfDefined(int graphic)
753 if (graphic_info[graphic].bitmap)
754 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
757 void SetDoorBackgroundImageIfDefined(int graphic)
759 if (graphic_info[graphic].bitmap)
760 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
763 void SetWindowBackgroundImage(int graphic)
765 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
766 graphic_info[graphic].bitmap ?
767 graphic_info[graphic].bitmap :
768 graphic_info[IMG_BACKGROUND].bitmap);
771 void SetMainBackgroundImage(int graphic)
773 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
774 graphic_info[graphic].bitmap ?
775 graphic_info[graphic].bitmap :
776 graphic_info[IMG_BACKGROUND].bitmap);
779 void SetDoorBackgroundImage(int graphic)
781 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
782 graphic_info[graphic].bitmap ?
783 graphic_info[graphic].bitmap :
784 graphic_info[IMG_BACKGROUND].bitmap);
787 void SetPanelBackground()
789 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
790 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
792 SetDoorBackgroundBitmap(bitmap_db_panel);
795 void DrawBackground(int x, int y, int width, int height)
797 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
798 /* (when entering hall of fame after playing) */
800 ClearRectangleOnBackground(drawto, x, y, width, height);
802 ClearRectangleOnBackground(backbuffer, x, y, width, height);
805 redraw_mask |= REDRAW_FIELD;
808 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
810 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
812 if (font->bitmap == NULL)
815 DrawBackground(x, y, width, height);
818 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
820 struct GraphicInfo *g = &graphic_info[graphic];
822 if (g->bitmap == NULL)
825 DrawBackground(x, y, width, height);
830 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
831 /* (when entering hall of fame after playing) */
832 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
834 /* !!! maybe this should be done before clearing the background !!! */
835 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
837 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
838 SetDrawtoField(DRAW_BUFFERED);
841 SetDrawtoField(DRAW_BACKBUFFER);
844 void MarkTileDirty(int x, int y)
846 int xx = redraw_x1 + x;
847 int yy = redraw_y1 + y;
852 redraw[xx][yy] = TRUE;
853 redraw_mask |= REDRAW_TILES;
856 void SetBorderElement()
860 BorderElement = EL_EMPTY;
862 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
864 for (x = 0; x < lev_fieldx; x++)
866 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
867 BorderElement = EL_STEELWALL;
869 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
875 void FloodFillLevel(int from_x, int from_y, int fill_element,
876 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
877 int max_fieldx, int max_fieldy)
881 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
882 static int safety = 0;
884 /* check if starting field still has the desired content */
885 if (field[from_x][from_y] == fill_element)
890 if (safety > max_fieldx * max_fieldy)
891 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
893 old_element = field[from_x][from_y];
894 field[from_x][from_y] = fill_element;
896 for (i = 0; i < 4; i++)
898 x = from_x + check[i][0];
899 y = from_y + check[i][1];
901 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
902 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
908 void SetRandomAnimationValue(int x, int y)
910 gfx.anim_random_frame = GfxRandom[x][y];
913 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
915 /* animation synchronized with global frame counter, not move position */
916 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
917 sync_frame = FrameCounter;
919 return getAnimationFrame(graphic_info[graphic].anim_frames,
920 graphic_info[graphic].anim_delay,
921 graphic_info[graphic].anim_mode,
922 graphic_info[graphic].anim_start_frame,
926 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
927 Bitmap **bitmap, int *x, int *y)
931 int width_mult, width_div;
932 int height_mult, height_div;
936 { 15, 16, 2, 3 }, /* 1 x 1 */
937 { 7, 8, 2, 3 }, /* 2 x 2 */
938 { 3, 4, 2, 3 }, /* 4 x 4 */
939 { 1, 2, 2, 3 }, /* 8 x 8 */
940 { 0, 1, 2, 3 }, /* 16 x 16 */
941 { 0, 1, 0, 1 }, /* 32 x 32 */
943 struct GraphicInfo *g = &graphic_info[graphic];
944 Bitmap *src_bitmap = g->bitmap;
945 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
946 int offset_calc_pos = log_2(tilesize);
947 int width_mult = offset_calc[offset_calc_pos].width_mult;
948 int width_div = offset_calc[offset_calc_pos].width_div;
949 int height_mult = offset_calc[offset_calc_pos].height_mult;
950 int height_div = offset_calc[offset_calc_pos].height_div;
951 int startx = src_bitmap->width * width_mult / width_div;
952 int starty = src_bitmap->height * height_mult / height_div;
953 int src_x = g->src_x * tilesize / TILESIZE;
954 int src_y = g->src_y * tilesize / TILESIZE;
955 int width = g->width * tilesize / TILESIZE;
956 int height = g->height * tilesize / TILESIZE;
957 int offset_x = g->offset_x * tilesize / TILESIZE;
958 int offset_y = g->offset_y * tilesize / TILESIZE;
960 if (g->offset_y == 0) /* frames are ordered horizontally */
962 int max_width = g->anim_frames_per_line * width;
963 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
965 src_x = pos % max_width;
966 src_y = src_y % height + pos / max_width * height;
968 else if (g->offset_x == 0) /* frames are ordered vertically */
970 int max_height = g->anim_frames_per_line * height;
971 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
973 src_x = src_x % width + pos / max_height * width;
974 src_y = pos % max_height;
976 else /* frames are ordered diagonally */
978 src_x = src_x + frame * offset_x;
979 src_y = src_y + frame * offset_y;
982 *bitmap = src_bitmap;
987 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
990 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
992 struct GraphicInfo *g = &graphic_info[graphic];
994 int mini_starty = g->bitmap->height * 2 / 3;
997 *x = mini_startx + g->src_x / 2;
998 *y = mini_starty + g->src_y / 2;
1002 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1003 int *x, int *y, boolean get_backside)
1005 struct GraphicInfo *g = &graphic_info[graphic];
1006 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1007 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1009 *bitmap = g->bitmap;
1011 if (g->offset_y == 0) /* frames are ordered horizontally */
1013 int max_width = g->anim_frames_per_line * g->width;
1014 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1016 *x = pos % max_width;
1017 *y = src_y % g->height + pos / max_width * g->height;
1019 else if (g->offset_x == 0) /* frames are ordered vertically */
1021 int max_height = g->anim_frames_per_line * g->height;
1022 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1024 *x = src_x % g->width + pos / max_height * g->width;
1025 *y = pos % max_height;
1027 else /* frames are ordered diagonally */
1029 *x = src_x + frame * g->offset_x;
1030 *y = src_y + frame * g->offset_y;
1034 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1036 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1039 void DrawGraphic(int x, int y, int graphic, int frame)
1042 if (!IN_SCR_FIELD(x, y))
1044 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1045 printf("DrawGraphic(): This should never happen!\n");
1050 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1051 MarkTileDirty(x, y);
1054 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1060 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1061 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1064 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1067 if (!IN_SCR_FIELD(x, y))
1069 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1070 printf("DrawGraphicThruMask(): This should never happen!\n");
1075 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1077 MarkTileDirty(x, y);
1080 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1086 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1088 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1089 dst_x - src_x, dst_y - src_y);
1090 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1093 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1095 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1097 MarkTileDirty(x / tilesize, y / tilesize);
1100 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1106 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1107 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1110 void DrawMiniGraphic(int x, int y, int graphic)
1112 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1113 MarkTileDirty(x / 2, y / 2);
1116 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1121 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1122 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1125 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1126 int graphic, int frame,
1127 int cut_mode, int mask_mode)
1132 int width = TILEX, height = TILEY;
1135 if (dx || dy) /* shifted graphic */
1137 if (x < BX1) /* object enters playfield from the left */
1144 else if (x > BX2) /* object enters playfield from the right */
1150 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1156 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1158 else if (dx) /* general horizontal movement */
1159 MarkTileDirty(x + SIGN(dx), y);
1161 if (y < BY1) /* object enters playfield from the top */
1163 if (cut_mode==CUT_BELOW) /* object completely above top border */
1171 else if (y > BY2) /* object enters playfield from the bottom */
1177 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1183 else if (dy > 0 && cut_mode == CUT_ABOVE)
1185 if (y == BY2) /* object completely above bottom border */
1191 MarkTileDirty(x, y + 1);
1192 } /* object leaves playfield to the bottom */
1193 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1195 else if (dy) /* general vertical movement */
1196 MarkTileDirty(x, y + SIGN(dy));
1200 if (!IN_SCR_FIELD(x, y))
1202 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1203 printf("DrawGraphicShifted(): This should never happen!\n");
1208 if (width > 0 && height > 0)
1210 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1215 dst_x = FX + x * TILEX + dx;
1216 dst_y = FY + y * TILEY + dy;
1218 if (mask_mode == USE_MASKING)
1220 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1221 dst_x - src_x, dst_y - src_y);
1222 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1226 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1229 MarkTileDirty(x, y);
1233 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1234 int graphic, int frame,
1235 int cut_mode, int mask_mode)
1240 int width = TILEX, height = TILEY;
1243 int x2 = x + SIGN(dx);
1244 int y2 = y + SIGN(dy);
1246 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1247 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1249 /* movement with two-tile animations must be sync'ed with movement position,
1250 not with current GfxFrame (which can be higher when using slow movement) */
1251 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1252 int anim_frames = graphic_info[graphic].anim_frames;
1254 /* (we also need anim_delay here for movement animations with less frames) */
1255 int anim_delay = graphic_info[graphic].anim_delay;
1256 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1258 int sync_frame = anim_pos * anim_frames / TILESIZE;
1261 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1262 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1264 /* re-calculate animation frame for two-tile movement animation */
1265 frame = getGraphicAnimationFrame(graphic, sync_frame);
1269 printf("::: %d, %d, %d => %d [%d]\n",
1270 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1272 printf("::: %d, %d => %d\n",
1273 anim_pos, anim_frames, sync_frame);
1278 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1279 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1282 /* check if movement start graphic inside screen area and should be drawn */
1283 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1285 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1287 dst_x = FX + x1 * TILEX;
1288 dst_y = FY + y1 * TILEY;
1290 if (mask_mode == USE_MASKING)
1292 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1293 dst_x - src_x, dst_y - src_y);
1294 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1298 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1301 MarkTileDirty(x1, y1);
1304 /* check if movement end graphic inside screen area and should be drawn */
1305 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1307 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1309 dst_x = FX + x2 * TILEX;
1310 dst_y = FY + y2 * TILEY;
1312 if (mask_mode == USE_MASKING)
1314 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1315 dst_x - src_x, dst_y - src_y);
1316 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1320 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1323 MarkTileDirty(x2, y2);
1327 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1328 int graphic, int frame,
1329 int cut_mode, int mask_mode)
1333 DrawGraphic(x, y, graphic, frame);
1338 if (graphic_info[graphic].double_movement) /* EM style movement images */
1339 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1341 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1344 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1345 int frame, int cut_mode)
1347 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1350 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1351 int cut_mode, int mask_mode)
1353 int lx = LEVELX(x), ly = LEVELY(y);
1357 if (IN_LEV_FIELD(lx, ly))
1359 SetRandomAnimationValue(lx, ly);
1361 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1362 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1364 /* do not use double (EM style) movement graphic when not moving */
1365 if (graphic_info[graphic].double_movement && !dx && !dy)
1367 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1368 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1371 else /* border element */
1373 graphic = el2img(element);
1374 frame = getGraphicAnimationFrame(graphic, -1);
1377 if (element == EL_EXPANDABLE_WALL)
1379 boolean left_stopped = FALSE, right_stopped = FALSE;
1381 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1382 left_stopped = TRUE;
1383 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1384 right_stopped = TRUE;
1386 if (left_stopped && right_stopped)
1388 else if (left_stopped)
1390 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1391 frame = graphic_info[graphic].anim_frames - 1;
1393 else if (right_stopped)
1395 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1396 frame = graphic_info[graphic].anim_frames - 1;
1401 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1402 else if (mask_mode == USE_MASKING)
1403 DrawGraphicThruMask(x, y, graphic, frame);
1405 DrawGraphic(x, y, graphic, frame);
1408 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1409 int cut_mode, int mask_mode)
1411 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1412 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1413 cut_mode, mask_mode);
1416 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1419 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1422 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1425 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1428 void DrawLevelElementThruMask(int x, int y, int element)
1430 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1433 void DrawLevelFieldThruMask(int x, int y)
1435 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1438 /* !!! implementation of quicksand is totally broken !!! */
1439 #define IS_CRUMBLED_TILE(x, y, e) \
1440 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1441 !IS_MOVING(x, y) || \
1442 (e) == EL_QUICKSAND_EMPTYING || \
1443 (e) == EL_QUICKSAND_FAST_EMPTYING))
1445 static void DrawLevelFieldCrumbledSandExtBlitInner(int x, int y, int dx, int dy,
1450 int width, height, cx, cy;
1451 int sx = SCREENX(x), sy = SCREENY(y);
1452 int crumbled_border_size = graphic_info[graphic].border_size;
1455 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1457 for (i = 1; i < 4; i++)
1459 int dxx = (i & 1 ? dx : 0);
1460 int dyy = (i & 2 ? dy : 0);
1463 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1466 /* check if neighbour field is of same crumble type */
1467 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1468 graphic_info[graphic].class ==
1469 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1471 /* return if check prevents inner corner */
1472 if (same == (dxx == dx && dyy == dy))
1476 /* if we reach this point, we have an inner corner */
1478 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1480 width = crumbled_border_size;
1481 height = crumbled_border_size;
1482 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1483 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1485 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1486 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1489 static void DrawLevelFieldCrumbledSandExtBlit(int x, int y,
1490 int graphic, int frame, int dir)
1494 int width, height, bx, by, cx, cy;
1495 int sx = SCREENX(x), sy = SCREENY(y);
1496 int crumbled_border_size = graphic_info[graphic].border_size;
1499 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1501 /* draw simple, sloppy, non-corner-accurate crumbled border */
1504 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1505 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1506 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1507 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1509 if (dir == 1 || dir == 2) /* left or right crumbled border */
1511 width = crumbled_border_size;
1513 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1516 else /* top or bottom crumbled border */
1519 height = crumbled_border_size;
1521 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1525 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1526 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1528 /* (remaining middle border part must be at least as big as corner part) */
1529 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1530 crumbled_border_size >= TILESIZE / 3)
1533 /* correct corners of crumbled border, if needed */
1536 for (i = -1; i <= 1; i+=2)
1538 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1539 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1540 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1545 /* check if neighbour field is of same crumble type */
1546 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1547 graphic_info[graphic].class ==
1548 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1550 /* no crumbled corner, but continued crumbled border */
1552 width = crumbled_border_size;
1553 height = crumbled_border_size;
1554 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1555 cy = (i == 1 ? TILEX - crumbled_border_size : 0);
1557 by = (i == 1 ? crumbled_border_size :
1558 TILEY - 2 * crumbled_border_size);
1560 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1561 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1565 if (dir == 1 || dir == 2) /* left or right crumbled border */
1567 for (i = -1; i <= 1; i+=2)
1571 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1574 /* check if neighbour field is of same crumble type */
1575 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1576 graphic_info[graphic].class ==
1577 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1579 /* no crumbled corner, but continued crumbled border */
1581 width = crumbled_border_size;
1582 height = crumbled_border_size;
1583 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1584 cy = (i == 1 ? TILEX - crumbled_border_size : 0);
1586 by = (i == 1 ? crumbled_border_size :
1587 TILEY - 2 * crumbled_border_size);
1589 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1590 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1594 else /* top or bottom crumbled border */
1596 for (i = -1; i <= 1; i+=2)
1600 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1603 /* check if neighbour field is of same crumble type */
1604 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1605 graphic_info[graphic].class ==
1606 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1608 /* no crumbled corner, but continued crumbled border */
1610 width = crumbled_border_size;
1611 height = crumbled_border_size;
1612 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1613 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1614 bx = (i == 1 ? crumbled_border_size :
1615 TILEY - 2 * crumbled_border_size);
1618 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1619 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1626 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1628 int sx = SCREENX(x), sy = SCREENY(y);
1631 static int xy[4][2] =
1639 if (!IN_LEV_FIELD(x, y))
1642 element = TILE_GFX_ELEMENT(x, y);
1644 /* crumble field itself */
1645 if (IS_CRUMBLED_TILE(x, y, element))
1647 if (!IN_SCR_FIELD(sx, sy))
1650 for (i = 0; i < 4; i++)
1652 int xx = x + xy[i][0];
1653 int yy = y + xy[i][1];
1655 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1658 /* check if neighbour field is of same crumble type */
1660 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1661 graphic_info[graphic].class ==
1662 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1665 if (IS_CRUMBLED_TILE(xx, yy, element))
1669 DrawLevelFieldCrumbledSandExtBlit(x, y, graphic, frame, i);
1672 if ((graphic_info[graphic].style & STYLE_WITH_INNER_CORNERS) &&
1673 graphic_info[graphic].anim_frames == 2)
1675 for (i = 0; i < 4; i++)
1677 int dx = (i & 1 ? +1 : -1);
1678 int dy = (i & 2 ? +1 : -1);
1680 DrawLevelFieldCrumbledSandExtBlitInner(x, y, dx, dy, graphic);
1684 MarkTileDirty(sx, sy);
1686 else /* center field not crumbled -- crumble neighbour fields */
1688 for (i = 0; i < 4; i++)
1690 int xx = x + xy[i][0];
1691 int yy = y + xy[i][1];
1692 int sxx = sx + xy[i][0];
1693 int syy = sy + xy[i][1];
1695 if (!IN_LEV_FIELD(xx, yy) ||
1696 !IN_SCR_FIELD(sxx, syy))
1699 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1702 element = TILE_GFX_ELEMENT(xx, yy);
1704 if (!IS_CRUMBLED_TILE(xx, yy, element))
1707 graphic = el_act2crm(element, ACTION_DEFAULT);
1709 DrawLevelFieldCrumbledSandExtBlit(xx, yy, graphic, 0, 3 - i);
1711 MarkTileDirty(sxx, syy);
1716 void DrawLevelFieldCrumbledSand(int x, int y)
1720 if (!IN_LEV_FIELD(x, y))
1724 /* !!! CHECK THIS !!! */
1727 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1728 GFX_CRUMBLED(GfxElement[x][y]))
1731 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1732 GfxElement[x][y] != EL_UNDEFINED &&
1733 GFX_CRUMBLED(GfxElement[x][y]))
1735 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1742 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1744 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1747 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1750 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1753 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1754 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1755 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1756 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1757 int sx = SCREENX(x), sy = SCREENY(y);
1759 DrawGraphic(sx, sy, graphic1, frame1);
1760 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1763 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1765 int sx = SCREENX(x), sy = SCREENY(y);
1766 static int xy[4][2] =
1776 int element = TILE_GFX_ELEMENT(x, y);
1777 int graphic = el_act2crm(element, ACTION_DEFAULT);
1779 if (graphic_info[graphic].style & STYLE_WITH_INNER_CORNERS)
1783 for (dy = -1; dy < 2; dy++)
1785 for (dx = -1; dx < 2; dx++)
1787 if (dx != 0 || dy != 0)
1794 if (!IN_LEV_FIELD(xx, yy) ||
1795 !IN_SCR_FIELD(sxx, syy) ||
1796 !GFX_CRUMBLED(Feld[xx][yy]) ||
1800 DrawLevelField(xx, yy);
1807 for (i = 0; i < 4; i++)
1809 int xx = x + xy[i][0];
1810 int yy = y + xy[i][1];
1811 int sxx = sx + xy[i][0];
1812 int syy = sy + xy[i][1];
1814 if (!IN_LEV_FIELD(xx, yy) ||
1815 !IN_SCR_FIELD(sxx, syy) ||
1816 !GFX_CRUMBLED(Feld[xx][yy]) ||
1820 DrawLevelField(xx, yy);
1824 for (i = 0; i < 4; i++)
1826 int xx = x + xy[i][0];
1827 int yy = y + xy[i][1];
1828 int sxx = sx + xy[i][0];
1829 int syy = sy + xy[i][1];
1831 if (!IN_LEV_FIELD(xx, yy) ||
1832 !IN_SCR_FIELD(sxx, syy) ||
1833 !GFX_CRUMBLED(Feld[xx][yy]) ||
1837 DrawLevelField(xx, yy);
1842 static int getBorderElement(int x, int y)
1846 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1847 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1848 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1849 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1850 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1851 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1852 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1854 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1855 int steel_position = (x == -1 && y == -1 ? 0 :
1856 x == lev_fieldx && y == -1 ? 1 :
1857 x == -1 && y == lev_fieldy ? 2 :
1858 x == lev_fieldx && y == lev_fieldy ? 3 :
1859 x == -1 || x == lev_fieldx ? 4 :
1860 y == -1 || y == lev_fieldy ? 5 : 6);
1862 return border[steel_position][steel_type];
1865 void DrawScreenElement(int x, int y, int element)
1867 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1868 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1871 void DrawLevelElement(int x, int y, int element)
1873 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1874 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1877 void DrawScreenField(int x, int y)
1879 int lx = LEVELX(x), ly = LEVELY(y);
1880 int element, content;
1882 if (!IN_LEV_FIELD(lx, ly))
1884 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1887 element = getBorderElement(lx, ly);
1889 DrawScreenElement(x, y, element);
1894 element = Feld[lx][ly];
1895 content = Store[lx][ly];
1897 if (IS_MOVING(lx, ly))
1899 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1900 boolean cut_mode = NO_CUTTING;
1902 if (element == EL_QUICKSAND_EMPTYING ||
1903 element == EL_QUICKSAND_FAST_EMPTYING ||
1904 element == EL_MAGIC_WALL_EMPTYING ||
1905 element == EL_BD_MAGIC_WALL_EMPTYING ||
1906 element == EL_DC_MAGIC_WALL_EMPTYING ||
1907 element == EL_AMOEBA_DROPPING)
1908 cut_mode = CUT_ABOVE;
1909 else if (element == EL_QUICKSAND_FILLING ||
1910 element == EL_QUICKSAND_FAST_FILLING ||
1911 element == EL_MAGIC_WALL_FILLING ||
1912 element == EL_BD_MAGIC_WALL_FILLING ||
1913 element == EL_DC_MAGIC_WALL_FILLING)
1914 cut_mode = CUT_BELOW;
1917 if (lx == 9 && ly == 1)
1918 printf("::: %s [%d] [%d, %d] [%d]\n",
1919 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1920 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1921 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1922 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1923 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1926 if (cut_mode == CUT_ABOVE)
1928 DrawScreenElement(x, y, element);
1930 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1933 DrawScreenElement(x, y, EL_EMPTY);
1936 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1937 else if (cut_mode == NO_CUTTING)
1938 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1941 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1944 if (cut_mode == CUT_BELOW &&
1945 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1946 DrawLevelElement(lx, ly + 1, element);
1950 if (content == EL_ACID)
1952 int dir = MovDir[lx][ly];
1953 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1954 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1956 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1959 else if (IS_BLOCKED(lx, ly))
1964 boolean cut_mode = NO_CUTTING;
1965 int element_old, content_old;
1967 Blocked2Moving(lx, ly, &oldx, &oldy);
1970 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1971 MovDir[oldx][oldy] == MV_RIGHT);
1973 element_old = Feld[oldx][oldy];
1974 content_old = Store[oldx][oldy];
1976 if (element_old == EL_QUICKSAND_EMPTYING ||
1977 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1978 element_old == EL_MAGIC_WALL_EMPTYING ||
1979 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1980 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1981 element_old == EL_AMOEBA_DROPPING)
1982 cut_mode = CUT_ABOVE;
1984 DrawScreenElement(x, y, EL_EMPTY);
1987 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1989 else if (cut_mode == NO_CUTTING)
1990 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1993 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1996 else if (IS_DRAWABLE(element))
1997 DrawScreenElement(x, y, element);
1999 DrawScreenElement(x, y, EL_EMPTY);
2002 void DrawLevelField(int x, int y)
2004 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2005 DrawScreenField(SCREENX(x), SCREENY(y));
2006 else if (IS_MOVING(x, y))
2010 Moving2Blocked(x, y, &newx, &newy);
2011 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2012 DrawScreenField(SCREENX(newx), SCREENY(newy));
2014 else if (IS_BLOCKED(x, y))
2018 Blocked2Moving(x, y, &oldx, &oldy);
2019 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2020 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2024 void DrawMiniElement(int x, int y, int element)
2028 graphic = el2edimg(element);
2029 DrawMiniGraphic(x, y, graphic);
2032 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2034 int x = sx + scroll_x, y = sy + scroll_y;
2036 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2037 DrawMiniElement(sx, sy, EL_EMPTY);
2038 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2039 DrawMiniElement(sx, sy, Feld[x][y]);
2041 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2044 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
2045 int x, int y, int xsize, int ysize, int font_nr)
2047 int font_width = getFontWidth(font_nr);
2048 int font_height = getFontHeight(font_nr);
2049 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2052 int dst_x = SX + startx + x * font_width;
2053 int dst_y = SY + starty + y * font_height;
2054 int width = graphic_info[graphic].width;
2055 int height = graphic_info[graphic].height;
2056 int inner_width = MAX(width - 2 * font_width, font_width);
2057 int inner_height = MAX(height - 2 * font_height, font_height);
2058 int inner_sx = (width >= 3 * font_width ? font_width : 0);
2059 int inner_sy = (height >= 3 * font_height ? font_height : 0);
2060 boolean draw_masked = graphic_info[graphic].draw_masked;
2062 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2064 if (src_bitmap == NULL || width < font_width || height < font_height)
2066 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
2070 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
2071 inner_sx + (x - 1) * font_width % inner_width);
2072 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
2073 inner_sy + (y - 1) * font_height % inner_height);
2077 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2078 dst_x - src_x, dst_y - src_y);
2079 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2083 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2087 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2089 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2090 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2091 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2092 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2093 boolean no_delay = (tape.warp_forward);
2094 unsigned long anim_delay = 0;
2095 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2096 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2097 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2098 int font_width = getFontWidth(font_nr);
2099 int font_height = getFontHeight(font_nr);
2100 int max_xsize = level.envelope[envelope_nr].xsize;
2101 int max_ysize = level.envelope[envelope_nr].ysize;
2102 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2103 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2104 int xend = max_xsize;
2105 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2106 int xstep = (xstart < xend ? 1 : 0);
2107 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2110 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2112 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2113 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2114 int sx = (SXSIZE - xsize * font_width) / 2;
2115 int sy = (SYSIZE - ysize * font_height) / 2;
2118 SetDrawtoField(DRAW_BUFFERED);
2120 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2122 SetDrawtoField(DRAW_BACKBUFFER);
2124 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2125 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2128 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2129 level.envelope[envelope_nr].text, font_nr, max_xsize,
2130 xsize - 2, ysize - 2, mask_mode,
2131 level.envelope[envelope_nr].autowrap,
2132 level.envelope[envelope_nr].centered, FALSE);
2134 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2135 level.envelope[envelope_nr].text, font_nr, max_xsize,
2136 xsize - 2, ysize - 2, mask_mode);
2139 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2142 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2146 void ShowEnvelope(int envelope_nr)
2148 int element = EL_ENVELOPE_1 + envelope_nr;
2149 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2150 int sound_opening = element_info[element].sound[ACTION_OPENING];
2151 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2152 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2153 boolean no_delay = (tape.warp_forward);
2154 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2155 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2156 int anim_mode = graphic_info[graphic].anim_mode;
2157 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2158 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2160 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2162 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2164 if (anim_mode == ANIM_DEFAULT)
2165 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2167 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2170 Delay(wait_delay_value);
2172 WaitForEventToContinue();
2174 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2176 if (anim_mode != ANIM_NONE)
2177 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2179 if (anim_mode == ANIM_DEFAULT)
2180 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2182 game.envelope_active = FALSE;
2184 SetDrawtoField(DRAW_BUFFERED);
2186 redraw_mask |= REDRAW_FIELD;
2190 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2194 int graphic = el2preimg(element);
2196 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2197 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2205 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2206 SetDrawBackgroundMask(REDRAW_FIELD);
2208 SetDrawBackgroundMask(REDRAW_NONE);
2213 for (x = BX1; x <= BX2; x++)
2214 for (y = BY1; y <= BY2; y++)
2215 DrawScreenField(x, y);
2217 redraw_mask |= REDRAW_FIELD;
2220 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2224 for (x = 0; x < size_x; x++)
2225 for (y = 0; y < size_y; y++)
2226 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2228 redraw_mask |= REDRAW_FIELD;
2231 static void DrawPreviewLevelExt(int from_x, int from_y)
2233 boolean show_level_border = (BorderElement != EL_EMPTY);
2234 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2235 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2236 int tile_size = preview.tile_size;
2237 int preview_width = preview.xsize * tile_size;
2238 int preview_height = preview.ysize * tile_size;
2239 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2240 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2241 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2242 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2245 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2247 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2248 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2250 for (x = 0; x < real_preview_xsize; x++)
2252 for (y = 0; y < real_preview_ysize; y++)
2254 int lx = from_x + x + (show_level_border ? -1 : 0);
2255 int ly = from_y + y + (show_level_border ? -1 : 0);
2256 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2257 getBorderElement(lx, ly));
2259 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2260 element, tile_size);
2264 redraw_mask |= REDRAW_MICROLEVEL;
2267 #define MICROLABEL_EMPTY 0
2268 #define MICROLABEL_LEVEL_NAME 1
2269 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2270 #define MICROLABEL_LEVEL_AUTHOR 3
2271 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2272 #define MICROLABEL_IMPORTED_FROM 5
2273 #define MICROLABEL_IMPORTED_BY_HEAD 6
2274 #define MICROLABEL_IMPORTED_BY 7
2276 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2278 int max_text_width = SXSIZE;
2279 int font_width = getFontWidth(font_nr);
2281 if (pos->align == ALIGN_CENTER)
2282 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2283 else if (pos->align == ALIGN_RIGHT)
2284 max_text_width = pos->x;
2286 max_text_width = SXSIZE - pos->x;
2288 return max_text_width / font_width;
2291 static void DrawPreviewLevelLabelExt(int mode)
2293 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2294 char label_text[MAX_OUTPUT_LINESIZE + 1];
2295 int max_len_label_text;
2297 int font_nr = pos->font;
2300 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2301 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2302 mode == MICROLABEL_IMPORTED_BY_HEAD)
2303 font_nr = pos->font_alt;
2305 int font_nr = FONT_TEXT_2;
2308 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2309 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2310 mode == MICROLABEL_IMPORTED_BY_HEAD)
2311 font_nr = FONT_TEXT_3;
2315 max_len_label_text = getMaxTextLength(pos, font_nr);
2317 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2321 if (pos->size != -1)
2322 max_len_label_text = pos->size;
2325 for (i = 0; i < max_len_label_text; i++)
2326 label_text[i] = ' ';
2327 label_text[max_len_label_text] = '\0';
2329 if (strlen(label_text) > 0)
2332 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2334 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2335 int lypos = MICROLABEL2_YPOS;
2337 DrawText(lxpos, lypos, label_text, font_nr);
2342 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2343 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2344 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2345 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2346 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2347 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2348 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2349 max_len_label_text);
2350 label_text[max_len_label_text] = '\0';
2352 if (strlen(label_text) > 0)
2355 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2357 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2358 int lypos = MICROLABEL2_YPOS;
2360 DrawText(lxpos, lypos, label_text, font_nr);
2364 redraw_mask |= REDRAW_MICROLEVEL;
2367 void DrawPreviewLevel(boolean restart)
2369 static unsigned long scroll_delay = 0;
2370 static unsigned long label_delay = 0;
2371 static int from_x, from_y, scroll_direction;
2372 static int label_state, label_counter;
2373 unsigned long scroll_delay_value = preview.step_delay;
2374 boolean show_level_border = (BorderElement != EL_EMPTY);
2375 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2376 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2377 int last_game_status = game_status; /* save current game status */
2380 /* force PREVIEW font on preview level */
2381 game_status = GAME_MODE_PSEUDO_PREVIEW;
2389 if (preview.anim_mode == ANIM_CENTERED)
2391 if (level_xsize > preview.xsize)
2392 from_x = (level_xsize - preview.xsize) / 2;
2393 if (level_ysize > preview.ysize)
2394 from_y = (level_ysize - preview.ysize) / 2;
2397 from_x += preview.xoffset;
2398 from_y += preview.yoffset;
2400 scroll_direction = MV_RIGHT;
2404 DrawPreviewLevelExt(from_x, from_y);
2405 DrawPreviewLevelLabelExt(label_state);
2407 /* initialize delay counters */
2408 DelayReached(&scroll_delay, 0);
2409 DelayReached(&label_delay, 0);
2411 if (leveldir_current->name)
2413 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2414 char label_text[MAX_OUTPUT_LINESIZE + 1];
2416 int font_nr = pos->font;
2418 int font_nr = FONT_TEXT_1;
2421 int max_len_label_text = getMaxTextLength(pos, font_nr);
2423 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2431 if (pos->size != -1)
2432 max_len_label_text = pos->size;
2435 strncpy(label_text, leveldir_current->name, max_len_label_text);
2436 label_text[max_len_label_text] = '\0';
2439 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2441 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2442 lypos = SY + MICROLABEL1_YPOS;
2444 DrawText(lxpos, lypos, label_text, font_nr);
2448 game_status = last_game_status; /* restore current game status */
2453 /* scroll preview level, if needed */
2454 if (preview.anim_mode != ANIM_NONE &&
2455 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2456 DelayReached(&scroll_delay, scroll_delay_value))
2458 switch (scroll_direction)
2463 from_x -= preview.step_offset;
2464 from_x = (from_x < 0 ? 0 : from_x);
2467 scroll_direction = MV_UP;
2471 if (from_x < level_xsize - preview.xsize)
2473 from_x += preview.step_offset;
2474 from_x = (from_x > level_xsize - preview.xsize ?
2475 level_xsize - preview.xsize : from_x);
2478 scroll_direction = MV_DOWN;
2484 from_y -= preview.step_offset;
2485 from_y = (from_y < 0 ? 0 : from_y);
2488 scroll_direction = MV_RIGHT;
2492 if (from_y < level_ysize - preview.ysize)
2494 from_y += preview.step_offset;
2495 from_y = (from_y > level_ysize - preview.ysize ?
2496 level_ysize - preview.ysize : from_y);
2499 scroll_direction = MV_LEFT;
2506 DrawPreviewLevelExt(from_x, from_y);
2509 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2510 /* redraw micro level label, if needed */
2511 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2512 !strEqual(level.author, ANONYMOUS_NAME) &&
2513 !strEqual(level.author, leveldir_current->name) &&
2514 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2516 int max_label_counter = 23;
2518 if (leveldir_current->imported_from != NULL &&
2519 strlen(leveldir_current->imported_from) > 0)
2520 max_label_counter += 14;
2521 if (leveldir_current->imported_by != NULL &&
2522 strlen(leveldir_current->imported_by) > 0)
2523 max_label_counter += 14;
2525 label_counter = (label_counter + 1) % max_label_counter;
2526 label_state = (label_counter >= 0 && label_counter <= 7 ?
2527 MICROLABEL_LEVEL_NAME :
2528 label_counter >= 9 && label_counter <= 12 ?
2529 MICROLABEL_LEVEL_AUTHOR_HEAD :
2530 label_counter >= 14 && label_counter <= 21 ?
2531 MICROLABEL_LEVEL_AUTHOR :
2532 label_counter >= 23 && label_counter <= 26 ?
2533 MICROLABEL_IMPORTED_FROM_HEAD :
2534 label_counter >= 28 && label_counter <= 35 ?
2535 MICROLABEL_IMPORTED_FROM :
2536 label_counter >= 37 && label_counter <= 40 ?
2537 MICROLABEL_IMPORTED_BY_HEAD :
2538 label_counter >= 42 && label_counter <= 49 ?
2539 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2541 if (leveldir_current->imported_from == NULL &&
2542 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2543 label_state == MICROLABEL_IMPORTED_FROM))
2544 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2545 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2547 DrawPreviewLevelLabelExt(label_state);
2550 game_status = last_game_status; /* restore current game status */
2553 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2554 int graphic, int sync_frame, int mask_mode)
2556 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2558 if (mask_mode == USE_MASKING)
2559 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2561 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2564 inline void DrawGraphicAnimation(int x, int y, int graphic)
2566 int lx = LEVELX(x), ly = LEVELY(y);
2568 if (!IN_SCR_FIELD(x, y))
2571 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2572 graphic, GfxFrame[lx][ly], NO_MASKING);
2573 MarkTileDirty(x, y);
2576 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2578 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2581 void DrawLevelElementAnimation(int x, int y, int element)
2583 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2585 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2588 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2590 int sx = SCREENX(x), sy = SCREENY(y);
2592 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2595 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2598 DrawGraphicAnimation(sx, sy, graphic);
2601 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2602 DrawLevelFieldCrumbledSand(x, y);
2604 if (GFX_CRUMBLED(Feld[x][y]))
2605 DrawLevelFieldCrumbledSand(x, y);
2609 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2611 int sx = SCREENX(x), sy = SCREENY(y);
2614 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2617 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2619 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2622 DrawGraphicAnimation(sx, sy, graphic);
2624 if (GFX_CRUMBLED(element))
2625 DrawLevelFieldCrumbledSand(x, y);
2628 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2630 if (player->use_murphy)
2632 /* this works only because currently only one player can be "murphy" ... */
2633 static int last_horizontal_dir = MV_LEFT;
2634 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2636 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2637 last_horizontal_dir = move_dir;
2639 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2641 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2643 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2649 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2652 static boolean equalGraphics(int graphic1, int graphic2)
2654 struct GraphicInfo *g1 = &graphic_info[graphic1];
2655 struct GraphicInfo *g2 = &graphic_info[graphic2];
2657 return (g1->bitmap == g2->bitmap &&
2658 g1->src_x == g2->src_x &&
2659 g1->src_y == g2->src_y &&
2660 g1->anim_frames == g2->anim_frames &&
2661 g1->anim_delay == g2->anim_delay &&
2662 g1->anim_mode == g2->anim_mode);
2665 void DrawAllPlayers()
2669 for (i = 0; i < MAX_PLAYERS; i++)
2670 if (stored_player[i].active)
2671 DrawPlayer(&stored_player[i]);
2674 void DrawPlayerField(int x, int y)
2676 if (!IS_PLAYER(x, y))
2679 DrawPlayer(PLAYERINFO(x, y));
2682 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2684 void DrawPlayer(struct PlayerInfo *player)
2686 int jx = player->jx;
2687 int jy = player->jy;
2688 int move_dir = player->MovDir;
2689 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2690 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2691 int last_jx = (player->is_moving ? jx - dx : jx);
2692 int last_jy = (player->is_moving ? jy - dy : jy);
2693 int next_jx = jx + dx;
2694 int next_jy = jy + dy;
2695 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2696 boolean player_is_opaque = FALSE;
2697 int sx = SCREENX(jx), sy = SCREENY(jy);
2698 int sxx = 0, syy = 0;
2699 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2701 int action = ACTION_DEFAULT;
2702 int last_player_graphic = getPlayerGraphic(player, move_dir);
2703 int last_player_frame = player->Frame;
2706 /* GfxElement[][] is set to the element the player is digging or collecting;
2707 remove also for off-screen player if the player is not moving anymore */
2708 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2709 GfxElement[jx][jy] = EL_UNDEFINED;
2711 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2715 if (!IN_LEV_FIELD(jx, jy))
2717 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2718 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2719 printf("DrawPlayerField(): This should never happen!\n");
2724 if (element == EL_EXPLOSION)
2727 action = (player->is_pushing ? ACTION_PUSHING :
2728 player->is_digging ? ACTION_DIGGING :
2729 player->is_collecting ? ACTION_COLLECTING :
2730 player->is_moving ? ACTION_MOVING :
2731 player->is_snapping ? ACTION_SNAPPING :
2732 player->is_dropping ? ACTION_DROPPING :
2733 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2735 if (player->is_waiting)
2736 move_dir = player->dir_waiting;
2738 InitPlayerGfxAnimation(player, action, move_dir);
2740 /* ----------------------------------------------------------------------- */
2741 /* draw things in the field the player is leaving, if needed */
2742 /* ----------------------------------------------------------------------- */
2744 if (player->is_moving)
2746 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2748 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2750 if (last_element == EL_DYNAMITE_ACTIVE ||
2751 last_element == EL_EM_DYNAMITE_ACTIVE ||
2752 last_element == EL_SP_DISK_RED_ACTIVE)
2753 DrawDynamite(last_jx, last_jy);
2755 DrawLevelFieldThruMask(last_jx, last_jy);
2757 else if (last_element == EL_DYNAMITE_ACTIVE ||
2758 last_element == EL_EM_DYNAMITE_ACTIVE ||
2759 last_element == EL_SP_DISK_RED_ACTIVE)
2760 DrawDynamite(last_jx, last_jy);
2762 /* !!! this is not enough to prevent flickering of players which are
2763 moving next to each others without a free tile between them -- this
2764 can only be solved by drawing all players layer by layer (first the
2765 background, then the foreground etc.) !!! => TODO */
2766 else if (!IS_PLAYER(last_jx, last_jy))
2767 DrawLevelField(last_jx, last_jy);
2770 DrawLevelField(last_jx, last_jy);
2773 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2774 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2777 if (!IN_SCR_FIELD(sx, sy))
2780 /* ----------------------------------------------------------------------- */
2781 /* draw things behind the player, if needed */
2782 /* ----------------------------------------------------------------------- */
2785 DrawLevelElement(jx, jy, Back[jx][jy]);
2786 else if (IS_ACTIVE_BOMB(element))
2787 DrawLevelElement(jx, jy, EL_EMPTY);
2790 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2792 int old_element = GfxElement[jx][jy];
2793 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2794 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2796 if (GFX_CRUMBLED(old_element))
2797 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2799 DrawGraphic(sx, sy, old_graphic, frame);
2801 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2802 player_is_opaque = TRUE;
2806 GfxElement[jx][jy] = EL_UNDEFINED;
2808 /* make sure that pushed elements are drawn with correct frame rate */
2810 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2812 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2813 GfxFrame[jx][jy] = player->StepFrame;
2815 if (player->is_pushing && player->is_moving)
2816 GfxFrame[jx][jy] = player->StepFrame;
2819 DrawLevelField(jx, jy);
2823 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
2824 /* ----------------------------------------------------------------------- */
2825 /* draw player himself */
2826 /* ----------------------------------------------------------------------- */
2828 graphic = getPlayerGraphic(player, move_dir);
2830 /* in the case of changed player action or direction, prevent the current
2831 animation frame from being restarted for identical animations */
2832 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2833 player->Frame = last_player_frame;
2835 frame = getGraphicAnimationFrame(graphic, player->Frame);
2839 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2840 sxx = player->GfxPos;
2842 syy = player->GfxPos;
2845 if (!setup.soft_scrolling && ScreenMovPos)
2848 if (player_is_opaque)
2849 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2851 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2853 if (SHIELD_ON(player))
2855 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2856 IMG_SHIELD_NORMAL_ACTIVE);
2857 int frame = getGraphicAnimationFrame(graphic, -1);
2859 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2863 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2866 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2867 sxx = player->GfxPos;
2869 syy = player->GfxPos;
2873 /* ----------------------------------------------------------------------- */
2874 /* draw things the player is pushing, if needed */
2875 /* ----------------------------------------------------------------------- */
2878 printf("::: %d, %d [%d, %d] [%d]\n",
2879 player->is_pushing, player_is_moving, player->GfxAction,
2880 player->is_moving, player_is_moving);
2884 if (player->is_pushing && player->is_moving)
2886 int px = SCREENX(jx), py = SCREENY(jy);
2887 int pxx = (TILEX - ABS(sxx)) * dx;
2888 int pyy = (TILEY - ABS(syy)) * dy;
2889 int gfx_frame = GfxFrame[jx][jy];
2895 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2897 element = Feld[next_jx][next_jy];
2898 gfx_frame = GfxFrame[next_jx][next_jy];
2901 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2904 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2905 frame = getGraphicAnimationFrame(graphic, sync_frame);
2907 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2910 /* draw background element under pushed element (like the Sokoban field) */
2912 if (game.use_masked_pushing && IS_MOVING(jx, jy))
2914 /* this allows transparent pushing animation over non-black background */
2917 DrawLevelElement(jx, jy, Back[jx][jy]);
2919 DrawLevelElement(jx, jy, EL_EMPTY);
2921 if (Back[next_jx][next_jy])
2922 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2924 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2926 else if (Back[next_jx][next_jy])
2927 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2929 if (Back[next_jx][next_jy])
2930 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2934 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
2935 jx, px, player->GfxPos, player->StepFrame,
2940 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
2944 /* do not draw (EM style) pushing animation when pushing is finished */
2945 /* (two-tile animations usually do not contain start and end frame) */
2946 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
2947 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
2949 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2951 /* masked drawing is needed for EMC style (double) movement graphics */
2952 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
2953 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2958 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2959 /* ----------------------------------------------------------------------- */
2960 /* draw player himself */
2961 /* ----------------------------------------------------------------------- */
2963 graphic = getPlayerGraphic(player, move_dir);
2965 /* in the case of changed player action or direction, prevent the current
2966 animation frame from being restarted for identical animations */
2967 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2968 player->Frame = last_player_frame;
2970 frame = getGraphicAnimationFrame(graphic, player->Frame);
2974 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2975 sxx = player->GfxPos;
2977 syy = player->GfxPos;
2980 if (!setup.soft_scrolling && ScreenMovPos)
2983 if (player_is_opaque)
2984 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2986 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2988 if (SHIELD_ON(player))
2990 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2991 IMG_SHIELD_NORMAL_ACTIVE);
2992 int frame = getGraphicAnimationFrame(graphic, -1);
2994 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2998 /* ----------------------------------------------------------------------- */
2999 /* draw things in front of player (active dynamite or dynabombs) */
3000 /* ----------------------------------------------------------------------- */
3002 if (IS_ACTIVE_BOMB(element))
3004 graphic = el2img(element);
3005 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3007 if (game.emulation == EMU_SUPAPLEX)
3008 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3010 DrawGraphicThruMask(sx, sy, graphic, frame);
3013 if (player_is_moving && last_element == EL_EXPLOSION)
3015 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3016 GfxElement[last_jx][last_jy] : EL_EMPTY);
3017 int graphic = el_act2img(element, ACTION_EXPLODING);
3018 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3019 int phase = ExplodePhase[last_jx][last_jy] - 1;
3020 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3023 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3026 /* ----------------------------------------------------------------------- */
3027 /* draw elements the player is just walking/passing through/under */
3028 /* ----------------------------------------------------------------------- */
3030 if (player_is_moving)
3032 /* handle the field the player is leaving ... */
3033 if (IS_ACCESSIBLE_INSIDE(last_element))
3034 DrawLevelField(last_jx, last_jy);
3035 else if (IS_ACCESSIBLE_UNDER(last_element))
3036 DrawLevelFieldThruMask(last_jx, last_jy);
3039 /* do not redraw accessible elements if the player is just pushing them */
3040 if (!player_is_moving || !player->is_pushing)
3042 /* ... and the field the player is entering */
3043 if (IS_ACCESSIBLE_INSIDE(element))
3044 DrawLevelField(jx, jy);
3045 else if (IS_ACCESSIBLE_UNDER(element))
3046 DrawLevelFieldThruMask(jx, jy);
3049 MarkTileDirty(sx, sy);
3052 /* ------------------------------------------------------------------------- */
3054 void WaitForEventToContinue()
3056 boolean still_wait = TRUE;
3058 /* simulate releasing mouse button over last gadget, if still pressed */
3060 HandleGadgets(-1, -1, 0);
3062 button_status = MB_RELEASED;
3078 case EVENT_BUTTONPRESS:
3079 case EVENT_KEYPRESS:
3083 case EVENT_KEYRELEASE:
3084 ClearPlayerAction();
3088 HandleOtherEvents(&event);
3092 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3099 /* don't eat all CPU time */
3104 #define MAX_REQUEST_LINES 13
3105 #define MAX_REQUEST_LINE_FONT1_LEN 7
3106 #define MAX_REQUEST_LINE_FONT2_LEN 10
3108 boolean Request(char *text, unsigned int req_state)
3110 int mx, my, ty, result = -1;
3111 unsigned int old_door_state;
3112 int last_game_status = game_status; /* save current game status */
3113 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3114 int font_nr = FONT_TEXT_2;
3115 int max_word_len = 0;
3118 for (text_ptr = text; *text_ptr; text_ptr++)
3120 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3122 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3124 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3126 font_nr = FONT_TEXT_1;
3128 font_nr = FONT_LEVEL_NUMBER;
3135 if (game_status == GAME_MODE_PLAYING)
3137 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3138 BlitScreenToBitmap_EM(backbuffer);
3139 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3140 BlitScreenToBitmap_SP(backbuffer);
3143 /* disable deactivated drawing when quick-loading level tape recording */
3144 if (tape.playing && tape.deactivate_display)
3145 TapeDeactivateDisplayOff(TRUE);
3147 SetMouseCursor(CURSOR_DEFAULT);
3149 #if defined(NETWORK_AVALIABLE)
3150 /* pause network game while waiting for request to answer */
3151 if (options.network &&
3152 game_status == GAME_MODE_PLAYING &&
3153 req_state & REQUEST_WAIT_FOR_INPUT)
3154 SendToServer_PausePlaying();
3157 old_door_state = GetDoorState();
3159 /* simulate releasing mouse button over last gadget, if still pressed */
3161 HandleGadgets(-1, -1, 0);
3165 if (old_door_state & DOOR_OPEN_1)
3167 CloseDoor(DOOR_CLOSE_1);
3169 /* save old door content */
3170 BlitBitmap(bitmap_db_door, bitmap_db_door,
3171 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3172 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3176 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3179 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3181 /* clear door drawing field */
3182 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3184 /* force DOOR font inside door area */
3185 game_status = GAME_MODE_PSEUDO_DOOR;
3187 /* write text for request */
3188 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
3190 char text_line[max_request_line_len + 1];
3196 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3199 if (!tc || tc == ' ')
3210 strncpy(text_line, text, tl);
3213 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3214 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3215 text_line, font_nr);
3217 text += tl + (tc == ' ' ? 1 : 0);
3220 game_status = last_game_status; /* restore current game status */
3222 if (req_state & REQ_ASK)
3224 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3225 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3227 else if (req_state & REQ_CONFIRM)
3229 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3231 else if (req_state & REQ_PLAYER)
3233 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3234 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3235 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3236 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3239 /* copy request gadgets to door backbuffer */
3240 BlitBitmap(drawto, bitmap_db_door,
3241 DX, DY, DXSIZE, DYSIZE,
3242 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3244 OpenDoor(DOOR_OPEN_1);
3246 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3248 if (game_status == GAME_MODE_PLAYING)
3250 SetPanelBackground();
3251 SetDrawBackgroundMask(REDRAW_DOOR_1);
3255 SetDrawBackgroundMask(REDRAW_FIELD);
3261 if (game_status != GAME_MODE_MAIN)
3264 button_status = MB_RELEASED;
3266 request_gadget_id = -1;
3268 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3280 case EVENT_BUTTONPRESS:
3281 case EVENT_BUTTONRELEASE:
3282 case EVENT_MOTIONNOTIFY:
3284 if (event.type == EVENT_MOTIONNOTIFY)
3286 if (!PointerInWindow(window))
3287 continue; /* window and pointer are on different screens */
3292 motion_status = TRUE;
3293 mx = ((MotionEvent *) &event)->x;
3294 my = ((MotionEvent *) &event)->y;
3298 motion_status = FALSE;
3299 mx = ((ButtonEvent *) &event)->x;
3300 my = ((ButtonEvent *) &event)->y;
3301 if (event.type == EVENT_BUTTONPRESS)
3302 button_status = ((ButtonEvent *) &event)->button;
3304 button_status = MB_RELEASED;
3307 /* this sets 'request_gadget_id' */
3308 HandleGadgets(mx, my, button_status);
3310 switch (request_gadget_id)
3312 case TOOL_CTRL_ID_YES:
3315 case TOOL_CTRL_ID_NO:
3318 case TOOL_CTRL_ID_CONFIRM:
3319 result = TRUE | FALSE;
3322 case TOOL_CTRL_ID_PLAYER_1:
3325 case TOOL_CTRL_ID_PLAYER_2:
3328 case TOOL_CTRL_ID_PLAYER_3:
3331 case TOOL_CTRL_ID_PLAYER_4:
3342 case EVENT_KEYPRESS:
3343 switch (GetEventKey((KeyEvent *)&event, TRUE))
3346 if (req_state & REQ_CONFIRM)
3362 if (req_state & REQ_PLAYER)
3366 case EVENT_KEYRELEASE:
3367 ClearPlayerAction();
3371 HandleOtherEvents(&event);
3375 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3377 int joy = AnyJoystick();
3379 if (joy & JOY_BUTTON_1)
3381 else if (joy & JOY_BUTTON_2)
3387 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3389 HandleGameActions();
3395 if (!PendingEvent()) /* delay only if no pending events */
3406 if (!PendingEvent()) /* delay only if no pending events */
3409 /* don't eat all CPU time */
3416 if (game_status != GAME_MODE_MAIN)
3421 if (!(req_state & REQ_STAY_OPEN))
3423 CloseDoor(DOOR_CLOSE_1);
3425 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3426 (req_state & REQ_REOPEN))
3427 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3432 if (game_status == GAME_MODE_PLAYING)
3434 SetPanelBackground();
3435 SetDrawBackgroundMask(REDRAW_DOOR_1);
3439 SetDrawBackgroundMask(REDRAW_FIELD);
3442 #if defined(NETWORK_AVALIABLE)
3443 /* continue network game after request */
3444 if (options.network &&
3445 game_status == GAME_MODE_PLAYING &&
3446 req_state & REQUEST_WAIT_FOR_INPUT)
3447 SendToServer_ContinuePlaying();
3450 /* restore deactivated drawing when quick-loading level tape recording */
3451 if (tape.playing && tape.deactivate_display)
3452 TapeDeactivateDisplayOn();
3457 unsigned int OpenDoor(unsigned int door_state)
3459 if (door_state & DOOR_COPY_BACK)
3461 if (door_state & DOOR_OPEN_1)
3462 BlitBitmap(bitmap_db_door, bitmap_db_door,
3463 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3464 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3466 if (door_state & DOOR_OPEN_2)
3467 BlitBitmap(bitmap_db_door, bitmap_db_door,
3468 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3469 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3471 door_state &= ~DOOR_COPY_BACK;
3474 return MoveDoor(door_state);
3477 unsigned int CloseDoor(unsigned int door_state)
3479 unsigned int old_door_state = GetDoorState();
3481 if (!(door_state & DOOR_NO_COPY_BACK))
3483 if (old_door_state & DOOR_OPEN_1)
3484 BlitBitmap(backbuffer, bitmap_db_door,
3485 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3487 if (old_door_state & DOOR_OPEN_2)
3488 BlitBitmap(backbuffer, bitmap_db_door,
3489 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3491 door_state &= ~DOOR_NO_COPY_BACK;
3494 return MoveDoor(door_state);
3497 unsigned int GetDoorState()
3499 return MoveDoor(DOOR_GET_STATE);
3502 unsigned int SetDoorState(unsigned int door_state)
3504 return MoveDoor(door_state | DOOR_SET_STATE);
3507 unsigned int MoveDoor(unsigned int door_state)
3509 static int door1 = DOOR_OPEN_1;
3510 static int door2 = DOOR_CLOSE_2;
3511 unsigned long door_delay = 0;
3512 unsigned long door_delay_value;
3515 if (door_1.width < 0 || door_1.width > DXSIZE)
3516 door_1.width = DXSIZE;
3517 if (door_1.height < 0 || door_1.height > DYSIZE)
3518 door_1.height = DYSIZE;
3519 if (door_2.width < 0 || door_2.width > VXSIZE)
3520 door_2.width = VXSIZE;
3521 if (door_2.height < 0 || door_2.height > VYSIZE)
3522 door_2.height = VYSIZE;
3524 if (door_state == DOOR_GET_STATE)
3525 return (door1 | door2);
3527 if (door_state & DOOR_SET_STATE)
3529 if (door_state & DOOR_ACTION_1)
3530 door1 = door_state & DOOR_ACTION_1;
3531 if (door_state & DOOR_ACTION_2)
3532 door2 = door_state & DOOR_ACTION_2;
3534 return (door1 | door2);
3537 if (!(door_state & DOOR_FORCE_REDRAW))
3539 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3540 door_state &= ~DOOR_OPEN_1;
3541 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3542 door_state &= ~DOOR_CLOSE_1;
3543 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3544 door_state &= ~DOOR_OPEN_2;
3545 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3546 door_state &= ~DOOR_CLOSE_2;
3549 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3552 if (setup.quick_doors)
3554 stepsize = 20; /* must be chosen to always draw last frame */
3555 door_delay_value = 0;
3558 if (global.autoplay_leveldir)
3560 door_state |= DOOR_NO_DELAY;
3561 door_state &= ~DOOR_CLOSE_ALL;
3565 if (game_status == GAME_MODE_EDITOR)
3566 door_state |= DOOR_NO_DELAY;
3569 if (door_state & DOOR_ACTION)
3571 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3572 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3573 boolean door_1_done = (!handle_door_1);
3574 boolean door_2_done = (!handle_door_2);
3575 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3576 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3577 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3578 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3579 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3580 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3581 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3582 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3583 int door_skip = max_door_size - door_size;
3584 int end = door_size;
3585 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3588 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3590 /* opening door sound has priority over simultaneously closing door */
3591 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3592 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3593 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3594 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3597 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3600 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3601 GC gc = bitmap->stored_clip_gc;
3603 if (door_state & DOOR_ACTION_1)
3605 int a = MIN(x * door_1.step_offset, end);
3606 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3607 int i = p + door_skip;
3609 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3611 BlitBitmap(bitmap_db_door, drawto,
3612 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3613 DXSIZE, DYSIZE, DX, DY);
3617 BlitBitmap(bitmap_db_door, drawto,
3618 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3619 DXSIZE, DYSIZE - p / 2, DX, DY);
3621 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3624 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3626 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3627 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3628 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3629 int dst2_x = DX, dst2_y = DY;
3630 int width = i, height = DYSIZE;
3632 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3633 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3636 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3637 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3640 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3642 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3643 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3644 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3645 int dst2_x = DX, dst2_y = DY;
3646 int width = DXSIZE, height = i;
3648 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3649 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3652 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3653 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3656 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3658 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3660 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3661 BlitBitmapMasked(bitmap, drawto,
3662 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3663 DX + DXSIZE - i, DY + j);
3664 BlitBitmapMasked(bitmap, drawto,
3665 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3666 DX + DXSIZE - i, DY + 140 + j);
3667 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3668 DY - (DOOR_GFX_PAGEY1 + j));
3669 BlitBitmapMasked(bitmap, drawto,
3670 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3672 BlitBitmapMasked(bitmap, drawto,
3673 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3676 BlitBitmapMasked(bitmap, drawto,
3677 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3679 BlitBitmapMasked(bitmap, drawto,
3680 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3682 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3683 BlitBitmapMasked(bitmap, drawto,
3684 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3685 DX + DXSIZE - i, DY + 77 + j);
3686 BlitBitmapMasked(bitmap, drawto,
3687 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3688 DX + DXSIZE - i, DY + 203 + j);
3691 redraw_mask |= REDRAW_DOOR_1;
3692 door_1_done = (a == end);
3695 if (door_state & DOOR_ACTION_2)
3697 int a = MIN(x * door_2.step_offset, door_size);
3698 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3699 int i = p + door_skip;
3701 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3703 BlitBitmap(bitmap_db_door, drawto,
3704 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3705 VXSIZE, VYSIZE, VX, VY);
3707 else if (x <= VYSIZE)
3709 BlitBitmap(bitmap_db_door, drawto,
3710 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3711 VXSIZE, VYSIZE - p / 2, VX, VY);
3713 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3716 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3718 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3719 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3720 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3721 int dst2_x = VX, dst2_y = VY;
3722 int width = i, height = VYSIZE;
3724 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3725 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3728 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3729 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3732 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3734 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3735 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3736 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3737 int dst2_x = VX, dst2_y = VY;
3738 int width = VXSIZE, height = i;
3740 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3741 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3744 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3745 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3748 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3750 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3752 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3753 BlitBitmapMasked(bitmap, drawto,
3754 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3755 VX + VXSIZE - i, VY + j);
3756 SetClipOrigin(bitmap, gc,
3757 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3758 BlitBitmapMasked(bitmap, drawto,
3759 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3762 BlitBitmapMasked(bitmap, drawto,
3763 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3764 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3765 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3766 BlitBitmapMasked(bitmap, drawto,
3767 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3769 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3772 redraw_mask |= REDRAW_DOOR_2;
3773 door_2_done = (a == VXSIZE);
3776 if (!(door_state & DOOR_NO_DELAY))
3780 if (game_status == GAME_MODE_MAIN)
3783 WaitUntilDelayReached(&door_delay, door_delay_value);
3788 if (door_state & DOOR_ACTION_1)
3789 door1 = door_state & DOOR_ACTION_1;
3790 if (door_state & DOOR_ACTION_2)
3791 door2 = door_state & DOOR_ACTION_2;
3793 return (door1 | door2);
3796 void DrawSpecialEditorDoor()
3798 /* draw bigger toolbox window */
3799 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3800 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3802 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3803 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3806 redraw_mask |= REDRAW_ALL;
3809 void UndrawSpecialEditorDoor()
3811 /* draw normal tape recorder window */
3812 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3813 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3816 redraw_mask |= REDRAW_ALL;
3820 /* ---------- new tool button stuff ---------------------------------------- */
3822 /* graphic position values for tool buttons */
3823 #define TOOL_BUTTON_YES_XPOS 2
3824 #define TOOL_BUTTON_YES_YPOS 250
3825 #define TOOL_BUTTON_YES_GFX_YPOS 0
3826 #define TOOL_BUTTON_YES_XSIZE 46
3827 #define TOOL_BUTTON_YES_YSIZE 28
3828 #define TOOL_BUTTON_NO_XPOS 52
3829 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3830 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3831 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3832 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3833 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3834 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3835 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3836 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3837 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3838 #define TOOL_BUTTON_PLAYER_XSIZE 30
3839 #define TOOL_BUTTON_PLAYER_YSIZE 30
3840 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3841 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3842 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3843 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3844 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3845 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3846 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3847 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3848 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3849 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3850 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3851 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3852 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3853 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3854 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3855 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3856 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3857 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3858 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3859 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3868 } toolbutton_info[NUM_TOOL_BUTTONS] =
3871 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3872 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3873 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3878 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3879 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3880 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3885 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3886 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3887 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3888 TOOL_CTRL_ID_CONFIRM,
3892 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3893 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3894 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3895 TOOL_CTRL_ID_PLAYER_1,
3899 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3900 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3901 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3902 TOOL_CTRL_ID_PLAYER_2,
3906 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3907 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3908 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3909 TOOL_CTRL_ID_PLAYER_3,
3913 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3914 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3915 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3916 TOOL_CTRL_ID_PLAYER_4,
3921 void CreateToolButtons()
3925 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3927 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3928 Bitmap *deco_bitmap = None;
3929 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3930 struct GadgetInfo *gi;
3931 unsigned long event_mask;
3932 int gd_xoffset, gd_yoffset;
3933 int gd_x1, gd_x2, gd_y;
3936 event_mask = GD_EVENT_RELEASED;
3938 gd_xoffset = toolbutton_info[i].xpos;
3939 gd_yoffset = toolbutton_info[i].ypos;
3940 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3941 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3942 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3944 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3946 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3948 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3949 &deco_bitmap, &deco_x, &deco_y);
3950 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3951 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3954 gi = CreateGadget(GDI_CUSTOM_ID, id,
3955 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3956 GDI_X, DX + toolbutton_info[i].x,
3957 GDI_Y, DY + toolbutton_info[i].y,
3958 GDI_WIDTH, toolbutton_info[i].width,
3959 GDI_HEIGHT, toolbutton_info[i].height,
3960 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3961 GDI_STATE, GD_BUTTON_UNPRESSED,
3962 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3963 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3964 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3965 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3966 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3967 GDI_DECORATION_SHIFTING, 1, 1,
3968 GDI_DIRECT_DRAW, FALSE,
3969 GDI_EVENT_MASK, event_mask,
3970 GDI_CALLBACK_ACTION, HandleToolButtons,
3974 Error(ERR_EXIT, "cannot create gadget");
3976 tool_gadget[id] = gi;
3980 void FreeToolButtons()
3984 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3985 FreeGadget(tool_gadget[i]);
3988 static void UnmapToolButtons()
3992 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3993 UnmapGadget(tool_gadget[i]);
3996 static void HandleToolButtons(struct GadgetInfo *gi)
3998 request_gadget_id = gi->custom_id;
4001 static struct Mapping_EM_to_RND_object
4004 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4005 boolean is_backside; /* backside of moving element */
4011 em_object_mapping_list[] =
4014 Xblank, TRUE, FALSE,
4018 Yacid_splash_eB, FALSE, FALSE,
4019 EL_ACID_SPLASH_RIGHT, -1, -1
4022 Yacid_splash_wB, FALSE, FALSE,
4023 EL_ACID_SPLASH_LEFT, -1, -1
4026 #ifdef EM_ENGINE_BAD_ROLL
4028 Xstone_force_e, FALSE, FALSE,
4029 EL_ROCK, -1, MV_BIT_RIGHT
4032 Xstone_force_w, FALSE, FALSE,
4033 EL_ROCK, -1, MV_BIT_LEFT
4036 Xnut_force_e, FALSE, FALSE,
4037 EL_NUT, -1, MV_BIT_RIGHT
4040 Xnut_force_w, FALSE, FALSE,
4041 EL_NUT, -1, MV_BIT_LEFT
4044 Xspring_force_e, FALSE, FALSE,
4045 EL_SPRING, -1, MV_BIT_RIGHT
4048 Xspring_force_w, FALSE, FALSE,
4049 EL_SPRING, -1, MV_BIT_LEFT
4052 Xemerald_force_e, FALSE, FALSE,
4053 EL_EMERALD, -1, MV_BIT_RIGHT
4056 Xemerald_force_w, FALSE, FALSE,
4057 EL_EMERALD, -1, MV_BIT_LEFT
4060 Xdiamond_force_e, FALSE, FALSE,
4061 EL_DIAMOND, -1, MV_BIT_RIGHT
4064 Xdiamond_force_w, FALSE, FALSE,
4065 EL_DIAMOND, -1, MV_BIT_LEFT
4068 Xbomb_force_e, FALSE, FALSE,
4069 EL_BOMB, -1, MV_BIT_RIGHT
4072 Xbomb_force_w, FALSE, FALSE,
4073 EL_BOMB, -1, MV_BIT_LEFT
4075 #endif /* EM_ENGINE_BAD_ROLL */
4078 Xstone, TRUE, FALSE,
4082 Xstone_pause, FALSE, FALSE,
4086 Xstone_fall, FALSE, FALSE,
4090 Ystone_s, FALSE, FALSE,
4091 EL_ROCK, ACTION_FALLING, -1
4094 Ystone_sB, FALSE, TRUE,
4095 EL_ROCK, ACTION_FALLING, -1
4098 Ystone_e, FALSE, FALSE,
4099 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4102 Ystone_eB, FALSE, TRUE,
4103 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4106 Ystone_w, FALSE, FALSE,
4107 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4110 Ystone_wB, FALSE, TRUE,
4111 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4118 Xnut_pause, FALSE, FALSE,
4122 Xnut_fall, FALSE, FALSE,
4126 Ynut_s, FALSE, FALSE,
4127 EL_NUT, ACTION_FALLING, -1
4130 Ynut_sB, FALSE, TRUE,
4131 EL_NUT, ACTION_FALLING, -1
4134 Ynut_e, FALSE, FALSE,
4135 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4138 Ynut_eB, FALSE, TRUE,
4139 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4142 Ynut_w, FALSE, FALSE,
4143 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4146 Ynut_wB, FALSE, TRUE,
4147 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4150 Xbug_n, TRUE, FALSE,
4154 Xbug_e, TRUE, FALSE,
4155 EL_BUG_RIGHT, -1, -1
4158 Xbug_s, TRUE, FALSE,
4162 Xbug_w, TRUE, FALSE,
4166 Xbug_gon, FALSE, FALSE,
4170 Xbug_goe, FALSE, FALSE,
4171 EL_BUG_RIGHT, -1, -1
4174 Xbug_gos, FALSE, FALSE,
4178 Xbug_gow, FALSE, FALSE,
4182 Ybug_n, FALSE, FALSE,
4183 EL_BUG, ACTION_MOVING, MV_BIT_UP
4186 Ybug_nB, FALSE, TRUE,
4187 EL_BUG, ACTION_MOVING, MV_BIT_UP
4190 Ybug_e, FALSE, FALSE,
4191 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4194 Ybug_eB, FALSE, TRUE,
4195 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4198 Ybug_s, FALSE, FALSE,
4199 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4202 Ybug_sB, FALSE, TRUE,
4203 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4206 Ybug_w, FALSE, FALSE,
4207 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4210 Ybug_wB, FALSE, TRUE,
4211 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4214 Ybug_w_n, FALSE, FALSE,
4215 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4218 Ybug_n_e, FALSE, FALSE,
4219 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4222 Ybug_e_s, FALSE, FALSE,
4223 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4226 Ybug_s_w, FALSE, FALSE,
4227 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4230 Ybug_e_n, FALSE, FALSE,
4231 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4234 Ybug_s_e, FALSE, FALSE,
4235 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4238 Ybug_w_s, FALSE, FALSE,
4239 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4242 Ybug_n_w, FALSE, FALSE,
4243 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4246 Ybug_stone, FALSE, FALSE,
4247 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4250 Ybug_spring, FALSE, FALSE,
4251 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4254 Xtank_n, TRUE, FALSE,
4255 EL_SPACESHIP_UP, -1, -1
4258 Xtank_e, TRUE, FALSE,
4259 EL_SPACESHIP_RIGHT, -1, -1
4262 Xtank_s, TRUE, FALSE,
4263 EL_SPACESHIP_DOWN, -1, -1
4266 Xtank_w, TRUE, FALSE,
4267 EL_SPACESHIP_LEFT, -1, -1
4270 Xtank_gon, FALSE, FALSE,
4271 EL_SPACESHIP_UP, -1, -1
4274 Xtank_goe, FALSE, FALSE,
4275 EL_SPACESHIP_RIGHT, -1, -1
4278 Xtank_gos, FALSE, FALSE,
4279 EL_SPACESHIP_DOWN, -1, -1
4282 Xtank_gow, FALSE, FALSE,
4283 EL_SPACESHIP_LEFT, -1, -1
4286 Ytank_n, FALSE, FALSE,
4287 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4290 Ytank_nB, FALSE, TRUE,
4291 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4294 Ytank_e, FALSE, FALSE,
4295 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4298 Ytank_eB, FALSE, TRUE,
4299 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4302 Ytank_s, FALSE, FALSE,
4303 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4306 Ytank_sB, FALSE, TRUE,
4307 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4310 Ytank_w, FALSE, FALSE,
4311 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4314 Ytank_wB, FALSE, TRUE,
4315 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4318 Ytank_w_n, FALSE, FALSE,
4319 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4322 Ytank_n_e, FALSE, FALSE,
4323 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4326 Ytank_e_s, FALSE, FALSE,
4327 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4330 Ytank_s_w, FALSE, FALSE,
4331 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4334 Ytank_e_n, FALSE, FALSE,
4335 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4338 Ytank_s_e, FALSE, FALSE,
4339 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4342 Ytank_w_s, FALSE, FALSE,
4343 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4346 Ytank_n_w, FALSE, FALSE,
4347 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4350 Ytank_stone, FALSE, FALSE,
4351 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4354 Ytank_spring, FALSE, FALSE,
4355 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4358 Xandroid, TRUE, FALSE,
4359 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4362 Xandroid_1_n, FALSE, FALSE,
4363 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4366 Xandroid_2_n, FALSE, FALSE,
4367 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4370 Xandroid_1_e, FALSE, FALSE,
4371 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4374 Xandroid_2_e, FALSE, FALSE,
4375 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4378 Xandroid_1_w, FALSE, FALSE,
4379 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4382 Xandroid_2_w, FALSE, FALSE,
4383 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4386 Xandroid_1_s, FALSE, FALSE,
4387 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4390 Xandroid_2_s, FALSE, FALSE,
4391 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4394 Yandroid_n, FALSE, FALSE,
4395 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4398 Yandroid_nB, FALSE, TRUE,
4399 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4402 Yandroid_ne, FALSE, FALSE,
4403 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4406 Yandroid_neB, FALSE, TRUE,
4407 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4410 Yandroid_e, FALSE, FALSE,
4411 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4414 Yandroid_eB, FALSE, TRUE,
4415 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4418 Yandroid_se, FALSE, FALSE,
4419 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4422 Yandroid_seB, FALSE, TRUE,
4423 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4426 Yandroid_s, FALSE, FALSE,
4427 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4430 Yandroid_sB, FALSE, TRUE,
4431 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4434 Yandroid_sw, FALSE, FALSE,
4435 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4438 Yandroid_swB, FALSE, TRUE,
4439 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4442 Yandroid_w, FALSE, FALSE,
4443 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4446 Yandroid_wB, FALSE, TRUE,
4447 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4450 Yandroid_nw, FALSE, FALSE,
4451 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4454 Yandroid_nwB, FALSE, TRUE,
4455 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4458 Xspring, TRUE, FALSE,
4462 Xspring_pause, FALSE, FALSE,
4466 Xspring_e, FALSE, FALSE,
4470 Xspring_w, FALSE, FALSE,
4474 Xspring_fall, FALSE, FALSE,
4478 Yspring_s, FALSE, FALSE,
4479 EL_SPRING, ACTION_FALLING, -1
4482 Yspring_sB, FALSE, TRUE,
4483 EL_SPRING, ACTION_FALLING, -1
4486 Yspring_e, FALSE, FALSE,
4487 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4490 Yspring_eB, FALSE, TRUE,
4491 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4494 Yspring_w, FALSE, FALSE,
4495 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4498 Yspring_wB, FALSE, TRUE,
4499 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4502 Yspring_kill_e, FALSE, FALSE,
4503 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4506 Yspring_kill_eB, FALSE, TRUE,
4507 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4510 Yspring_kill_w, FALSE, FALSE,
4511 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4514 Yspring_kill_wB, FALSE, TRUE,
4515 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4518 Xeater_n, TRUE, FALSE,
4519 EL_YAMYAM_UP, -1, -1
4522 Xeater_e, TRUE, FALSE,
4523 EL_YAMYAM_RIGHT, -1, -1
4526 Xeater_w, TRUE, FALSE,
4527 EL_YAMYAM_LEFT, -1, -1
4530 Xeater_s, TRUE, FALSE,
4531 EL_YAMYAM_DOWN, -1, -1
4534 Yeater_n, FALSE, FALSE,
4535 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4538 Yeater_nB, FALSE, TRUE,
4539 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4542 Yeater_e, FALSE, FALSE,
4543 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4546 Yeater_eB, FALSE, TRUE,
4547 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4550 Yeater_s, FALSE, FALSE,
4551 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4554 Yeater_sB, FALSE, TRUE,
4555 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4558 Yeater_w, FALSE, FALSE,
4559 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4562 Yeater_wB, FALSE, TRUE,
4563 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4566 Yeater_stone, FALSE, FALSE,
4567 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4570 Yeater_spring, FALSE, FALSE,
4571 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4574 Xalien, TRUE, FALSE,
4578 Xalien_pause, FALSE, FALSE,
4582 Yalien_n, FALSE, FALSE,
4583 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4586 Yalien_nB, FALSE, TRUE,
4587 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4590 Yalien_e, FALSE, FALSE,
4591 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4594 Yalien_eB, FALSE, TRUE,
4595 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4598 Yalien_s, FALSE, FALSE,
4599 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4602 Yalien_sB, FALSE, TRUE,
4603 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4606 Yalien_w, FALSE, FALSE,
4607 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4610 Yalien_wB, FALSE, TRUE,
4611 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4614 Yalien_stone, FALSE, FALSE,
4615 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4618 Yalien_spring, FALSE, FALSE,
4619 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4622 Xemerald, TRUE, FALSE,
4626 Xemerald_pause, FALSE, FALSE,
4630 Xemerald_fall, FALSE, FALSE,
4634 Xemerald_shine, FALSE, FALSE,
4635 EL_EMERALD, ACTION_TWINKLING, -1
4638 Yemerald_s, FALSE, FALSE,
4639 EL_EMERALD, ACTION_FALLING, -1
4642 Yemerald_sB, FALSE, TRUE,
4643 EL_EMERALD, ACTION_FALLING, -1
4646 Yemerald_e, FALSE, FALSE,
4647 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4650 Yemerald_eB, FALSE, TRUE,
4651 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4654 Yemerald_w, FALSE, FALSE,
4655 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4658 Yemerald_wB, FALSE, TRUE,
4659 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4662 Yemerald_eat, FALSE, FALSE,
4663 EL_EMERALD, ACTION_COLLECTING, -1
4666 Yemerald_stone, FALSE, FALSE,
4667 EL_NUT, ACTION_BREAKING, -1
4670 Xdiamond, TRUE, FALSE,
4674 Xdiamond_pause, FALSE, FALSE,
4678 Xdiamond_fall, FALSE, FALSE,
4682 Xdiamond_shine, FALSE, FALSE,
4683 EL_DIAMOND, ACTION_TWINKLING, -1
4686 Ydiamond_s, FALSE, FALSE,
4687 EL_DIAMOND, ACTION_FALLING, -1
4690 Ydiamond_sB, FALSE, TRUE,
4691 EL_DIAMOND, ACTION_FALLING, -1
4694 Ydiamond_e, FALSE, FALSE,
4695 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4698 Ydiamond_eB, FALSE, TRUE,
4699 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4702 Ydiamond_w, FALSE, FALSE,
4703 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4706 Ydiamond_wB, FALSE, TRUE,
4707 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4710 Ydiamond_eat, FALSE, FALSE,
4711 EL_DIAMOND, ACTION_COLLECTING, -1
4714 Ydiamond_stone, FALSE, FALSE,
4715 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4718 Xdrip_fall, TRUE, FALSE,
4719 EL_AMOEBA_DROP, -1, -1
4722 Xdrip_stretch, FALSE, FALSE,
4723 EL_AMOEBA_DROP, ACTION_FALLING, -1
4726 Xdrip_stretchB, FALSE, TRUE,
4727 EL_AMOEBA_DROP, ACTION_FALLING, -1
4730 Xdrip_eat, FALSE, FALSE,
4731 EL_AMOEBA_DROP, ACTION_GROWING, -1
4734 Ydrip_s1, FALSE, FALSE,
4735 EL_AMOEBA_DROP, ACTION_FALLING, -1
4738 Ydrip_s1B, FALSE, TRUE,
4739 EL_AMOEBA_DROP, ACTION_FALLING, -1
4742 Ydrip_s2, FALSE, FALSE,
4743 EL_AMOEBA_DROP, ACTION_FALLING, -1
4746 Ydrip_s2B, FALSE, TRUE,
4747 EL_AMOEBA_DROP, ACTION_FALLING, -1
4754 Xbomb_pause, FALSE, FALSE,
4758 Xbomb_fall, FALSE, FALSE,
4762 Ybomb_s, FALSE, FALSE,
4763 EL_BOMB, ACTION_FALLING, -1
4766 Ybomb_sB, FALSE, TRUE,
4767 EL_BOMB, ACTION_FALLING, -1
4770 Ybomb_e, FALSE, FALSE,
4771 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4774 Ybomb_eB, FALSE, TRUE,
4775 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4778 Ybomb_w, FALSE, FALSE,
4779 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4782 Ybomb_wB, FALSE, TRUE,
4783 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4786 Ybomb_eat, FALSE, FALSE,
4787 EL_BOMB, ACTION_ACTIVATING, -1
4790 Xballoon, TRUE, FALSE,
4794 Yballoon_n, FALSE, FALSE,
4795 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4798 Yballoon_nB, FALSE, TRUE,
4799 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4802 Yballoon_e, FALSE, FALSE,
4803 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4806 Yballoon_eB, FALSE, TRUE,
4807 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4810 Yballoon_s, FALSE, FALSE,
4811 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4814 Yballoon_sB, FALSE, TRUE,
4815 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4818 Yballoon_w, FALSE, FALSE,
4819 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4822 Yballoon_wB, FALSE, TRUE,
4823 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4826 Xgrass, TRUE, FALSE,
4827 EL_EMC_GRASS, -1, -1
4830 Ygrass_nB, FALSE, FALSE,
4831 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4834 Ygrass_eB, FALSE, FALSE,
4835 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4838 Ygrass_sB, FALSE, FALSE,
4839 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4842 Ygrass_wB, FALSE, FALSE,
4843 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4850 Ydirt_nB, FALSE, FALSE,
4851 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4854 Ydirt_eB, FALSE, FALSE,
4855 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4858 Ydirt_sB, FALSE, FALSE,
4859 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4862 Ydirt_wB, FALSE, FALSE,
4863 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4866 Xacid_ne, TRUE, FALSE,
4867 EL_ACID_POOL_TOPRIGHT, -1, -1
4870 Xacid_se, TRUE, FALSE,
4871 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4874 Xacid_s, TRUE, FALSE,
4875 EL_ACID_POOL_BOTTOM, -1, -1
4878 Xacid_sw, TRUE, FALSE,
4879 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4882 Xacid_nw, TRUE, FALSE,
4883 EL_ACID_POOL_TOPLEFT, -1, -1
4886 Xacid_1, TRUE, FALSE,
4890 Xacid_2, FALSE, FALSE,
4894 Xacid_3, FALSE, FALSE,
4898 Xacid_4, FALSE, FALSE,
4902 Xacid_5, FALSE, FALSE,
4906 Xacid_6, FALSE, FALSE,
4910 Xacid_7, FALSE, FALSE,
4914 Xacid_8, FALSE, FALSE,
4918 Xball_1, TRUE, FALSE,
4919 EL_EMC_MAGIC_BALL, -1, -1
4922 Xball_1B, FALSE, FALSE,
4923 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4926 Xball_2, FALSE, FALSE,
4927 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4930 Xball_2B, FALSE, FALSE,
4931 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4934 Yball_eat, FALSE, FALSE,
4935 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4938 Ykey_1_eat, FALSE, FALSE,
4939 EL_EM_KEY_1, ACTION_COLLECTING, -1
4942 Ykey_2_eat, FALSE, FALSE,
4943 EL_EM_KEY_2, ACTION_COLLECTING, -1
4946 Ykey_3_eat, FALSE, FALSE,
4947 EL_EM_KEY_3, ACTION_COLLECTING, -1
4950 Ykey_4_eat, FALSE, FALSE,
4951 EL_EM_KEY_4, ACTION_COLLECTING, -1
4954 Ykey_5_eat, FALSE, FALSE,
4955 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4958 Ykey_6_eat, FALSE, FALSE,
4959 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4962 Ykey_7_eat, FALSE, FALSE,
4963 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4966 Ykey_8_eat, FALSE, FALSE,
4967 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4970 Ylenses_eat, FALSE, FALSE,
4971 EL_EMC_LENSES, ACTION_COLLECTING, -1
4974 Ymagnify_eat, FALSE, FALSE,
4975 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4978 Ygrass_eat, FALSE, FALSE,
4979 EL_EMC_GRASS, ACTION_SNAPPING, -1
4982 Ydirt_eat, FALSE, FALSE,
4983 EL_SAND, ACTION_SNAPPING, -1
4986 Xgrow_ns, TRUE, FALSE,
4987 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4990 Ygrow_ns_eat, FALSE, FALSE,
4991 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4994 Xgrow_ew, TRUE, FALSE,
4995 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4998 Ygrow_ew_eat, FALSE, FALSE,
4999 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5002 Xwonderwall, TRUE, FALSE,
5003 EL_MAGIC_WALL, -1, -1
5006 XwonderwallB, FALSE, FALSE,
5007 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5010 Xamoeba_1, TRUE, FALSE,
5011 EL_AMOEBA_DRY, ACTION_OTHER, -1
5014 Xamoeba_2, FALSE, FALSE,
5015 EL_AMOEBA_DRY, ACTION_OTHER, -1
5018 Xamoeba_3, FALSE, FALSE,
5019 EL_AMOEBA_DRY, ACTION_OTHER, -1
5022 Xamoeba_4, FALSE, FALSE,
5023 EL_AMOEBA_DRY, ACTION_OTHER, -1
5026 Xamoeba_5, TRUE, FALSE,
5027 EL_AMOEBA_WET, ACTION_OTHER, -1
5030 Xamoeba_6, FALSE, FALSE,
5031 EL_AMOEBA_WET, ACTION_OTHER, -1
5034 Xamoeba_7, FALSE, FALSE,
5035 EL_AMOEBA_WET, ACTION_OTHER, -1
5038 Xamoeba_8, FALSE, FALSE,
5039 EL_AMOEBA_WET, ACTION_OTHER, -1
5042 Xdoor_1, TRUE, FALSE,
5043 EL_EM_GATE_1, -1, -1
5046 Xdoor_2, TRUE, FALSE,
5047 EL_EM_GATE_2, -1, -1
5050 Xdoor_3, TRUE, FALSE,
5051 EL_EM_GATE_3, -1, -1
5054 Xdoor_4, TRUE, FALSE,
5055 EL_EM_GATE_4, -1, -1
5058 Xdoor_5, TRUE, FALSE,
5059 EL_EMC_GATE_5, -1, -1
5062 Xdoor_6, TRUE, FALSE,
5063 EL_EMC_GATE_6, -1, -1
5066 Xdoor_7, TRUE, FALSE,
5067 EL_EMC_GATE_7, -1, -1
5070 Xdoor_8, TRUE, FALSE,
5071 EL_EMC_GATE_8, -1, -1
5074 Xkey_1, TRUE, FALSE,
5078 Xkey_2, TRUE, FALSE,
5082 Xkey_3, TRUE, FALSE,
5086 Xkey_4, TRUE, FALSE,
5090 Xkey_5, TRUE, FALSE,
5091 EL_EMC_KEY_5, -1, -1
5094 Xkey_6, TRUE, FALSE,
5095 EL_EMC_KEY_6, -1, -1
5098 Xkey_7, TRUE, FALSE,
5099 EL_EMC_KEY_7, -1, -1
5102 Xkey_8, TRUE, FALSE,
5103 EL_EMC_KEY_8, -1, -1
5106 Xwind_n, TRUE, FALSE,
5107 EL_BALLOON_SWITCH_UP, -1, -1
5110 Xwind_e, TRUE, FALSE,
5111 EL_BALLOON_SWITCH_RIGHT, -1, -1
5114 Xwind_s, TRUE, FALSE,
5115 EL_BALLOON_SWITCH_DOWN, -1, -1
5118 Xwind_w, TRUE, FALSE,
5119 EL_BALLOON_SWITCH_LEFT, -1, -1
5122 Xwind_nesw, TRUE, FALSE,
5123 EL_BALLOON_SWITCH_ANY, -1, -1
5126 Xwind_stop, TRUE, FALSE,
5127 EL_BALLOON_SWITCH_NONE, -1, -1
5131 EL_EM_EXIT_CLOSED, -1, -1
5134 Xexit_1, TRUE, FALSE,
5135 EL_EM_EXIT_OPEN, -1, -1
5138 Xexit_2, FALSE, FALSE,
5139 EL_EM_EXIT_OPEN, -1, -1
5142 Xexit_3, FALSE, FALSE,
5143 EL_EM_EXIT_OPEN, -1, -1
5146 Xdynamite, TRUE, FALSE,
5147 EL_EM_DYNAMITE, -1, -1
5150 Ydynamite_eat, FALSE, FALSE,
5151 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5154 Xdynamite_1, TRUE, FALSE,
5155 EL_EM_DYNAMITE_ACTIVE, -1, -1
5158 Xdynamite_2, FALSE, FALSE,
5159 EL_EM_DYNAMITE_ACTIVE, -1, -1
5162 Xdynamite_3, FALSE, FALSE,
5163 EL_EM_DYNAMITE_ACTIVE, -1, -1
5166 Xdynamite_4, FALSE, FALSE,
5167 EL_EM_DYNAMITE_ACTIVE, -1, -1
5170 Xbumper, TRUE, FALSE,
5171 EL_EMC_SPRING_BUMPER, -1, -1
5174 XbumperB, FALSE, FALSE,
5175 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5178 Xwheel, TRUE, FALSE,
5179 EL_ROBOT_WHEEL, -1, -1
5182 XwheelB, FALSE, FALSE,
5183 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5186 Xswitch, TRUE, FALSE,
5187 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5190 XswitchB, FALSE, FALSE,
5191 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5195 EL_QUICKSAND_EMPTY, -1, -1
5198 Xsand_stone, TRUE, FALSE,
5199 EL_QUICKSAND_FULL, -1, -1
5202 Xsand_stonein_1, FALSE, TRUE,
5203 EL_ROCK, ACTION_FILLING, -1
5206 Xsand_stonein_2, FALSE, TRUE,
5207 EL_ROCK, ACTION_FILLING, -1
5210 Xsand_stonein_3, FALSE, TRUE,
5211 EL_ROCK, ACTION_FILLING, -1
5214 Xsand_stonein_4, FALSE, TRUE,
5215 EL_ROCK, ACTION_FILLING, -1
5219 Xsand_stonesand_1, FALSE, FALSE,
5220 EL_QUICKSAND_EMPTYING, -1, -1
5223 Xsand_stonesand_2, FALSE, FALSE,
5224 EL_QUICKSAND_EMPTYING, -1, -1
5227 Xsand_stonesand_3, FALSE, FALSE,
5228 EL_QUICKSAND_EMPTYING, -1, -1
5231 Xsand_stonesand_4, FALSE, FALSE,
5232 EL_QUICKSAND_EMPTYING, -1, -1
5235 Xsand_stonesand_quickout_1, FALSE, FALSE,
5236 EL_QUICKSAND_EMPTYING, -1, -1
5239 Xsand_stonesand_quickout_2, FALSE, FALSE,
5240 EL_QUICKSAND_EMPTYING, -1, -1
5244 Xsand_stonesand_1, FALSE, FALSE,
5245 EL_QUICKSAND_FULL, -1, -1
5248 Xsand_stonesand_2, FALSE, FALSE,
5249 EL_QUICKSAND_FULL, -1, -1
5252 Xsand_stonesand_3, FALSE, FALSE,
5253 EL_QUICKSAND_FULL, -1, -1
5256 Xsand_stonesand_4, FALSE, FALSE,
5257 EL_QUICKSAND_FULL, -1, -1
5261 Xsand_stoneout_1, FALSE, FALSE,
5262 EL_ROCK, ACTION_EMPTYING, -1
5265 Xsand_stoneout_2, FALSE, FALSE,
5266 EL_ROCK, ACTION_EMPTYING, -1
5270 Xsand_sandstone_1, FALSE, FALSE,
5271 EL_QUICKSAND_FILLING, -1, -1
5274 Xsand_sandstone_2, FALSE, FALSE,
5275 EL_QUICKSAND_FILLING, -1, -1
5278 Xsand_sandstone_3, FALSE, FALSE,
5279 EL_QUICKSAND_FILLING, -1, -1
5282 Xsand_sandstone_4, FALSE, FALSE,
5283 EL_QUICKSAND_FILLING, -1, -1
5287 Xsand_sandstone_1, FALSE, FALSE,
5288 EL_QUICKSAND_FULL, -1, -1
5291 Xsand_sandstone_2, FALSE, FALSE,
5292 EL_QUICKSAND_FULL, -1, -1
5295 Xsand_sandstone_3, FALSE, FALSE,
5296 EL_QUICKSAND_FULL, -1, -1
5299 Xsand_sandstone_4, FALSE, FALSE,
5300 EL_QUICKSAND_FULL, -1, -1
5304 Xplant, TRUE, FALSE,
5305 EL_EMC_PLANT, -1, -1
5308 Yplant, FALSE, FALSE,
5309 EL_EMC_PLANT, -1, -1
5312 Xlenses, TRUE, FALSE,
5313 EL_EMC_LENSES, -1, -1
5316 Xmagnify, TRUE, FALSE,
5317 EL_EMC_MAGNIFIER, -1, -1
5320 Xdripper, TRUE, FALSE,
5321 EL_EMC_DRIPPER, -1, -1
5324 XdripperB, FALSE, FALSE,
5325 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5328 Xfake_blank, TRUE, FALSE,
5329 EL_INVISIBLE_WALL, -1, -1
5332 Xfake_blankB, FALSE, FALSE,
5333 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5336 Xfake_grass, TRUE, FALSE,
5337 EL_EMC_FAKE_GRASS, -1, -1
5340 Xfake_grassB, FALSE, FALSE,
5341 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5344 Xfake_door_1, TRUE, FALSE,
5345 EL_EM_GATE_1_GRAY, -1, -1
5348 Xfake_door_2, TRUE, FALSE,
5349 EL_EM_GATE_2_GRAY, -1, -1
5352 Xfake_door_3, TRUE, FALSE,
5353 EL_EM_GATE_3_GRAY, -1, -1
5356 Xfake_door_4, TRUE, FALSE,
5357 EL_EM_GATE_4_GRAY, -1, -1
5360 Xfake_door_5, TRUE, FALSE,
5361 EL_EMC_GATE_5_GRAY, -1, -1
5364 Xfake_door_6, TRUE, FALSE,
5365 EL_EMC_GATE_6_GRAY, -1, -1
5368 Xfake_door_7, TRUE, FALSE,
5369 EL_EMC_GATE_7_GRAY, -1, -1
5372 Xfake_door_8, TRUE, FALSE,
5373 EL_EMC_GATE_8_GRAY, -1, -1
5376 Xfake_acid_1, TRUE, FALSE,
5377 EL_EMC_FAKE_ACID, -1, -1
5380 Xfake_acid_2, FALSE, FALSE,
5381 EL_EMC_FAKE_ACID, -1, -1
5384 Xfake_acid_3, FALSE, FALSE,
5385 EL_EMC_FAKE_ACID, -1, -1
5388 Xfake_acid_4, FALSE, FALSE,
5389 EL_EMC_FAKE_ACID, -1, -1
5392 Xfake_acid_5, FALSE, FALSE,
5393 EL_EMC_FAKE_ACID, -1, -1
5396 Xfake_acid_6, FALSE, FALSE,
5397 EL_EMC_FAKE_ACID, -1, -1
5400 Xfake_acid_7, FALSE, FALSE,
5401 EL_EMC_FAKE_ACID, -1, -1
5404 Xfake_acid_8, FALSE, FALSE,
5405 EL_EMC_FAKE_ACID, -1, -1
5408 Xsteel_1, TRUE, FALSE,
5409 EL_STEELWALL, -1, -1
5412 Xsteel_2, TRUE, FALSE,
5413 EL_EMC_STEELWALL_2, -1, -1
5416 Xsteel_3, TRUE, FALSE,
5417 EL_EMC_STEELWALL_3, -1, -1
5420 Xsteel_4, TRUE, FALSE,
5421 EL_EMC_STEELWALL_4, -1, -1
5424 Xwall_1, TRUE, FALSE,
5428 Xwall_2, TRUE, FALSE,
5429 EL_EMC_WALL_14, -1, -1
5432 Xwall_3, TRUE, FALSE,
5433 EL_EMC_WALL_15, -1, -1
5436 Xwall_4, TRUE, FALSE,
5437 EL_EMC_WALL_16, -1, -1
5440 Xround_wall_1, TRUE, FALSE,
5441 EL_WALL_SLIPPERY, -1, -1
5444 Xround_wall_2, TRUE, FALSE,
5445 EL_EMC_WALL_SLIPPERY_2, -1, -1
5448 Xround_wall_3, TRUE, FALSE,
5449 EL_EMC_WALL_SLIPPERY_3, -1, -1
5452 Xround_wall_4, TRUE, FALSE,
5453 EL_EMC_WALL_SLIPPERY_4, -1, -1
5456 Xdecor_1, TRUE, FALSE,
5457 EL_EMC_WALL_8, -1, -1
5460 Xdecor_2, TRUE, FALSE,
5461 EL_EMC_WALL_6, -1, -1
5464 Xdecor_3, TRUE, FALSE,
5465 EL_EMC_WALL_4, -1, -1
5468 Xdecor_4, TRUE, FALSE,
5469 EL_EMC_WALL_7, -1, -1
5472 Xdecor_5, TRUE, FALSE,
5473 EL_EMC_WALL_5, -1, -1
5476 Xdecor_6, TRUE, FALSE,
5477 EL_EMC_WALL_9, -1, -1
5480 Xdecor_7, TRUE, FALSE,
5481 EL_EMC_WALL_10, -1, -1
5484 Xdecor_8, TRUE, FALSE,
5485 EL_EMC_WALL_1, -1, -1
5488 Xdecor_9, TRUE, FALSE,
5489 EL_EMC_WALL_2, -1, -1
5492 Xdecor_10, TRUE, FALSE,
5493 EL_EMC_WALL_3, -1, -1
5496 Xdecor_11, TRUE, FALSE,
5497 EL_EMC_WALL_11, -1, -1
5500 Xdecor_12, TRUE, FALSE,
5501 EL_EMC_WALL_12, -1, -1
5504 Xalpha_0, TRUE, FALSE,
5505 EL_CHAR('0'), -1, -1
5508 Xalpha_1, TRUE, FALSE,
5509 EL_CHAR('1'), -1, -1
5512 Xalpha_2, TRUE, FALSE,
5513 EL_CHAR('2'), -1, -1
5516 Xalpha_3, TRUE, FALSE,
5517 EL_CHAR('3'), -1, -1
5520 Xalpha_4, TRUE, FALSE,
5521 EL_CHAR('4'), -1, -1
5524 Xalpha_5, TRUE, FALSE,
5525 EL_CHAR('5'), -1, -1
5528 Xalpha_6, TRUE, FALSE,
5529 EL_CHAR('6'), -1, -1
5532 Xalpha_7, TRUE, FALSE,
5533 EL_CHAR('7'), -1, -1
5536 Xalpha_8, TRUE, FALSE,
5537 EL_CHAR('8'), -1, -1
5540 Xalpha_9, TRUE, FALSE,
5541 EL_CHAR('9'), -1, -1
5544 Xalpha_excla, TRUE, FALSE,
5545 EL_CHAR('!'), -1, -1
5548 Xalpha_quote, TRUE, FALSE,
5549 EL_CHAR('"'), -1, -1
5552 Xalpha_comma, TRUE, FALSE,
5553 EL_CHAR(','), -1, -1
5556 Xalpha_minus, TRUE, FALSE,
5557 EL_CHAR('-'), -1, -1
5560 Xalpha_perio, TRUE, FALSE,
5561 EL_CHAR('.'), -1, -1
5564 Xalpha_colon, TRUE, FALSE,
5565 EL_CHAR(':'), -1, -1
5568 Xalpha_quest, TRUE, FALSE,
5569 EL_CHAR('?'), -1, -1
5572 Xalpha_a, TRUE, FALSE,
5573 EL_CHAR('A'), -1, -1
5576 Xalpha_b, TRUE, FALSE,
5577 EL_CHAR('B'), -1, -1
5580 Xalpha_c, TRUE, FALSE,
5581 EL_CHAR('C'), -1, -1
5584 Xalpha_d, TRUE, FALSE,
5585 EL_CHAR('D'), -1, -1
5588 Xalpha_e, TRUE, FALSE,
5589 EL_CHAR('E'), -1, -1
5592 Xalpha_f, TRUE, FALSE,
5593 EL_CHAR('F'), -1, -1
5596 Xalpha_g, TRUE, FALSE,
5597 EL_CHAR('G'), -1, -1
5600 Xalpha_h, TRUE, FALSE,
5601 EL_CHAR('H'), -1, -1
5604 Xalpha_i, TRUE, FALSE,
5605 EL_CHAR('I'), -1, -1
5608 Xalpha_j, TRUE, FALSE,
5609 EL_CHAR('J'), -1, -1
5612 Xalpha_k, TRUE, FALSE,
5613 EL_CHAR('K'), -1, -1
5616 Xalpha_l, TRUE, FALSE,
5617 EL_CHAR('L'), -1, -1
5620 Xalpha_m, TRUE, FALSE,
5621 EL_CHAR('M'), -1, -1
5624 Xalpha_n, TRUE, FALSE,
5625 EL_CHAR('N'), -1, -1
5628 Xalpha_o, TRUE, FALSE,
5629 EL_CHAR('O'), -1, -1
5632 Xalpha_p, TRUE, FALSE,
5633 EL_CHAR('P'), -1, -1
5636 Xalpha_q, TRUE, FALSE,
5637 EL_CHAR('Q'), -1, -1
5640 Xalpha_r, TRUE, FALSE,
5641 EL_CHAR('R'), -1, -1
5644 Xalpha_s, TRUE, FALSE,
5645 EL_CHAR('S'), -1, -1
5648 Xalpha_t, TRUE, FALSE,
5649 EL_CHAR('T'), -1, -1
5652 Xalpha_u, TRUE, FALSE,
5653 EL_CHAR('U'), -1, -1
5656 Xalpha_v, TRUE, FALSE,
5657 EL_CHAR('V'), -1, -1
5660 Xalpha_w, TRUE, FALSE,
5661 EL_CHAR('W'), -1, -1
5664 Xalpha_x, TRUE, FALSE,
5665 EL_CHAR('X'), -1, -1
5668 Xalpha_y, TRUE, FALSE,
5669 EL_CHAR('Y'), -1, -1
5672 Xalpha_z, TRUE, FALSE,
5673 EL_CHAR('Z'), -1, -1
5676 Xalpha_arrow_e, TRUE, FALSE,
5677 EL_CHAR('>'), -1, -1
5680 Xalpha_arrow_w, TRUE, FALSE,
5681 EL_CHAR('<'), -1, -1
5684 Xalpha_copyr, TRUE, FALSE,
5685 EL_CHAR('©'), -1, -1
5689 Xboom_bug, FALSE, FALSE,
5690 EL_BUG, ACTION_EXPLODING, -1
5693 Xboom_bomb, FALSE, FALSE,
5694 EL_BOMB, ACTION_EXPLODING, -1
5697 Xboom_android, FALSE, FALSE,
5698 EL_EMC_ANDROID, ACTION_OTHER, -1
5701 Xboom_1, FALSE, FALSE,
5702 EL_DEFAULT, ACTION_EXPLODING, -1
5705 Xboom_2, FALSE, FALSE,
5706 EL_DEFAULT, ACTION_EXPLODING, -1
5709 Znormal, FALSE, FALSE,
5713 Zdynamite, FALSE, FALSE,
5717 Zplayer, FALSE, FALSE,
5721 ZBORDER, FALSE, FALSE,
5731 static struct Mapping_EM_to_RND_player
5740 em_player_mapping_list[] =
5744 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5748 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5752 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5756 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5760 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5764 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5768 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5772 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5776 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5780 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5784 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5788 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5792 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5796 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5800 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5804 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5808 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5812 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5816 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5820 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5824 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5828 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5832 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5836 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5840 EL_PLAYER_1, ACTION_DEFAULT, -1,
5844 EL_PLAYER_2, ACTION_DEFAULT, -1,
5848 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5852 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5856 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5860 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5864 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5868 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5872 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5876 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5880 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5884 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5888 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5892 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5896 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5900 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5904 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5908 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5912 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5916 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5920 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5924 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5928 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5932 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5936 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5940 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5944 EL_PLAYER_3, ACTION_DEFAULT, -1,
5948 EL_PLAYER_4, ACTION_DEFAULT, -1,
5957 int map_element_RND_to_EM(int element_rnd)
5959 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5960 static boolean mapping_initialized = FALSE;
5962 if (!mapping_initialized)
5966 /* return "Xalpha_quest" for all undefined elements in mapping array */
5967 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5968 mapping_RND_to_EM[i] = Xalpha_quest;
5970 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5971 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5972 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5973 em_object_mapping_list[i].element_em;
5975 mapping_initialized = TRUE;
5978 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5979 return mapping_RND_to_EM[element_rnd];
5981 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5986 int map_element_EM_to_RND(int element_em)
5988 static unsigned short mapping_EM_to_RND[TILE_MAX];
5989 static boolean mapping_initialized = FALSE;
5991 if (!mapping_initialized)
5995 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5996 for (i = 0; i < TILE_MAX; i++)
5997 mapping_EM_to_RND[i] = EL_UNKNOWN;
5999 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6000 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6001 em_object_mapping_list[i].element_rnd;
6003 mapping_initialized = TRUE;
6006 if (element_em >= 0 && element_em < TILE_MAX)
6007 return mapping_EM_to_RND[element_em];
6009 Error(ERR_WARN, "invalid EM level element %d", element_em);
6014 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6016 struct LevelInfo_EM *level_em = level->native_em_level;
6017 struct LEVEL *lev = level_em->lev;
6020 for (i = 0; i < TILE_MAX; i++)
6021 lev->android_array[i] = Xblank;
6023 for (i = 0; i < level->num_android_clone_elements; i++)
6025 int element_rnd = level->android_clone_element[i];
6026 int element_em = map_element_RND_to_EM(element_rnd);
6028 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6029 if (em_object_mapping_list[j].element_rnd == element_rnd)
6030 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6034 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6036 struct LevelInfo_EM *level_em = level->native_em_level;
6037 struct LEVEL *lev = level_em->lev;
6040 level->num_android_clone_elements = 0;
6042 for (i = 0; i < TILE_MAX; i++)
6044 int element_em = lev->android_array[i];
6046 boolean element_found = FALSE;
6048 if (element_em == Xblank)
6051 element_rnd = map_element_EM_to_RND(element_em);
6053 for (j = 0; j < level->num_android_clone_elements; j++)
6054 if (level->android_clone_element[j] == element_rnd)
6055 element_found = TRUE;
6059 level->android_clone_element[level->num_android_clone_elements++] =
6062 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6067 if (level->num_android_clone_elements == 0)
6069 level->num_android_clone_elements = 1;
6070 level->android_clone_element[0] = EL_EMPTY;
6074 int map_direction_RND_to_EM(int direction)
6076 return (direction == MV_UP ? 0 :
6077 direction == MV_RIGHT ? 1 :
6078 direction == MV_DOWN ? 2 :
6079 direction == MV_LEFT ? 3 :
6083 int map_direction_EM_to_RND(int direction)
6085 return (direction == 0 ? MV_UP :
6086 direction == 1 ? MV_RIGHT :
6087 direction == 2 ? MV_DOWN :
6088 direction == 3 ? MV_LEFT :
6092 int map_element_RND_to_SP(int element_rnd)
6094 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6096 if (element_rnd >= EL_SP_START &&
6097 element_rnd <= EL_SP_END)
6098 element_sp = element_rnd - EL_SP_START;
6099 else if (element_rnd == EL_EMPTY_SPACE)
6101 else if (element_rnd == EL_INVISIBLE_WALL)
6107 int map_element_SP_to_RND(int element_sp)
6109 int element_rnd = EL_UNKNOWN;
6111 if (element_sp >= 0x00 &&
6113 element_rnd = EL_SP_START + element_sp;
6114 else if (element_sp == 0x28)
6115 element_rnd = EL_INVISIBLE_WALL;
6120 int map_action_SP_to_RND(int action_sp)
6124 case actActive: return ACTION_ACTIVE;
6125 case actImpact: return ACTION_IMPACT;
6126 case actExploding: return ACTION_EXPLODING;
6127 case actDigging: return ACTION_DIGGING;
6128 case actSnapping: return ACTION_SNAPPING;
6129 case actCollecting: return ACTION_COLLECTING;
6130 case actPassing: return ACTION_PASSING;
6131 case actPushing: return ACTION_PUSHING;
6132 case actDropping: return ACTION_DROPPING;
6134 default: return ACTION_DEFAULT;
6138 int get_next_element(int element)
6142 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6143 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6144 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6145 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6146 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6147 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6148 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6149 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6150 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6151 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6152 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6154 default: return element;
6159 int el_act_dir2img(int element, int action, int direction)
6161 element = GFX_ELEMENT(element);
6163 if (direction == MV_NONE)
6164 return element_info[element].graphic[action];
6166 direction = MV_DIR_TO_BIT(direction);
6168 return element_info[element].direction_graphic[action][direction];
6171 int el_act_dir2img(int element, int action, int direction)
6173 element = GFX_ELEMENT(element);
6174 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6176 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6177 return element_info[element].direction_graphic[action][direction];
6182 static int el_act_dir2crm(int element, int action, int direction)
6184 element = GFX_ELEMENT(element);
6186 if (direction == MV_NONE)
6187 return element_info[element].crumbled[action];
6189 direction = MV_DIR_TO_BIT(direction);
6191 return element_info[element].direction_crumbled[action][direction];
6194 static int el_act_dir2crm(int element, int action, int direction)
6196 element = GFX_ELEMENT(element);
6197 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6199 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6200 return element_info[element].direction_crumbled[action][direction];
6204 int el_act2img(int element, int action)
6206 element = GFX_ELEMENT(element);
6208 return element_info[element].graphic[action];
6211 int el_act2crm(int element, int action)
6213 element = GFX_ELEMENT(element);
6215 return element_info[element].crumbled[action];
6218 int el_dir2img(int element, int direction)
6220 element = GFX_ELEMENT(element);
6222 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6225 int el2baseimg(int element)
6227 return element_info[element].graphic[ACTION_DEFAULT];
6230 int el2img(int element)
6232 element = GFX_ELEMENT(element);
6234 return element_info[element].graphic[ACTION_DEFAULT];
6237 int el2edimg(int element)
6239 element = GFX_ELEMENT(element);
6241 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6244 int el2preimg(int element)
6246 element = GFX_ELEMENT(element);
6248 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6251 int el2panelimg(int element)
6253 element = GFX_ELEMENT(element);
6255 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6258 int font2baseimg(int font_nr)
6260 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6263 int getBeltNrFromBeltElement(int element)
6265 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6266 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6267 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6270 int getBeltNrFromBeltActiveElement(int element)
6272 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6273 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6274 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6277 int getBeltNrFromBeltSwitchElement(int element)
6279 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6280 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6281 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6284 int getBeltDirNrFromBeltElement(int element)
6286 static int belt_base_element[4] =
6288 EL_CONVEYOR_BELT_1_LEFT,
6289 EL_CONVEYOR_BELT_2_LEFT,
6290 EL_CONVEYOR_BELT_3_LEFT,
6291 EL_CONVEYOR_BELT_4_LEFT
6294 int belt_nr = getBeltNrFromBeltElement(element);
6295 int belt_dir_nr = element - belt_base_element[belt_nr];
6297 return (belt_dir_nr % 3);
6300 int getBeltDirNrFromBeltSwitchElement(int element)
6302 static int belt_base_element[4] =
6304 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6305 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6306 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6307 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6310 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6311 int belt_dir_nr = element - belt_base_element[belt_nr];
6313 return (belt_dir_nr % 3);
6316 int getBeltDirFromBeltElement(int element)
6318 static int belt_move_dir[3] =
6325 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6327 return belt_move_dir[belt_dir_nr];
6330 int getBeltDirFromBeltSwitchElement(int element)
6332 static int belt_move_dir[3] =
6339 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6341 return belt_move_dir[belt_dir_nr];
6344 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6346 static int belt_base_element[4] =
6348 EL_CONVEYOR_BELT_1_LEFT,
6349 EL_CONVEYOR_BELT_2_LEFT,
6350 EL_CONVEYOR_BELT_3_LEFT,
6351 EL_CONVEYOR_BELT_4_LEFT
6354 return belt_base_element[belt_nr] + belt_dir_nr;
6357 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6359 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6361 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6364 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6366 static int belt_base_element[4] =
6368 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6369 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6370 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6371 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6374 return belt_base_element[belt_nr] + belt_dir_nr;
6377 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6379 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6381 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6384 int getNumActivePlayers_EM()
6386 int num_players = 0;
6392 for (i = 0; i < MAX_PLAYERS; i++)
6393 if (tape.player_participates[i])
6399 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6401 int game_frame_delay_value;
6403 game_frame_delay_value =
6404 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6405 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6408 if (tape.playing && tape.warp_forward && !tape.pausing)
6409 game_frame_delay_value = 0;
6411 return game_frame_delay_value;
6414 unsigned int InitRND(long seed)
6416 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6417 return InitEngineRandom_EM(seed);
6418 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6419 return InitEngineRandom_SP(seed);
6421 return InitEngineRandom_RND(seed);
6425 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6426 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6429 inline static int get_effective_element_EM(int tile, int frame_em)
6431 int element = object_mapping[tile].element_rnd;
6432 int action = object_mapping[tile].action;
6433 boolean is_backside = object_mapping[tile].is_backside;
6434 boolean action_removing = (action == ACTION_DIGGING ||
6435 action == ACTION_SNAPPING ||
6436 action == ACTION_COLLECTING);
6442 case Yacid_splash_eB:
6443 case Yacid_splash_wB:
6444 return (frame_em > 5 ? EL_EMPTY : element);
6450 else /* frame_em == 7 */
6454 case Yacid_splash_eB:
6455 case Yacid_splash_wB:
6458 case Yemerald_stone:
6461 case Ydiamond_stone:
6465 case Xdrip_stretchB:
6484 case Xsand_stonein_1:
6485 case Xsand_stonein_2:
6486 case Xsand_stonein_3:
6487 case Xsand_stonein_4:
6491 return (is_backside || action_removing ? EL_EMPTY : element);
6496 inline static boolean check_linear_animation_EM(int tile)
6500 case Xsand_stonesand_1:
6501 case Xsand_stonesand_quickout_1:
6502 case Xsand_sandstone_1:
6503 case Xsand_stonein_1:
6504 case Xsand_stoneout_1:
6529 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6530 boolean has_crumbled_graphics,
6531 int crumbled, int sync_frame)
6533 /* if element can be crumbled, but certain action graphics are just empty
6534 space (like instantly snapping sand to empty space in 1 frame), do not
6535 treat these empty space graphics as crumbled graphics in EMC engine */
6536 if (crumbled == IMG_EMPTY_SPACE)
6537 has_crumbled_graphics = FALSE;
6539 if (has_crumbled_graphics)
6541 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6542 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6543 g_crumbled->anim_delay,
6544 g_crumbled->anim_mode,
6545 g_crumbled->anim_start_frame,
6548 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6549 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6551 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6553 g_em->has_crumbled_graphics = TRUE;
6557 g_em->crumbled_bitmap = NULL;
6558 g_em->crumbled_src_x = 0;
6559 g_em->crumbled_src_y = 0;
6560 g_em->crumbled_border_size = 0;
6562 g_em->has_crumbled_graphics = FALSE;
6566 void ResetGfxAnimation_EM(int x, int y, int tile)
6571 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6572 int tile, int frame_em, int x, int y)
6574 int action = object_mapping[tile].action;
6576 int direction = object_mapping[tile].direction;
6577 int effective_element = get_effective_element_EM(tile, frame_em);
6578 int graphic = (direction == MV_NONE ?
6579 el_act2img(effective_element, action) :
6580 el_act_dir2img(effective_element, action, direction));
6581 struct GraphicInfo *g = &graphic_info[graphic];
6584 boolean action_removing = (action == ACTION_DIGGING ||
6585 action == ACTION_SNAPPING ||
6586 action == ACTION_COLLECTING);
6587 boolean action_moving = (action == ACTION_FALLING ||
6588 action == ACTION_MOVING ||
6589 action == ACTION_PUSHING ||
6590 action == ACTION_EATING ||
6591 action == ACTION_FILLING ||
6592 action == ACTION_EMPTYING);
6593 boolean action_falling = (action == ACTION_FALLING ||
6594 action == ACTION_FILLING ||
6595 action == ACTION_EMPTYING);
6597 /* special case: graphic uses "2nd movement tile" and has defined
6598 7 frames for movement animation (or less) => use default graphic
6599 for last (8th) frame which ends the movement animation */
6600 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6602 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6603 graphic = (direction == MV_NONE ?
6604 el_act2img(effective_element, action) :
6605 el_act_dir2img(effective_element, action, direction));
6607 g = &graphic_info[graphic];
6611 if (tile == Xsand_stonesand_1 ||
6612 tile == Xsand_stonesand_2 ||
6613 tile == Xsand_stonesand_3 ||
6614 tile == Xsand_stonesand_4)
6615 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6619 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6623 // printf("::: resetting... [%d]\n", tile);
6626 if (action_removing || check_linear_animation_EM(tile))
6628 GfxFrame[x][y] = frame_em;
6630 // printf("::: resetting... [%d]\n", tile);
6633 else if (action_moving)
6635 boolean is_backside = object_mapping[tile].is_backside;
6639 int direction = object_mapping[tile].direction;
6640 int move_dir = (action_falling ? MV_DOWN : direction);
6645 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6646 if (g->double_movement && frame_em == 0)
6650 // printf("::: resetting... [%d]\n", tile);
6654 if (move_dir == MV_LEFT)
6655 GfxFrame[x - 1][y] = GfxFrame[x][y];
6656 else if (move_dir == MV_RIGHT)
6657 GfxFrame[x + 1][y] = GfxFrame[x][y];
6658 else if (move_dir == MV_UP)
6659 GfxFrame[x][y - 1] = GfxFrame[x][y];
6660 else if (move_dir == MV_DOWN)
6661 GfxFrame[x][y + 1] = GfxFrame[x][y];
6668 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6669 if (tile == Xsand_stonesand_quickout_1 ||
6670 tile == Xsand_stonesand_quickout_2)
6675 if (tile == Xsand_stonesand_1 ||
6676 tile == Xsand_stonesand_2 ||
6677 tile == Xsand_stonesand_3 ||
6678 tile == Xsand_stonesand_4)
6679 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6683 if (graphic_info[graphic].anim_global_sync)
6684 sync_frame = FrameCounter;
6685 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6686 sync_frame = GfxFrame[x][y];
6688 sync_frame = 0; /* playfield border (pseudo steel) */
6690 SetRandomAnimationValue(x, y);
6692 int frame = getAnimationFrame(g->anim_frames,
6695 g->anim_start_frame,
6698 g_em->unique_identifier =
6699 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6703 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6704 int tile, int frame_em, int x, int y)
6706 int action = object_mapping[tile].action;
6707 int direction = object_mapping[tile].direction;
6708 boolean is_backside = object_mapping[tile].is_backside;
6709 int effective_element = get_effective_element_EM(tile, frame_em);
6711 int effective_action = action;
6713 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
6715 int graphic = (direction == MV_NONE ?
6716 el_act2img(effective_element, effective_action) :
6717 el_act_dir2img(effective_element, effective_action,
6719 int crumbled = (direction == MV_NONE ?
6720 el_act2crm(effective_element, effective_action) :
6721 el_act_dir2crm(effective_element, effective_action,
6723 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6724 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6725 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6726 struct GraphicInfo *g = &graphic_info[graphic];
6728 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6732 /* special case: graphic uses "2nd movement tile" and has defined
6733 7 frames for movement animation (or less) => use default graphic
6734 for last (8th) frame which ends the movement animation */
6735 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6737 effective_action = ACTION_DEFAULT;
6738 graphic = (direction == MV_NONE ?
6739 el_act2img(effective_element, effective_action) :
6740 el_act_dir2img(effective_element, effective_action,
6742 crumbled = (direction == MV_NONE ?
6743 el_act2crm(effective_element, effective_action) :
6744 el_act_dir2crm(effective_element, effective_action,
6747 g = &graphic_info[graphic];
6757 if (frame_em == 0) /* reset animation frame for certain elements */
6759 if (check_linear_animation_EM(tile))
6764 if (graphic_info[graphic].anim_global_sync)
6765 sync_frame = FrameCounter;
6766 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6767 sync_frame = GfxFrame[x][y];
6769 sync_frame = 0; /* playfield border (pseudo steel) */
6771 SetRandomAnimationValue(x, y);
6776 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6777 i == Xdrip_stretchB ? 7 :
6778 i == Ydrip_s2 ? j + 8 :
6779 i == Ydrip_s2B ? j + 8 :
6788 i == Xfake_acid_1 ? 0 :
6789 i == Xfake_acid_2 ? 10 :
6790 i == Xfake_acid_3 ? 20 :
6791 i == Xfake_acid_4 ? 30 :
6792 i == Xfake_acid_5 ? 40 :
6793 i == Xfake_acid_6 ? 50 :
6794 i == Xfake_acid_7 ? 60 :
6795 i == Xfake_acid_8 ? 70 :
6797 i == Xball_2B ? j + 8 :
6798 i == Yball_eat ? j + 1 :
6799 i == Ykey_1_eat ? j + 1 :
6800 i == Ykey_2_eat ? j + 1 :
6801 i == Ykey_3_eat ? j + 1 :
6802 i == Ykey_4_eat ? j + 1 :
6803 i == Ykey_5_eat ? j + 1 :
6804 i == Ykey_6_eat ? j + 1 :
6805 i == Ykey_7_eat ? j + 1 :
6806 i == Ykey_8_eat ? j + 1 :
6807 i == Ylenses_eat ? j + 1 :
6808 i == Ymagnify_eat ? j + 1 :
6809 i == Ygrass_eat ? j + 1 :
6810 i == Ydirt_eat ? j + 1 :
6811 i == Xamoeba_1 ? 0 :
6812 i == Xamoeba_2 ? 1 :
6813 i == Xamoeba_3 ? 2 :
6814 i == Xamoeba_4 ? 3 :
6815 i == Xamoeba_5 ? 0 :
6816 i == Xamoeba_6 ? 1 :
6817 i == Xamoeba_7 ? 2 :
6818 i == Xamoeba_8 ? 3 :
6819 i == Xexit_2 ? j + 8 :
6820 i == Xexit_3 ? j + 16 :
6821 i == Xdynamite_1 ? 0 :
6822 i == Xdynamite_2 ? 8 :
6823 i == Xdynamite_3 ? 16 :
6824 i == Xdynamite_4 ? 24 :
6825 i == Xsand_stonein_1 ? j + 1 :
6826 i == Xsand_stonein_2 ? j + 9 :
6827 i == Xsand_stonein_3 ? j + 17 :
6828 i == Xsand_stonein_4 ? j + 25 :
6829 i == Xsand_stoneout_1 && j == 0 ? 0 :
6830 i == Xsand_stoneout_1 && j == 1 ? 0 :
6831 i == Xsand_stoneout_1 && j == 2 ? 1 :
6832 i == Xsand_stoneout_1 && j == 3 ? 2 :
6833 i == Xsand_stoneout_1 && j == 4 ? 2 :
6834 i == Xsand_stoneout_1 && j == 5 ? 3 :
6835 i == Xsand_stoneout_1 && j == 6 ? 4 :
6836 i == Xsand_stoneout_1 && j == 7 ? 4 :
6837 i == Xsand_stoneout_2 && j == 0 ? 5 :
6838 i == Xsand_stoneout_2 && j == 1 ? 6 :
6839 i == Xsand_stoneout_2 && j == 2 ? 7 :
6840 i == Xsand_stoneout_2 && j == 3 ? 8 :
6841 i == Xsand_stoneout_2 && j == 4 ? 9 :
6842 i == Xsand_stoneout_2 && j == 5 ? 11 :
6843 i == Xsand_stoneout_2 && j == 6 ? 13 :
6844 i == Xsand_stoneout_2 && j == 7 ? 15 :
6845 i == Xboom_bug && j == 1 ? 2 :
6846 i == Xboom_bug && j == 2 ? 2 :
6847 i == Xboom_bug && j == 3 ? 4 :
6848 i == Xboom_bug && j == 4 ? 4 :
6849 i == Xboom_bug && j == 5 ? 2 :
6850 i == Xboom_bug && j == 6 ? 2 :
6851 i == Xboom_bug && j == 7 ? 0 :
6852 i == Xboom_bomb && j == 1 ? 2 :
6853 i == Xboom_bomb && j == 2 ? 2 :
6854 i == Xboom_bomb && j == 3 ? 4 :
6855 i == Xboom_bomb && j == 4 ? 4 :
6856 i == Xboom_bomb && j == 5 ? 2 :
6857 i == Xboom_bomb && j == 6 ? 2 :
6858 i == Xboom_bomb && j == 7 ? 0 :
6859 i == Xboom_android && j == 7 ? 6 :
6860 i == Xboom_1 && j == 1 ? 2 :
6861 i == Xboom_1 && j == 2 ? 2 :
6862 i == Xboom_1 && j == 3 ? 4 :
6863 i == Xboom_1 && j == 4 ? 4 :
6864 i == Xboom_1 && j == 5 ? 6 :
6865 i == Xboom_1 && j == 6 ? 6 :
6866 i == Xboom_1 && j == 7 ? 8 :
6867 i == Xboom_2 && j == 0 ? 8 :
6868 i == Xboom_2 && j == 1 ? 8 :
6869 i == Xboom_2 && j == 2 ? 10 :
6870 i == Xboom_2 && j == 3 ? 10 :
6871 i == Xboom_2 && j == 4 ? 10 :
6872 i == Xboom_2 && j == 5 ? 12 :
6873 i == Xboom_2 && j == 6 ? 12 :
6874 i == Xboom_2 && j == 7 ? 12 :
6876 special_animation && j == 4 ? 3 :
6877 effective_action != action ? 0 :
6883 int xxx_effective_action;
6884 int xxx_has_action_graphics;
6887 int element = object_mapping[i].element_rnd;
6888 int action = object_mapping[i].action;
6889 int direction = object_mapping[i].direction;
6890 boolean is_backside = object_mapping[i].is_backside;
6892 boolean action_removing = (action == ACTION_DIGGING ||
6893 action == ACTION_SNAPPING ||
6894 action == ACTION_COLLECTING);
6896 boolean action_exploding = ((action == ACTION_EXPLODING ||
6897 action == ACTION_SMASHED_BY_ROCK ||
6898 action == ACTION_SMASHED_BY_SPRING) &&
6899 element != EL_DIAMOND);
6900 boolean action_active = (action == ACTION_ACTIVE);
6901 boolean action_other = (action == ACTION_OTHER);
6905 int effective_element = get_effective_element_EM(i, j);
6907 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6908 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6910 i == Xdrip_stretch ? element :
6911 i == Xdrip_stretchB ? element :
6912 i == Ydrip_s1 ? element :
6913 i == Ydrip_s1B ? element :
6914 i == Xball_1B ? element :
6915 i == Xball_2 ? element :
6916 i == Xball_2B ? element :
6917 i == Yball_eat ? element :
6918 i == Ykey_1_eat ? element :
6919 i == Ykey_2_eat ? element :
6920 i == Ykey_3_eat ? element :
6921 i == Ykey_4_eat ? element :
6922 i == Ykey_5_eat ? element :
6923 i == Ykey_6_eat ? element :
6924 i == Ykey_7_eat ? element :
6925 i == Ykey_8_eat ? element :
6926 i == Ylenses_eat ? element :
6927 i == Ymagnify_eat ? element :
6928 i == Ygrass_eat ? element :
6929 i == Ydirt_eat ? element :
6930 i == Yemerald_stone ? EL_EMERALD :
6931 i == Ydiamond_stone ? EL_ROCK :
6932 i == Xsand_stonein_1 ? element :
6933 i == Xsand_stonein_2 ? element :
6934 i == Xsand_stonein_3 ? element :
6935 i == Xsand_stonein_4 ? element :
6936 is_backside ? EL_EMPTY :
6937 action_removing ? EL_EMPTY :
6940 int effective_action = (j < 7 ? action :
6941 i == Xdrip_stretch ? action :
6942 i == Xdrip_stretchB ? action :
6943 i == Ydrip_s1 ? action :
6944 i == Ydrip_s1B ? action :
6945 i == Xball_1B ? action :
6946 i == Xball_2 ? action :
6947 i == Xball_2B ? action :
6948 i == Yball_eat ? action :
6949 i == Ykey_1_eat ? action :
6950 i == Ykey_2_eat ? action :
6951 i == Ykey_3_eat ? action :
6952 i == Ykey_4_eat ? action :
6953 i == Ykey_5_eat ? action :
6954 i == Ykey_6_eat ? action :
6955 i == Ykey_7_eat ? action :
6956 i == Ykey_8_eat ? action :
6957 i == Ylenses_eat ? action :
6958 i == Ymagnify_eat ? action :
6959 i == Ygrass_eat ? action :
6960 i == Ydirt_eat ? action :
6961 i == Xsand_stonein_1 ? action :
6962 i == Xsand_stonein_2 ? action :
6963 i == Xsand_stonein_3 ? action :
6964 i == Xsand_stonein_4 ? action :
6965 i == Xsand_stoneout_1 ? action :
6966 i == Xsand_stoneout_2 ? action :
6967 i == Xboom_android ? ACTION_EXPLODING :
6968 action_exploding ? ACTION_EXPLODING :
6969 action_active ? action :
6970 action_other ? action :
6972 int graphic = (el_act_dir2img(effective_element, effective_action,
6974 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6976 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6977 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6978 boolean has_action_graphics = (graphic != base_graphic);
6979 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6980 struct GraphicInfo *g = &graphic_info[graphic];
6982 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6984 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6987 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6988 boolean special_animation = (action != ACTION_DEFAULT &&
6989 g->anim_frames == 3 &&
6990 g->anim_delay == 2 &&
6991 g->anim_mode & ANIM_LINEAR);
6992 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6993 i == Xdrip_stretchB ? 7 :
6994 i == Ydrip_s2 ? j + 8 :
6995 i == Ydrip_s2B ? j + 8 :
7004 i == Xfake_acid_1 ? 0 :
7005 i == Xfake_acid_2 ? 10 :
7006 i == Xfake_acid_3 ? 20 :
7007 i == Xfake_acid_4 ? 30 :
7008 i == Xfake_acid_5 ? 40 :
7009 i == Xfake_acid_6 ? 50 :
7010 i == Xfake_acid_7 ? 60 :
7011 i == Xfake_acid_8 ? 70 :
7013 i == Xball_2B ? j + 8 :
7014 i == Yball_eat ? j + 1 :
7015 i == Ykey_1_eat ? j + 1 :
7016 i == Ykey_2_eat ? j + 1 :
7017 i == Ykey_3_eat ? j + 1 :
7018 i == Ykey_4_eat ? j + 1 :
7019 i == Ykey_5_eat ? j + 1 :
7020 i == Ykey_6_eat ? j + 1 :
7021 i == Ykey_7_eat ? j + 1 :
7022 i == Ykey_8_eat ? j + 1 :
7023 i == Ylenses_eat ? j + 1 :
7024 i == Ymagnify_eat ? j + 1 :
7025 i == Ygrass_eat ? j + 1 :
7026 i == Ydirt_eat ? j + 1 :
7027 i == Xamoeba_1 ? 0 :
7028 i == Xamoeba_2 ? 1 :
7029 i == Xamoeba_3 ? 2 :
7030 i == Xamoeba_4 ? 3 :
7031 i == Xamoeba_5 ? 0 :
7032 i == Xamoeba_6 ? 1 :
7033 i == Xamoeba_7 ? 2 :
7034 i == Xamoeba_8 ? 3 :
7035 i == Xexit_2 ? j + 8 :
7036 i == Xexit_3 ? j + 16 :
7037 i == Xdynamite_1 ? 0 :
7038 i == Xdynamite_2 ? 8 :
7039 i == Xdynamite_3 ? 16 :
7040 i == Xdynamite_4 ? 24 :
7041 i == Xsand_stonein_1 ? j + 1 :
7042 i == Xsand_stonein_2 ? j + 9 :
7043 i == Xsand_stonein_3 ? j + 17 :
7044 i == Xsand_stonein_4 ? j + 25 :
7045 i == Xsand_stoneout_1 && j == 0 ? 0 :
7046 i == Xsand_stoneout_1 && j == 1 ? 0 :
7047 i == Xsand_stoneout_1 && j == 2 ? 1 :
7048 i == Xsand_stoneout_1 && j == 3 ? 2 :
7049 i == Xsand_stoneout_1 && j == 4 ? 2 :
7050 i == Xsand_stoneout_1 && j == 5 ? 3 :
7051 i == Xsand_stoneout_1 && j == 6 ? 4 :
7052 i == Xsand_stoneout_1 && j == 7 ? 4 :
7053 i == Xsand_stoneout_2 && j == 0 ? 5 :
7054 i == Xsand_stoneout_2 && j == 1 ? 6 :
7055 i == Xsand_stoneout_2 && j == 2 ? 7 :
7056 i == Xsand_stoneout_2 && j == 3 ? 8 :
7057 i == Xsand_stoneout_2 && j == 4 ? 9 :
7058 i == Xsand_stoneout_2 && j == 5 ? 11 :
7059 i == Xsand_stoneout_2 && j == 6 ? 13 :
7060 i == Xsand_stoneout_2 && j == 7 ? 15 :
7061 i == Xboom_bug && j == 1 ? 2 :
7062 i == Xboom_bug && j == 2 ? 2 :
7063 i == Xboom_bug && j == 3 ? 4 :
7064 i == Xboom_bug && j == 4 ? 4 :
7065 i == Xboom_bug && j == 5 ? 2 :
7066 i == Xboom_bug && j == 6 ? 2 :
7067 i == Xboom_bug && j == 7 ? 0 :
7068 i == Xboom_bomb && j == 1 ? 2 :
7069 i == Xboom_bomb && j == 2 ? 2 :
7070 i == Xboom_bomb && j == 3 ? 4 :
7071 i == Xboom_bomb && j == 4 ? 4 :
7072 i == Xboom_bomb && j == 5 ? 2 :
7073 i == Xboom_bomb && j == 6 ? 2 :
7074 i == Xboom_bomb && j == 7 ? 0 :
7075 i == Xboom_android && j == 7 ? 6 :
7076 i == Xboom_1 && j == 1 ? 2 :
7077 i == Xboom_1 && j == 2 ? 2 :
7078 i == Xboom_1 && j == 3 ? 4 :
7079 i == Xboom_1 && j == 4 ? 4 :
7080 i == Xboom_1 && j == 5 ? 6 :
7081 i == Xboom_1 && j == 6 ? 6 :
7082 i == Xboom_1 && j == 7 ? 8 :
7083 i == Xboom_2 && j == 0 ? 8 :
7084 i == Xboom_2 && j == 1 ? 8 :
7085 i == Xboom_2 && j == 2 ? 10 :
7086 i == Xboom_2 && j == 3 ? 10 :
7087 i == Xboom_2 && j == 4 ? 10 :
7088 i == Xboom_2 && j == 5 ? 12 :
7089 i == Xboom_2 && j == 6 ? 12 :
7090 i == Xboom_2 && j == 7 ? 12 :
7091 special_animation && j == 4 ? 3 :
7092 effective_action != action ? 0 :
7095 xxx_effective_action = effective_action;
7096 xxx_has_action_graphics = has_action_graphics;
7101 int frame = getAnimationFrame(g->anim_frames,
7104 g->anim_start_frame,
7118 int old_src_x = g_em->src_x;
7119 int old_src_y = g_em->src_y;
7123 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7124 g->double_movement && is_backside);
7126 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7127 &g_em->src_x, &g_em->src_y, FALSE);
7138 if (graphic == IMG_BUG_MOVING_RIGHT)
7139 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7140 g->double_movement, is_backside,
7141 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7149 g_em->src_offset_x = 0;
7150 g_em->src_offset_y = 0;
7151 g_em->dst_offset_x = 0;
7152 g_em->dst_offset_y = 0;
7153 g_em->width = TILEX;
7154 g_em->height = TILEY;
7156 g_em->preserve_background = FALSE;
7159 /* (updating the "crumbled" graphic definitions is probably not really needed,
7160 as animations for crumbled graphics can't be longer than one EMC cycle) */
7162 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7167 g_em->crumbled_bitmap = NULL;
7168 g_em->crumbled_src_x = 0;
7169 g_em->crumbled_src_y = 0;
7171 g_em->has_crumbled_graphics = FALSE;
7173 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7175 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7176 g_crumbled->anim_delay,
7177 g_crumbled->anim_mode,
7178 g_crumbled->anim_start_frame,
7181 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7182 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7184 g_em->has_crumbled_graphics = TRUE;
7190 int effective_action = xxx_effective_action;
7191 int has_action_graphics = xxx_has_action_graphics;
7193 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7194 effective_action == ACTION_MOVING ||
7195 effective_action == ACTION_PUSHING ||
7196 effective_action == ACTION_EATING)) ||
7197 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7198 effective_action == ACTION_EMPTYING)))
7201 (effective_action == ACTION_FALLING ||
7202 effective_action == ACTION_FILLING ||
7203 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7204 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7205 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7206 int num_steps = (i == Ydrip_s1 ? 16 :
7207 i == Ydrip_s1B ? 16 :
7208 i == Ydrip_s2 ? 16 :
7209 i == Ydrip_s2B ? 16 :
7210 i == Xsand_stonein_1 ? 32 :
7211 i == Xsand_stonein_2 ? 32 :
7212 i == Xsand_stonein_3 ? 32 :
7213 i == Xsand_stonein_4 ? 32 :
7214 i == Xsand_stoneout_1 ? 16 :
7215 i == Xsand_stoneout_2 ? 16 : 8);
7216 int cx = ABS(dx) * (TILEX / num_steps);
7217 int cy = ABS(dy) * (TILEY / num_steps);
7218 int step_frame = (i == Ydrip_s2 ? j + 8 :
7219 i == Ydrip_s2B ? j + 8 :
7220 i == Xsand_stonein_2 ? j + 8 :
7221 i == Xsand_stonein_3 ? j + 16 :
7222 i == Xsand_stonein_4 ? j + 24 :
7223 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7224 int step = (is_backside ? step_frame : num_steps - step_frame);
7226 if (is_backside) /* tile where movement starts */
7228 if (dx < 0 || dy < 0)
7230 g_em->src_offset_x = cx * step;
7231 g_em->src_offset_y = cy * step;
7235 g_em->dst_offset_x = cx * step;
7236 g_em->dst_offset_y = cy * step;
7239 else /* tile where movement ends */
7241 if (dx < 0 || dy < 0)
7243 g_em->dst_offset_x = cx * step;
7244 g_em->dst_offset_y = cy * step;
7248 g_em->src_offset_x = cx * step;
7249 g_em->src_offset_y = cy * step;
7253 g_em->width = TILEX - cx * step;
7254 g_em->height = TILEY - cy * step;
7257 /* create unique graphic identifier to decide if tile must be redrawn */
7258 /* bit 31 - 16 (16 bit): EM style graphic
7259 bit 15 - 12 ( 4 bit): EM style frame
7260 bit 11 - 6 ( 6 bit): graphic width
7261 bit 5 - 0 ( 6 bit): graphic height */
7262 g_em->unique_identifier =
7263 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7269 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7270 int player_nr, int anim, int frame_em)
7272 int element = player_mapping[player_nr][anim].element_rnd;
7273 int action = player_mapping[player_nr][anim].action;
7274 int direction = player_mapping[player_nr][anim].direction;
7275 int graphic = (direction == MV_NONE ?
7276 el_act2img(element, action) :
7277 el_act_dir2img(element, action, direction));
7278 struct GraphicInfo *g = &graphic_info[graphic];
7281 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7283 stored_player[player_nr].StepFrame = frame_em;
7285 sync_frame = stored_player[player_nr].Frame;
7287 int frame = getAnimationFrame(g->anim_frames,
7290 g->anim_start_frame,
7293 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7294 &g_em->src_x, &g_em->src_y, FALSE);
7297 printf("::: %d: %d, %d [%d]\n",
7299 stored_player[player_nr].Frame,
7300 stored_player[player_nr].StepFrame,
7305 void InitGraphicInfo_EM(void)
7308 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7309 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7314 int num_em_gfx_errors = 0;
7316 if (graphic_info_em_object[0][0].bitmap == NULL)
7318 /* EM graphics not yet initialized in em_open_all() */
7323 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7326 /* always start with reliable default values */
7327 for (i = 0; i < TILE_MAX; i++)
7329 object_mapping[i].element_rnd = EL_UNKNOWN;
7330 object_mapping[i].is_backside = FALSE;
7331 object_mapping[i].action = ACTION_DEFAULT;
7332 object_mapping[i].direction = MV_NONE;
7335 /* always start with reliable default values */
7336 for (p = 0; p < MAX_PLAYERS; p++)
7338 for (i = 0; i < SPR_MAX; i++)
7340 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7341 player_mapping[p][i].action = ACTION_DEFAULT;
7342 player_mapping[p][i].direction = MV_NONE;
7346 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7348 int e = em_object_mapping_list[i].element_em;
7350 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7351 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7353 if (em_object_mapping_list[i].action != -1)
7354 object_mapping[e].action = em_object_mapping_list[i].action;
7356 if (em_object_mapping_list[i].direction != -1)
7357 object_mapping[e].direction =
7358 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7361 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7363 int a = em_player_mapping_list[i].action_em;
7364 int p = em_player_mapping_list[i].player_nr;
7366 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7368 if (em_player_mapping_list[i].action != -1)
7369 player_mapping[p][a].action = em_player_mapping_list[i].action;
7371 if (em_player_mapping_list[i].direction != -1)
7372 player_mapping[p][a].direction =
7373 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7376 for (i = 0; i < TILE_MAX; i++)
7378 int element = object_mapping[i].element_rnd;
7379 int action = object_mapping[i].action;
7380 int direction = object_mapping[i].direction;
7381 boolean is_backside = object_mapping[i].is_backside;
7383 boolean action_removing = (action == ACTION_DIGGING ||
7384 action == ACTION_SNAPPING ||
7385 action == ACTION_COLLECTING);
7387 boolean action_exploding = ((action == ACTION_EXPLODING ||
7388 action == ACTION_SMASHED_BY_ROCK ||
7389 action == ACTION_SMASHED_BY_SPRING) &&
7390 element != EL_DIAMOND);
7391 boolean action_active = (action == ACTION_ACTIVE);
7392 boolean action_other = (action == ACTION_OTHER);
7394 for (j = 0; j < 8; j++)
7397 int effective_element = get_effective_element_EM(i, j);
7399 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7400 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7402 i == Xdrip_stretch ? element :
7403 i == Xdrip_stretchB ? element :
7404 i == Ydrip_s1 ? element :
7405 i == Ydrip_s1B ? element :
7406 i == Xball_1B ? element :
7407 i == Xball_2 ? element :
7408 i == Xball_2B ? element :
7409 i == Yball_eat ? element :
7410 i == Ykey_1_eat ? element :
7411 i == Ykey_2_eat ? element :
7412 i == Ykey_3_eat ? element :
7413 i == Ykey_4_eat ? element :
7414 i == Ykey_5_eat ? element :
7415 i == Ykey_6_eat ? element :
7416 i == Ykey_7_eat ? element :
7417 i == Ykey_8_eat ? element :
7418 i == Ylenses_eat ? element :
7419 i == Ymagnify_eat ? element :
7420 i == Ygrass_eat ? element :
7421 i == Ydirt_eat ? element :
7422 i == Yemerald_stone ? EL_EMERALD :
7423 i == Ydiamond_stone ? EL_ROCK :
7424 i == Xsand_stonein_1 ? element :
7425 i == Xsand_stonein_2 ? element :
7426 i == Xsand_stonein_3 ? element :
7427 i == Xsand_stonein_4 ? element :
7428 is_backside ? EL_EMPTY :
7429 action_removing ? EL_EMPTY :
7432 int effective_action = (j < 7 ? action :
7433 i == Xdrip_stretch ? action :
7434 i == Xdrip_stretchB ? action :
7435 i == Ydrip_s1 ? action :
7436 i == Ydrip_s1B ? action :
7437 i == Xball_1B ? action :
7438 i == Xball_2 ? action :
7439 i == Xball_2B ? action :
7440 i == Yball_eat ? action :
7441 i == Ykey_1_eat ? action :
7442 i == Ykey_2_eat ? action :
7443 i == Ykey_3_eat ? action :
7444 i == Ykey_4_eat ? action :
7445 i == Ykey_5_eat ? action :
7446 i == Ykey_6_eat ? action :
7447 i == Ykey_7_eat ? action :
7448 i == Ykey_8_eat ? action :
7449 i == Ylenses_eat ? action :
7450 i == Ymagnify_eat ? action :
7451 i == Ygrass_eat ? action :
7452 i == Ydirt_eat ? action :
7453 i == Xsand_stonein_1 ? action :
7454 i == Xsand_stonein_2 ? action :
7455 i == Xsand_stonein_3 ? action :
7456 i == Xsand_stonein_4 ? action :
7457 i == Xsand_stoneout_1 ? action :
7458 i == Xsand_stoneout_2 ? action :
7459 i == Xboom_android ? ACTION_EXPLODING :
7460 action_exploding ? ACTION_EXPLODING :
7461 action_active ? action :
7462 action_other ? action :
7464 int graphic = (el_act_dir2img(effective_element, effective_action,
7466 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7468 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7469 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7470 boolean has_action_graphics = (graphic != base_graphic);
7471 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7472 struct GraphicInfo *g = &graphic_info[graphic];
7474 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7476 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7479 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7480 boolean special_animation = (action != ACTION_DEFAULT &&
7481 g->anim_frames == 3 &&
7482 g->anim_delay == 2 &&
7483 g->anim_mode & ANIM_LINEAR);
7484 int sync_frame = (i == Xdrip_stretch ? 7 :
7485 i == Xdrip_stretchB ? 7 :
7486 i == Ydrip_s2 ? j + 8 :
7487 i == Ydrip_s2B ? j + 8 :
7496 i == Xfake_acid_1 ? 0 :
7497 i == Xfake_acid_2 ? 10 :
7498 i == Xfake_acid_3 ? 20 :
7499 i == Xfake_acid_4 ? 30 :
7500 i == Xfake_acid_5 ? 40 :
7501 i == Xfake_acid_6 ? 50 :
7502 i == Xfake_acid_7 ? 60 :
7503 i == Xfake_acid_8 ? 70 :
7505 i == Xball_2B ? j + 8 :
7506 i == Yball_eat ? j + 1 :
7507 i == Ykey_1_eat ? j + 1 :
7508 i == Ykey_2_eat ? j + 1 :
7509 i == Ykey_3_eat ? j + 1 :
7510 i == Ykey_4_eat ? j + 1 :
7511 i == Ykey_5_eat ? j + 1 :
7512 i == Ykey_6_eat ? j + 1 :
7513 i == Ykey_7_eat ? j + 1 :
7514 i == Ykey_8_eat ? j + 1 :
7515 i == Ylenses_eat ? j + 1 :
7516 i == Ymagnify_eat ? j + 1 :
7517 i == Ygrass_eat ? j + 1 :
7518 i == Ydirt_eat ? j + 1 :
7519 i == Xamoeba_1 ? 0 :
7520 i == Xamoeba_2 ? 1 :
7521 i == Xamoeba_3 ? 2 :
7522 i == Xamoeba_4 ? 3 :
7523 i == Xamoeba_5 ? 0 :
7524 i == Xamoeba_6 ? 1 :
7525 i == Xamoeba_7 ? 2 :
7526 i == Xamoeba_8 ? 3 :
7527 i == Xexit_2 ? j + 8 :
7528 i == Xexit_3 ? j + 16 :
7529 i == Xdynamite_1 ? 0 :
7530 i == Xdynamite_2 ? 8 :
7531 i == Xdynamite_3 ? 16 :
7532 i == Xdynamite_4 ? 24 :
7533 i == Xsand_stonein_1 ? j + 1 :
7534 i == Xsand_stonein_2 ? j + 9 :
7535 i == Xsand_stonein_3 ? j + 17 :
7536 i == Xsand_stonein_4 ? j + 25 :
7537 i == Xsand_stoneout_1 && j == 0 ? 0 :
7538 i == Xsand_stoneout_1 && j == 1 ? 0 :
7539 i == Xsand_stoneout_1 && j == 2 ? 1 :
7540 i == Xsand_stoneout_1 && j == 3 ? 2 :
7541 i == Xsand_stoneout_1 && j == 4 ? 2 :
7542 i == Xsand_stoneout_1 && j == 5 ? 3 :
7543 i == Xsand_stoneout_1 && j == 6 ? 4 :
7544 i == Xsand_stoneout_1 && j == 7 ? 4 :
7545 i == Xsand_stoneout_2 && j == 0 ? 5 :
7546 i == Xsand_stoneout_2 && j == 1 ? 6 :
7547 i == Xsand_stoneout_2 && j == 2 ? 7 :
7548 i == Xsand_stoneout_2 && j == 3 ? 8 :
7549 i == Xsand_stoneout_2 && j == 4 ? 9 :
7550 i == Xsand_stoneout_2 && j == 5 ? 11 :
7551 i == Xsand_stoneout_2 && j == 6 ? 13 :
7552 i == Xsand_stoneout_2 && j == 7 ? 15 :
7553 i == Xboom_bug && j == 1 ? 2 :
7554 i == Xboom_bug && j == 2 ? 2 :
7555 i == Xboom_bug && j == 3 ? 4 :
7556 i == Xboom_bug && j == 4 ? 4 :
7557 i == Xboom_bug && j == 5 ? 2 :
7558 i == Xboom_bug && j == 6 ? 2 :
7559 i == Xboom_bug && j == 7 ? 0 :
7560 i == Xboom_bomb && j == 1 ? 2 :
7561 i == Xboom_bomb && j == 2 ? 2 :
7562 i == Xboom_bomb && j == 3 ? 4 :
7563 i == Xboom_bomb && j == 4 ? 4 :
7564 i == Xboom_bomb && j == 5 ? 2 :
7565 i == Xboom_bomb && j == 6 ? 2 :
7566 i == Xboom_bomb && j == 7 ? 0 :
7567 i == Xboom_android && j == 7 ? 6 :
7568 i == Xboom_1 && j == 1 ? 2 :
7569 i == Xboom_1 && j == 2 ? 2 :
7570 i == Xboom_1 && j == 3 ? 4 :
7571 i == Xboom_1 && j == 4 ? 4 :
7572 i == Xboom_1 && j == 5 ? 6 :
7573 i == Xboom_1 && j == 6 ? 6 :
7574 i == Xboom_1 && j == 7 ? 8 :
7575 i == Xboom_2 && j == 0 ? 8 :
7576 i == Xboom_2 && j == 1 ? 8 :
7577 i == Xboom_2 && j == 2 ? 10 :
7578 i == Xboom_2 && j == 3 ? 10 :
7579 i == Xboom_2 && j == 4 ? 10 :
7580 i == Xboom_2 && j == 5 ? 12 :
7581 i == Xboom_2 && j == 6 ? 12 :
7582 i == Xboom_2 && j == 7 ? 12 :
7583 special_animation && j == 4 ? 3 :
7584 effective_action != action ? 0 :
7588 Bitmap *debug_bitmap = g_em->bitmap;
7589 int debug_src_x = g_em->src_x;
7590 int debug_src_y = g_em->src_y;
7593 int frame = getAnimationFrame(g->anim_frames,
7596 g->anim_start_frame,
7599 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7600 g->double_movement && is_backside);
7602 g_em->bitmap = src_bitmap;
7603 g_em->src_x = src_x;
7604 g_em->src_y = src_y;
7605 g_em->src_offset_x = 0;
7606 g_em->src_offset_y = 0;
7607 g_em->dst_offset_x = 0;
7608 g_em->dst_offset_y = 0;
7609 g_em->width = TILEX;
7610 g_em->height = TILEY;
7612 g_em->preserve_background = FALSE;
7615 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7620 g_em->crumbled_bitmap = NULL;
7621 g_em->crumbled_src_x = 0;
7622 g_em->crumbled_src_y = 0;
7623 g_em->crumbled_border_size = 0;
7625 g_em->has_crumbled_graphics = FALSE;
7628 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
7629 printf("::: empty crumbled: %d [%s], %d, %d\n",
7630 effective_element, element_info[effective_element].token_name,
7631 effective_action, direction);
7634 /* if element can be crumbled, but certain action graphics are just empty
7635 space (like instantly snapping sand to empty space in 1 frame), do not
7636 treat these empty space graphics as crumbled graphics in EMC engine */
7637 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7639 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7640 g_crumbled->anim_delay,
7641 g_crumbled->anim_mode,
7642 g_crumbled->anim_start_frame,
7645 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
7647 g_em->has_crumbled_graphics = TRUE;
7648 g_em->crumbled_bitmap = src_bitmap;
7649 g_em->crumbled_src_x = src_x;
7650 g_em->crumbled_src_y = src_y;
7651 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7655 if (g_em == &graphic_info_em_object[207][0])
7656 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
7657 graphic_info_em_object[207][0].crumbled_src_x,
7658 graphic_info_em_object[207][0].crumbled_src_y,
7660 crumbled, frame, src_x, src_y,
7665 g->anim_start_frame,
7667 gfx.anim_random_frame,
7672 printf("::: EMC tile %d is crumbled\n", i);
7678 if (element == EL_ROCK &&
7679 effective_action == ACTION_FILLING)
7680 printf("::: has_action_graphics == %d\n", has_action_graphics);
7683 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7684 effective_action == ACTION_MOVING ||
7685 effective_action == ACTION_PUSHING ||
7686 effective_action == ACTION_EATING)) ||
7687 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7688 effective_action == ACTION_EMPTYING)))
7691 (effective_action == ACTION_FALLING ||
7692 effective_action == ACTION_FILLING ||
7693 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7694 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7695 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7696 int num_steps = (i == Ydrip_s1 ? 16 :
7697 i == Ydrip_s1B ? 16 :
7698 i == Ydrip_s2 ? 16 :
7699 i == Ydrip_s2B ? 16 :
7700 i == Xsand_stonein_1 ? 32 :
7701 i == Xsand_stonein_2 ? 32 :
7702 i == Xsand_stonein_3 ? 32 :
7703 i == Xsand_stonein_4 ? 32 :
7704 i == Xsand_stoneout_1 ? 16 :
7705 i == Xsand_stoneout_2 ? 16 : 8);
7706 int cx = ABS(dx) * (TILEX / num_steps);
7707 int cy = ABS(dy) * (TILEY / num_steps);
7708 int step_frame = (i == Ydrip_s2 ? j + 8 :
7709 i == Ydrip_s2B ? j + 8 :
7710 i == Xsand_stonein_2 ? j + 8 :
7711 i == Xsand_stonein_3 ? j + 16 :
7712 i == Xsand_stonein_4 ? j + 24 :
7713 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7714 int step = (is_backside ? step_frame : num_steps - step_frame);
7716 if (is_backside) /* tile where movement starts */
7718 if (dx < 0 || dy < 0)
7720 g_em->src_offset_x = cx * step;
7721 g_em->src_offset_y = cy * step;
7725 g_em->dst_offset_x = cx * step;
7726 g_em->dst_offset_y = cy * step;
7729 else /* tile where movement ends */
7731 if (dx < 0 || dy < 0)
7733 g_em->dst_offset_x = cx * step;
7734 g_em->dst_offset_y = cy * step;
7738 g_em->src_offset_x = cx * step;
7739 g_em->src_offset_y = cy * step;
7743 g_em->width = TILEX - cx * step;
7744 g_em->height = TILEY - cy * step;
7747 /* create unique graphic identifier to decide if tile must be redrawn */
7748 /* bit 31 - 16 (16 bit): EM style graphic
7749 bit 15 - 12 ( 4 bit): EM style frame
7750 bit 11 - 6 ( 6 bit): graphic width
7751 bit 5 - 0 ( 6 bit): graphic height */
7752 g_em->unique_identifier =
7753 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7757 /* skip check for EMC elements not contained in original EMC artwork */
7758 if (element == EL_EMC_FAKE_ACID)
7761 if (g_em->bitmap != debug_bitmap ||
7762 g_em->src_x != debug_src_x ||
7763 g_em->src_y != debug_src_y ||
7764 g_em->src_offset_x != 0 ||
7765 g_em->src_offset_y != 0 ||
7766 g_em->dst_offset_x != 0 ||
7767 g_em->dst_offset_y != 0 ||
7768 g_em->width != TILEX ||
7769 g_em->height != TILEY)
7771 static int last_i = -1;
7779 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7780 i, element, element_info[element].token_name,
7781 element_action_info[effective_action].suffix, direction);
7783 if (element != effective_element)
7784 printf(" [%d ('%s')]",
7786 element_info[effective_element].token_name);
7790 if (g_em->bitmap != debug_bitmap)
7791 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7792 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7794 if (g_em->src_x != debug_src_x ||
7795 g_em->src_y != debug_src_y)
7796 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7797 j, (is_backside ? 'B' : 'F'),
7798 g_em->src_x, g_em->src_y,
7799 g_em->src_x / 32, g_em->src_y / 32,
7800 debug_src_x, debug_src_y,
7801 debug_src_x / 32, debug_src_y / 32);
7803 if (g_em->src_offset_x != 0 ||
7804 g_em->src_offset_y != 0 ||
7805 g_em->dst_offset_x != 0 ||
7806 g_em->dst_offset_y != 0)
7807 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7809 g_em->src_offset_x, g_em->src_offset_y,
7810 g_em->dst_offset_x, g_em->dst_offset_y);
7812 if (g_em->width != TILEX ||
7813 g_em->height != TILEY)
7814 printf(" %d (%d): size %d,%d should be %d,%d\n",
7816 g_em->width, g_em->height, TILEX, TILEY);
7818 num_em_gfx_errors++;
7825 for (i = 0; i < TILE_MAX; i++)
7827 for (j = 0; j < 8; j++)
7829 int element = object_mapping[i].element_rnd;
7830 int action = object_mapping[i].action;
7831 int direction = object_mapping[i].direction;
7832 boolean is_backside = object_mapping[i].is_backside;
7833 int graphic_action = el_act_dir2img(element, action, direction);
7834 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7836 if ((action == ACTION_SMASHED_BY_ROCK ||
7837 action == ACTION_SMASHED_BY_SPRING ||
7838 action == ACTION_EATING) &&
7839 graphic_action == graphic_default)
7841 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7842 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7843 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7844 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7847 /* no separate animation for "smashed by rock" -- use rock instead */
7848 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7849 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7851 g_em->bitmap = g_xx->bitmap;
7852 g_em->src_x = g_xx->src_x;
7853 g_em->src_y = g_xx->src_y;
7854 g_em->src_offset_x = g_xx->src_offset_x;
7855 g_em->src_offset_y = g_xx->src_offset_y;
7856 g_em->dst_offset_x = g_xx->dst_offset_x;
7857 g_em->dst_offset_y = g_xx->dst_offset_y;
7858 g_em->width = g_xx->width;
7859 g_em->height = g_xx->height;
7860 g_em->unique_identifier = g_xx->unique_identifier;
7863 g_em->preserve_background = TRUE;
7868 for (p = 0; p < MAX_PLAYERS; p++)
7870 for (i = 0; i < SPR_MAX; i++)
7872 int element = player_mapping[p][i].element_rnd;
7873 int action = player_mapping[p][i].action;
7874 int direction = player_mapping[p][i].direction;
7876 for (j = 0; j < 8; j++)
7878 int effective_element = element;
7879 int effective_action = action;
7880 int graphic = (direction == MV_NONE ?
7881 el_act2img(effective_element, effective_action) :
7882 el_act_dir2img(effective_element, effective_action,
7884 struct GraphicInfo *g = &graphic_info[graphic];
7885 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7891 Bitmap *debug_bitmap = g_em->bitmap;
7892 int debug_src_x = g_em->src_x;
7893 int debug_src_y = g_em->src_y;
7896 int frame = getAnimationFrame(g->anim_frames,
7899 g->anim_start_frame,
7902 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7904 g_em->bitmap = src_bitmap;
7905 g_em->src_x = src_x;
7906 g_em->src_y = src_y;
7907 g_em->src_offset_x = 0;
7908 g_em->src_offset_y = 0;
7909 g_em->dst_offset_x = 0;
7910 g_em->dst_offset_y = 0;
7911 g_em->width = TILEX;
7912 g_em->height = TILEY;
7916 /* skip check for EMC elements not contained in original EMC artwork */
7917 if (element == EL_PLAYER_3 ||
7918 element == EL_PLAYER_4)
7921 if (g_em->bitmap != debug_bitmap ||
7922 g_em->src_x != debug_src_x ||
7923 g_em->src_y != debug_src_y)
7925 static int last_i = -1;
7933 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7934 p, i, element, element_info[element].token_name,
7935 element_action_info[effective_action].suffix, direction);
7937 if (element != effective_element)
7938 printf(" [%d ('%s')]",
7940 element_info[effective_element].token_name);
7944 if (g_em->bitmap != debug_bitmap)
7945 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7946 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7948 if (g_em->src_x != debug_src_x ||
7949 g_em->src_y != debug_src_y)
7950 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7952 g_em->src_x, g_em->src_y,
7953 g_em->src_x / 32, g_em->src_y / 32,
7954 debug_src_x, debug_src_y,
7955 debug_src_x / 32, debug_src_y / 32);
7957 num_em_gfx_errors++;
7967 printf("::: [%d errors found]\n", num_em_gfx_errors);
7973 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7974 int graphic, int sync_frame, int x, int y)
7976 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7978 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7981 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7983 return (IS_NEXT_FRAME(sync_frame, graphic));
7986 int getGraphicInfo_Delay(int graphic)
7988 return graphic_info[graphic].anim_delay;
7991 void PlayMenuSoundExt(int sound)
7993 if (sound == SND_UNDEFINED)
7996 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7997 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8000 if (IS_LOOP_SOUND(sound))
8001 PlaySoundLoop(sound);
8006 void PlayMenuSound()
8008 PlayMenuSoundExt(menu.sound[game_status]);
8011 void PlayMenuSoundStereo(int sound, int stereo_position)
8013 if (sound == SND_UNDEFINED)
8016 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8017 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8020 if (IS_LOOP_SOUND(sound))
8021 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8023 PlaySoundStereo(sound, stereo_position);
8026 void PlayMenuSoundIfLoopExt(int sound)
8028 if (sound == SND_UNDEFINED)
8031 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8032 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8035 if (IS_LOOP_SOUND(sound))
8036 PlaySoundLoop(sound);
8039 void PlayMenuSoundIfLoop()
8041 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8044 void PlayMenuMusicExt(int music)
8046 if (music == MUS_UNDEFINED)
8049 if (!setup.sound_music)
8055 void PlayMenuMusic()
8057 PlayMenuMusicExt(menu.music[game_status]);
8060 void PlaySoundActivating()
8063 PlaySound(SND_MENU_ITEM_ACTIVATING);
8067 void PlaySoundSelecting()
8070 PlaySound(SND_MENU_ITEM_SELECTING);
8074 void ToggleFullscreenIfNeeded()
8076 boolean change_fullscreen = (setup.fullscreen !=
8077 video.fullscreen_enabled);
8078 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8079 !strEqual(setup.fullscreen_mode,
8080 video.fullscreen_mode_current));
8082 if (!video.fullscreen_available)
8086 if (change_fullscreen || change_fullscreen_mode)
8088 if (setup.fullscreen != video.fullscreen_enabled ||
8089 setup.fullscreen_mode != video.fullscreen_mode_current)
8092 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8094 /* save backbuffer content which gets lost when toggling fullscreen mode */
8095 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8098 if (change_fullscreen_mode)
8100 if (setup.fullscreen && video.fullscreen_enabled)
8103 /* keep fullscreen, but change fullscreen mode (screen resolution) */
8105 /* (this is now set in sdl.c) */
8107 video.fullscreen_mode_current = setup.fullscreen_mode;
8109 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
8112 /* toggle fullscreen */
8113 ChangeVideoModeIfNeeded(setup.fullscreen);
8115 setup.fullscreen = video.fullscreen_enabled;
8117 /* restore backbuffer content from temporary backbuffer backup bitmap */
8118 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8120 FreeBitmap(tmp_backbuffer);
8123 /* update visible window/screen */
8124 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8126 redraw_mask = REDRAW_ALL;