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 && !game.envelope_active)
153 width = gfx.sxsize + 2 * TILEX;
154 height = gfx.sysize + 2 * TILEY;
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 for (xx = BX1; xx <= BX2; xx++)
164 for (yy = BY1; yy <= BY2; yy++)
165 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
166 DrawScreenField(xx, yy);
170 if (setup.soft_scrolling)
172 int fx = FX, fy = FY;
174 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
175 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
177 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
189 BlitBitmap(drawto, window, x, y, width, height, x, y);
192 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
194 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
196 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
197 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
200 void DrawMaskedBorder_FIELD()
202 if (global.border_status >= GAME_MODE_TITLE &&
203 global.border_status <= GAME_MODE_PLAYING &&
204 border.draw_masked[global.border_status])
205 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
208 void DrawMaskedBorder_DOOR_1()
210 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
211 (global.border_status != GAME_MODE_EDITOR ||
212 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
213 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
216 void DrawMaskedBorder_DOOR_2()
218 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
219 global.border_status != GAME_MODE_EDITOR)
220 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
223 void DrawMaskedBorder_DOOR_3()
225 /* currently not available */
228 void DrawMaskedBorder_ALL()
230 DrawMaskedBorder_FIELD();
231 DrawMaskedBorder_DOOR_1();
232 DrawMaskedBorder_DOOR_2();
233 DrawMaskedBorder_DOOR_3();
236 void DrawMaskedBorder(int redraw_mask)
238 /* never draw masked screen borders on borderless screens */
239 if (effectiveGameStatus() == GAME_MODE_LOADING ||
240 effectiveGameStatus() == GAME_MODE_TITLE)
243 if (redraw_mask & REDRAW_ALL)
244 DrawMaskedBorder_ALL();
247 if (redraw_mask & REDRAW_FIELD)
248 DrawMaskedBorder_FIELD();
249 if (redraw_mask & REDRAW_DOOR_1)
250 DrawMaskedBorder_DOOR_1();
251 if (redraw_mask & REDRAW_DOOR_2)
252 DrawMaskedBorder_DOOR_2();
253 if (redraw_mask & REDRAW_DOOR_3)
254 DrawMaskedBorder_DOOR_3();
261 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
263 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
264 redraw_mask |= REDRAW_FIELD;
266 if (redraw_mask & REDRAW_FIELD)
267 redraw_mask &= ~REDRAW_TILES;
269 if (redraw_mask == REDRAW_NONE)
272 if (redraw_mask & REDRAW_TILES &&
273 game_status == GAME_MODE_PLAYING &&
274 border.draw_masked[GAME_MODE_PLAYING])
275 redraw_mask |= REDRAW_FIELD;
277 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
279 static boolean last_frame_skipped = FALSE;
280 boolean skip_even_when_not_scrolling = TRUE;
281 boolean just_scrolling = (ScreenMovDir != 0);
282 boolean verbose = FALSE;
284 if (global.fps_slowdown_factor > 1 &&
285 (FrameCounter % global.fps_slowdown_factor) &&
286 (just_scrolling || skip_even_when_not_scrolling))
288 redraw_mask &= ~REDRAW_MAIN;
290 last_frame_skipped = TRUE;
293 printf("FRAME SKIPPED\n");
297 if (last_frame_skipped)
298 redraw_mask |= REDRAW_FIELD;
300 last_frame_skipped = FALSE;
303 printf("frame not skipped\n");
307 /* synchronize X11 graphics at this point; if we would synchronize the
308 display immediately after the buffer switching (after the XFlush),
309 this could mean that we have to wait for the graphics to complete,
310 although we could go on doing calculations for the next frame */
314 /* prevent drawing masked border to backbuffer when using playfield buffer */
315 if (game_status != GAME_MODE_PLAYING ||
316 redraw_mask & REDRAW_FROM_BACKBUFFER ||
317 buffer == backbuffer)
318 DrawMaskedBorder(redraw_mask);
320 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
322 if (redraw_mask & REDRAW_ALL)
324 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
326 redraw_mask = REDRAW_NONE;
329 if (redraw_mask & REDRAW_FIELD)
331 if (game_status != GAME_MODE_PLAYING ||
332 redraw_mask & REDRAW_FROM_BACKBUFFER)
334 BlitBitmap(backbuffer, window,
335 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
339 int fx = FX, fy = FY;
341 if (setup.soft_scrolling)
343 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
344 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
347 if (setup.soft_scrolling ||
348 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
349 ABS(ScreenMovPos) == ScrollStepSize ||
350 redraw_tiles > REDRAWTILES_THRESHOLD)
352 if (border.draw_masked[GAME_MODE_PLAYING])
354 if (buffer != backbuffer)
356 /* copy playfield buffer to backbuffer to add masked border */
357 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
358 DrawMaskedBorder(REDRAW_FIELD);
361 BlitBitmap(backbuffer, window,
362 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
367 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
372 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
374 (setup.soft_scrolling ?
375 "setup.soft_scrolling" :
376 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
377 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
378 ABS(ScreenGfxPos) == ScrollStepSize ?
379 "ABS(ScreenGfxPos) == ScrollStepSize" :
380 "redraw_tiles > REDRAWTILES_THRESHOLD"));
386 redraw_mask &= ~REDRAW_MAIN;
389 if (redraw_mask & REDRAW_DOORS)
391 if (redraw_mask & REDRAW_DOOR_1)
392 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
394 if (redraw_mask & REDRAW_DOOR_2)
395 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
397 if (redraw_mask & REDRAW_DOOR_3)
398 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
400 redraw_mask &= ~REDRAW_DOORS;
403 if (redraw_mask & REDRAW_MICROLEVEL)
405 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
406 SX, SY + 10 * TILEY);
408 redraw_mask &= ~REDRAW_MICROLEVEL;
411 if (redraw_mask & REDRAW_TILES)
413 for (x = 0; x < SCR_FIELDX; x++)
414 for (y = 0 ; y < SCR_FIELDY; y++)
415 if (redraw[redraw_x1 + x][redraw_y1 + y])
416 BlitBitmap(buffer, window,
417 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
418 SX + x * TILEX, SY + y * TILEY);
421 if (redraw_mask & REDRAW_FPS) /* display frames per second */
426 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
427 if (!global.fps_slowdown)
430 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
431 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
436 for (x = 0; x < MAX_BUF_XSIZE; x++)
437 for (y = 0; y < MAX_BUF_YSIZE; y++)
440 redraw_mask = REDRAW_NONE;
443 static void FadeCrossSaveBackbuffer()
445 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
448 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
450 static int fade_type_skip = FADE_TYPE_NONE;
451 void (*draw_border_function)(void) = NULL;
452 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
453 int x, y, width, height;
454 int fade_delay, post_delay;
456 if (fade_type == FADE_TYPE_FADE_OUT)
458 if (fade_type_skip != FADE_TYPE_NONE)
461 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
464 /* skip all fade operations until specified fade operation */
465 if (fade_type & fade_type_skip)
466 fade_type_skip = FADE_TYPE_NONE;
471 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
473 FadeCrossSaveBackbuffer();
479 redraw_mask |= fade_mask;
481 if (fade_type == FADE_TYPE_SKIP)
484 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
487 fade_type_skip = fade_mode;
492 if (fade_type_skip != FADE_TYPE_NONE)
495 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
498 /* skip all fade operations until specified fade operation */
499 if (fade_type & fade_type_skip)
500 fade_type_skip = FADE_TYPE_NONE;
506 if (global.autoplay_leveldir)
508 // fading.fade_mode = FADE_MODE_NONE;
515 if (fading.fade_mode == FADE_MODE_NONE)
523 /* !!! what abount fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
526 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
530 if (fade_mask == REDRAW_NONE)
531 fade_mask = REDRAW_FIELD;
534 // if (fade_mask & REDRAW_FIELD)
535 if (fade_mask == REDRAW_FIELD)
540 height = FULL_SYSIZE;
542 fade_delay = fading.fade_delay;
543 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
545 if (border.draw_masked_when_fading)
546 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
548 DrawMaskedBorder_FIELD(); /* draw once */
550 else /* REDRAW_ALL */
557 fade_delay = fading.fade_delay;
558 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
562 if (!setup.fade_screens ||
564 fading.fade_mode == FADE_MODE_NONE)
566 if (!setup.fade_screens || fade_delay == 0)
569 if (fade_mode == FADE_MODE_FADE_OUT)
573 if (fade_mode == FADE_MODE_FADE_OUT &&
574 fading.fade_mode != FADE_MODE_NONE)
575 ClearRectangle(backbuffer, x, y, width, height);
579 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
580 redraw_mask = REDRAW_NONE;
588 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
589 draw_border_function);
591 redraw_mask &= ~fade_mask;
594 void FadeIn(int fade_mask)
596 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
597 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
599 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
602 void FadeOut(int fade_mask)
604 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
605 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
607 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
609 global.border_status = game_status;
612 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
614 static struct TitleFadingInfo fading_leave_stored;
617 fading_leave_stored = fading_leave;
619 fading = fading_leave_stored;
622 void FadeSetEnterMenu()
624 fading = menu.enter_menu;
627 printf("::: storing enter_menu\n");
630 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
633 void FadeSetLeaveMenu()
635 fading = menu.leave_menu;
638 printf("::: storing leave_menu\n");
641 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
644 void FadeSetEnterScreen()
646 fading = menu.enter_screen[game_status];
649 printf("::: storing leave_screen[%d]\n", game_status);
652 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
655 void FadeSetNextScreen()
657 fading = menu.next_screen;
660 printf("::: storing next_screen\n");
663 // (do not overwrite fade mode set by FadeSetEnterScreen)
664 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
667 void FadeSetLeaveScreen()
670 printf("::: recalling last stored value\n");
673 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
676 void FadeSetFromType(int type)
678 if (type & TYPE_ENTER_SCREEN)
679 FadeSetEnterScreen();
680 else if (type & TYPE_ENTER)
682 else if (type & TYPE_LEAVE)
686 void FadeSetDisabled()
688 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
690 fading = fading_none;
693 void FadeSkipNextFadeIn()
695 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
698 void FadeSkipNextFadeOut()
700 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
703 void SetWindowBackgroundImageIfDefined(int graphic)
705 if (graphic_info[graphic].bitmap)
706 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
709 void SetMainBackgroundImageIfDefined(int graphic)
711 if (graphic_info[graphic].bitmap)
712 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
715 void SetDoorBackgroundImageIfDefined(int graphic)
717 if (graphic_info[graphic].bitmap)
718 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
721 void SetWindowBackgroundImage(int graphic)
723 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
724 graphic_info[graphic].bitmap ?
725 graphic_info[graphic].bitmap :
726 graphic_info[IMG_BACKGROUND].bitmap);
729 void SetMainBackgroundImage(int graphic)
731 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
732 graphic_info[graphic].bitmap ?
733 graphic_info[graphic].bitmap :
734 graphic_info[IMG_BACKGROUND].bitmap);
737 void SetDoorBackgroundImage(int graphic)
739 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
740 graphic_info[graphic].bitmap ?
741 graphic_info[graphic].bitmap :
742 graphic_info[IMG_BACKGROUND].bitmap);
745 void SetPanelBackground()
747 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
748 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
750 SetDoorBackgroundBitmap(bitmap_db_panel);
753 void DrawBackground(int x, int y, int width, int height)
755 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
756 /* (when entering hall of fame after playing) */
758 ClearRectangleOnBackground(drawto, x, y, width, height);
760 ClearRectangleOnBackground(backbuffer, x, y, width, height);
763 redraw_mask |= REDRAW_FIELD;
766 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
768 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
770 if (font->bitmap == NULL)
773 DrawBackground(x, y, width, height);
776 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
778 struct GraphicInfo *g = &graphic_info[graphic];
780 if (g->bitmap == NULL)
783 DrawBackground(x, y, width, height);
788 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
789 /* (when entering hall of fame after playing) */
790 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
792 /* !!! maybe this should be done before clearing the background !!! */
793 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
795 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
796 SetDrawtoField(DRAW_BUFFERED);
799 SetDrawtoField(DRAW_BACKBUFFER);
802 void MarkTileDirty(int x, int y)
804 int xx = redraw_x1 + x;
805 int yy = redraw_y1 + y;
810 redraw[xx][yy] = TRUE;
811 redraw_mask |= REDRAW_TILES;
814 void SetBorderElement()
818 BorderElement = EL_EMPTY;
820 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
822 for (x = 0; x < lev_fieldx; x++)
824 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
825 BorderElement = EL_STEELWALL;
827 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
833 void FloodFillLevel(int from_x, int from_y, int fill_element,
834 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
835 int max_fieldx, int max_fieldy)
839 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
840 static int safety = 0;
842 /* check if starting field still has the desired content */
843 if (field[from_x][from_y] == fill_element)
848 if (safety > max_fieldx * max_fieldy)
849 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
851 old_element = field[from_x][from_y];
852 field[from_x][from_y] = fill_element;
854 for (i = 0; i < 4; i++)
856 x = from_x + check[i][0];
857 y = from_y + check[i][1];
859 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
860 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
866 void SetRandomAnimationValue(int x, int y)
868 gfx.anim_random_frame = GfxRandom[x][y];
871 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
873 /* animation synchronized with global frame counter, not move position */
874 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
875 sync_frame = FrameCounter;
877 return getAnimationFrame(graphic_info[graphic].anim_frames,
878 graphic_info[graphic].anim_delay,
879 graphic_info[graphic].anim_mode,
880 graphic_info[graphic].anim_start_frame,
884 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
885 Bitmap **bitmap, int *x, int *y)
889 int width_mult, width_div;
890 int height_mult, height_div;
894 { 15, 16, 2, 3 }, /* 1 x 1 */
895 { 7, 8, 2, 3 }, /* 2 x 2 */
896 { 3, 4, 2, 3 }, /* 4 x 4 */
897 { 1, 2, 2, 3 }, /* 8 x 8 */
898 { 0, 1, 2, 3 }, /* 16 x 16 */
899 { 0, 1, 0, 1 }, /* 32 x 32 */
901 struct GraphicInfo *g = &graphic_info[graphic];
902 Bitmap *src_bitmap = g->bitmap;
903 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
904 int offset_calc_pos = log_2(tilesize);
905 int width_mult = offset_calc[offset_calc_pos].width_mult;
906 int width_div = offset_calc[offset_calc_pos].width_div;
907 int height_mult = offset_calc[offset_calc_pos].height_mult;
908 int height_div = offset_calc[offset_calc_pos].height_div;
909 int startx = src_bitmap->width * width_mult / width_div;
910 int starty = src_bitmap->height * height_mult / height_div;
911 int src_x = g->src_x * tilesize / TILESIZE;
912 int src_y = g->src_y * tilesize / TILESIZE;
913 int width = g->width * tilesize / TILESIZE;
914 int height = g->height * tilesize / TILESIZE;
915 int offset_x = g->offset_x * tilesize / TILESIZE;
916 int offset_y = g->offset_y * tilesize / TILESIZE;
918 if (g->offset_y == 0) /* frames are ordered horizontally */
920 int max_width = g->anim_frames_per_line * width;
921 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
923 src_x = pos % max_width;
924 src_y = src_y % height + pos / max_width * height;
926 else if (g->offset_x == 0) /* frames are ordered vertically */
928 int max_height = g->anim_frames_per_line * height;
929 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
931 src_x = src_x % width + pos / max_height * width;
932 src_y = pos % max_height;
934 else /* frames are ordered diagonally */
936 src_x = src_x + frame * offset_x;
937 src_y = src_y + frame * offset_y;
940 *bitmap = src_bitmap;
945 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
948 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
950 struct GraphicInfo *g = &graphic_info[graphic];
952 int mini_starty = g->bitmap->height * 2 / 3;
955 *x = mini_startx + g->src_x / 2;
956 *y = mini_starty + g->src_y / 2;
960 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
961 int *x, int *y, boolean get_backside)
963 struct GraphicInfo *g = &graphic_info[graphic];
964 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
965 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
969 if (g->offset_y == 0) /* frames are ordered horizontally */
971 int max_width = g->anim_frames_per_line * g->width;
972 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
974 *x = pos % max_width;
975 *y = src_y % g->height + pos / max_width * g->height;
977 else if (g->offset_x == 0) /* frames are ordered vertically */
979 int max_height = g->anim_frames_per_line * g->height;
980 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
982 *x = src_x % g->width + pos / max_height * g->width;
983 *y = pos % max_height;
985 else /* frames are ordered diagonally */
987 *x = src_x + frame * g->offset_x;
988 *y = src_y + frame * g->offset_y;
992 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
994 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
997 void DrawGraphic(int x, int y, int graphic, int frame)
1000 if (!IN_SCR_FIELD(x, y))
1002 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1003 printf("DrawGraphic(): This should never happen!\n");
1008 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1009 MarkTileDirty(x, y);
1012 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1018 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1019 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1022 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1025 if (!IN_SCR_FIELD(x, y))
1027 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1028 printf("DrawGraphicThruMask(): This should never happen!\n");
1033 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1035 MarkTileDirty(x, y);
1038 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1044 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1046 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1047 dst_x - src_x, dst_y - src_y);
1048 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1051 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1053 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1055 MarkTileDirty(x / tilesize, y / tilesize);
1058 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1064 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1065 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1068 void DrawMiniGraphic(int x, int y, int graphic)
1070 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1071 MarkTileDirty(x / 2, y / 2);
1074 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1079 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1080 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1083 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1084 int graphic, int frame,
1085 int cut_mode, int mask_mode)
1090 int width = TILEX, height = TILEY;
1093 if (dx || dy) /* shifted graphic */
1095 if (x < BX1) /* object enters playfield from the left */
1102 else if (x > BX2) /* object enters playfield from the right */
1108 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1114 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1116 else if (dx) /* general horizontal movement */
1117 MarkTileDirty(x + SIGN(dx), y);
1119 if (y < BY1) /* object enters playfield from the top */
1121 if (cut_mode==CUT_BELOW) /* object completely above top border */
1129 else if (y > BY2) /* object enters playfield from the bottom */
1135 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1141 else if (dy > 0 && cut_mode == CUT_ABOVE)
1143 if (y == BY2) /* object completely above bottom border */
1149 MarkTileDirty(x, y + 1);
1150 } /* object leaves playfield to the bottom */
1151 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1153 else if (dy) /* general vertical movement */
1154 MarkTileDirty(x, y + SIGN(dy));
1158 if (!IN_SCR_FIELD(x, y))
1160 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1161 printf("DrawGraphicShifted(): This should never happen!\n");
1166 if (width > 0 && height > 0)
1168 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1173 dst_x = FX + x * TILEX + dx;
1174 dst_y = FY + y * TILEY + dy;
1176 if (mask_mode == USE_MASKING)
1178 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1179 dst_x - src_x, dst_y - src_y);
1180 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1184 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1187 MarkTileDirty(x, y);
1191 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1192 int graphic, int frame,
1193 int cut_mode, int mask_mode)
1198 int width = TILEX, height = TILEY;
1201 int x2 = x + SIGN(dx);
1202 int y2 = y + SIGN(dy);
1203 int anim_frames = graphic_info[graphic].anim_frames;
1204 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1205 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1206 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1208 /* re-calculate animation frame for two-tile movement animation */
1209 frame = getGraphicAnimationFrame(graphic, sync_frame);
1211 /* check if movement start graphic inside screen area and should be drawn */
1212 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1214 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1216 dst_x = FX + x1 * TILEX;
1217 dst_y = FY + y1 * TILEY;
1219 if (mask_mode == USE_MASKING)
1221 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1222 dst_x - src_x, dst_y - src_y);
1223 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1227 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1230 MarkTileDirty(x1, y1);
1233 /* check if movement end graphic inside screen area and should be drawn */
1234 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1236 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1238 dst_x = FX + x2 * TILEX;
1239 dst_y = FY + y2 * TILEY;
1241 if (mask_mode == USE_MASKING)
1243 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1244 dst_x - src_x, dst_y - src_y);
1245 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1249 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1252 MarkTileDirty(x2, y2);
1256 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1257 int graphic, int frame,
1258 int cut_mode, int mask_mode)
1262 DrawGraphic(x, y, graphic, frame);
1267 if (graphic_info[graphic].double_movement) /* EM style movement images */
1268 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1270 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1273 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1274 int frame, int cut_mode)
1276 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1279 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1280 int cut_mode, int mask_mode)
1282 int lx = LEVELX(x), ly = LEVELY(y);
1286 if (IN_LEV_FIELD(lx, ly))
1288 SetRandomAnimationValue(lx, ly);
1290 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1291 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1293 /* do not use double (EM style) movement graphic when not moving */
1294 if (graphic_info[graphic].double_movement && !dx && !dy)
1296 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1297 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1300 else /* border element */
1302 graphic = el2img(element);
1303 frame = getGraphicAnimationFrame(graphic, -1);
1306 if (element == EL_EXPANDABLE_WALL)
1308 boolean left_stopped = FALSE, right_stopped = FALSE;
1310 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1311 left_stopped = TRUE;
1312 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1313 right_stopped = TRUE;
1315 if (left_stopped && right_stopped)
1317 else if (left_stopped)
1319 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1320 frame = graphic_info[graphic].anim_frames - 1;
1322 else if (right_stopped)
1324 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1325 frame = graphic_info[graphic].anim_frames - 1;
1330 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1331 else if (mask_mode == USE_MASKING)
1332 DrawGraphicThruMask(x, y, graphic, frame);
1334 DrawGraphic(x, y, graphic, frame);
1337 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1338 int cut_mode, int mask_mode)
1340 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1341 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1342 cut_mode, mask_mode);
1345 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1348 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1351 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1354 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1357 void DrawLevelElementThruMask(int x, int y, int element)
1359 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1362 void DrawLevelFieldThruMask(int x, int y)
1364 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1367 /* !!! implementation of quicksand is totally broken !!! */
1368 #define IS_CRUMBLED_TILE(x, y, e) \
1369 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1370 !IS_MOVING(x, y) || \
1371 (e) == EL_QUICKSAND_EMPTYING || \
1372 (e) == EL_QUICKSAND_FAST_EMPTYING))
1374 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1378 int sx = SCREENX(x), sy = SCREENY(y);
1380 int width, height, cx, cy, i;
1381 int crumbled_border_size = graphic_info[graphic].border_size;
1382 static int xy[4][2] =
1390 if (!IN_LEV_FIELD(x, y))
1393 element = TILE_GFX_ELEMENT(x, y);
1395 /* crumble field itself */
1397 if (IS_CRUMBLED_TILE(x, y, element))
1399 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1402 if (!IN_SCR_FIELD(sx, sy))
1405 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1407 for (i = 0; i < 4; i++)
1409 int xx = x + xy[i][0];
1410 int yy = y + xy[i][1];
1412 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1415 /* check if neighbour field is of same type */
1417 if (IS_CRUMBLED_TILE(xx, yy, element))
1420 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1424 if (i == 1 || i == 2)
1426 width = crumbled_border_size;
1428 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1434 height = crumbled_border_size;
1436 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1439 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1440 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1443 MarkTileDirty(sx, sy);
1445 else /* crumble neighbour fields */
1447 for (i = 0; i < 4; i++)
1449 int xx = x + xy[i][0];
1450 int yy = y + xy[i][1];
1451 int sxx = sx + xy[i][0];
1452 int syy = sy + xy[i][1];
1455 if (!IN_LEV_FIELD(xx, yy) ||
1456 !IN_SCR_FIELD(sxx, syy))
1459 if (!IN_LEV_FIELD(xx, yy) ||
1460 !IN_SCR_FIELD(sxx, syy) ||
1465 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1468 element = TILE_GFX_ELEMENT(xx, yy);
1471 if (!IS_CRUMBLED_TILE(xx, yy, element))
1474 if (!GFX_CRUMBLED(element))
1478 graphic = el_act2crm(element, ACTION_DEFAULT);
1479 crumbled_border_size = graphic_info[graphic].border_size;
1481 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1483 if (i == 1 || i == 2)
1485 width = crumbled_border_size;
1487 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1493 height = crumbled_border_size;
1495 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1498 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1499 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1501 MarkTileDirty(sxx, syy);
1506 void DrawLevelFieldCrumbledSand(int x, int y)
1510 if (!IN_LEV_FIELD(x, y))
1514 /* !!! CHECK THIS !!! */
1517 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1518 GFX_CRUMBLED(GfxElement[x][y]))
1521 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1522 GfxElement[x][y] != EL_UNDEFINED &&
1523 GFX_CRUMBLED(GfxElement[x][y]))
1525 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1532 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1534 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1537 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1540 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1543 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1544 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1545 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1546 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1547 int sx = SCREENX(x), sy = SCREENY(y);
1549 DrawGraphic(sx, sy, graphic1, frame1);
1550 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1553 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1555 int sx = SCREENX(x), sy = SCREENY(y);
1556 static int xy[4][2] =
1565 for (i = 0; i < 4; i++)
1567 int xx = x + xy[i][0];
1568 int yy = y + xy[i][1];
1569 int sxx = sx + xy[i][0];
1570 int syy = sy + xy[i][1];
1572 if (!IN_LEV_FIELD(xx, yy) ||
1573 !IN_SCR_FIELD(sxx, syy) ||
1574 !GFX_CRUMBLED(Feld[xx][yy]) ||
1578 DrawLevelField(xx, yy);
1582 static int getBorderElement(int x, int y)
1586 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1587 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1588 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1589 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1590 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1591 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1592 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1594 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1595 int steel_position = (x == -1 && y == -1 ? 0 :
1596 x == lev_fieldx && y == -1 ? 1 :
1597 x == -1 && y == lev_fieldy ? 2 :
1598 x == lev_fieldx && y == lev_fieldy ? 3 :
1599 x == -1 || x == lev_fieldx ? 4 :
1600 y == -1 || y == lev_fieldy ? 5 : 6);
1602 return border[steel_position][steel_type];
1605 void DrawScreenElement(int x, int y, int element)
1607 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1608 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1611 void DrawLevelElement(int x, int y, int element)
1613 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1614 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1617 void DrawScreenField(int x, int y)
1619 int lx = LEVELX(x), ly = LEVELY(y);
1620 int element, content;
1622 if (!IN_LEV_FIELD(lx, ly))
1624 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1627 element = getBorderElement(lx, ly);
1629 DrawScreenElement(x, y, element);
1634 element = Feld[lx][ly];
1635 content = Store[lx][ly];
1637 if (IS_MOVING(lx, ly))
1639 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1640 boolean cut_mode = NO_CUTTING;
1642 if (element == EL_QUICKSAND_EMPTYING ||
1643 element == EL_QUICKSAND_FAST_EMPTYING ||
1644 element == EL_MAGIC_WALL_EMPTYING ||
1645 element == EL_BD_MAGIC_WALL_EMPTYING ||
1646 element == EL_DC_MAGIC_WALL_EMPTYING ||
1647 element == EL_AMOEBA_DROPPING)
1648 cut_mode = CUT_ABOVE;
1649 else if (element == EL_QUICKSAND_FILLING ||
1650 element == EL_QUICKSAND_FAST_FILLING ||
1651 element == EL_MAGIC_WALL_FILLING ||
1652 element == EL_BD_MAGIC_WALL_FILLING ||
1653 element == EL_DC_MAGIC_WALL_FILLING)
1654 cut_mode = CUT_BELOW;
1657 if (lx == 9 && ly == 1)
1658 printf("::: %s [%d] [%d, %d] [%d]\n",
1659 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1660 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1661 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1662 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1663 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1666 if (cut_mode == CUT_ABOVE)
1668 DrawScreenElement(x, y, element);
1670 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1673 DrawScreenElement(x, y, EL_EMPTY);
1676 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1677 else if (cut_mode == NO_CUTTING)
1678 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1681 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1684 if (cut_mode == CUT_BELOW &&
1685 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1686 DrawLevelElement(lx, ly + 1, element);
1690 if (content == EL_ACID)
1692 int dir = MovDir[lx][ly];
1693 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1694 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1696 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1699 else if (IS_BLOCKED(lx, ly))
1704 boolean cut_mode = NO_CUTTING;
1705 int element_old, content_old;
1707 Blocked2Moving(lx, ly, &oldx, &oldy);
1710 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1711 MovDir[oldx][oldy] == MV_RIGHT);
1713 element_old = Feld[oldx][oldy];
1714 content_old = Store[oldx][oldy];
1716 if (element_old == EL_QUICKSAND_EMPTYING ||
1717 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1718 element_old == EL_MAGIC_WALL_EMPTYING ||
1719 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1720 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1721 element_old == EL_AMOEBA_DROPPING)
1722 cut_mode = CUT_ABOVE;
1724 DrawScreenElement(x, y, EL_EMPTY);
1727 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1729 else if (cut_mode == NO_CUTTING)
1730 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1733 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1736 else if (IS_DRAWABLE(element))
1737 DrawScreenElement(x, y, element);
1739 DrawScreenElement(x, y, EL_EMPTY);
1742 void DrawLevelField(int x, int y)
1744 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1745 DrawScreenField(SCREENX(x), SCREENY(y));
1746 else if (IS_MOVING(x, y))
1750 Moving2Blocked(x, y, &newx, &newy);
1751 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1752 DrawScreenField(SCREENX(newx), SCREENY(newy));
1754 else if (IS_BLOCKED(x, y))
1758 Blocked2Moving(x, y, &oldx, &oldy);
1759 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1760 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1764 void DrawMiniElement(int x, int y, int element)
1768 graphic = el2edimg(element);
1769 DrawMiniGraphic(x, y, graphic);
1772 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1774 int x = sx + scroll_x, y = sy + scroll_y;
1776 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1777 DrawMiniElement(sx, sy, EL_EMPTY);
1778 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1779 DrawMiniElement(sx, sy, Feld[x][y]);
1781 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1784 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1785 int x, int y, int xsize, int ysize, int font_nr)
1787 int font_width = getFontWidth(font_nr);
1788 int font_height = getFontHeight(font_nr);
1789 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1792 int dst_x = SX + startx + x * font_width;
1793 int dst_y = SY + starty + y * font_height;
1794 int width = graphic_info[graphic].width;
1795 int height = graphic_info[graphic].height;
1796 int inner_width = MAX(width - 2 * font_width, font_width);
1797 int inner_height = MAX(height - 2 * font_height, font_height);
1798 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1799 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1800 boolean draw_masked = graphic_info[graphic].draw_masked;
1802 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1804 if (src_bitmap == NULL || width < font_width || height < font_height)
1806 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1810 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1811 inner_sx + (x - 1) * font_width % inner_width);
1812 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1813 inner_sy + (y - 1) * font_height % inner_height);
1817 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1818 dst_x - src_x, dst_y - src_y);
1819 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1823 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1827 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1829 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1830 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1831 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1832 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1833 boolean no_delay = (tape.warp_forward);
1834 unsigned long anim_delay = 0;
1835 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1836 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1837 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1838 int font_width = getFontWidth(font_nr);
1839 int font_height = getFontHeight(font_nr);
1840 int max_xsize = level.envelope[envelope_nr].xsize;
1841 int max_ysize = level.envelope[envelope_nr].ysize;
1842 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1843 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1844 int xend = max_xsize;
1845 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1846 int xstep = (xstart < xend ? 1 : 0);
1847 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1850 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1852 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1853 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1854 int sx = (SXSIZE - xsize * font_width) / 2;
1855 int sy = (SYSIZE - ysize * font_height) / 2;
1858 SetDrawtoField(DRAW_BUFFERED);
1860 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1862 SetDrawtoField(DRAW_BACKBUFFER);
1864 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1865 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1868 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1869 level.envelope[envelope_nr].text, font_nr, max_xsize,
1870 xsize - 2, ysize - 2, mask_mode,
1871 level.envelope[envelope_nr].autowrap,
1872 level.envelope[envelope_nr].centered, FALSE);
1874 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1875 level.envelope[envelope_nr].text, font_nr, max_xsize,
1876 xsize - 2, ysize - 2, mask_mode);
1879 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1882 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1886 void ShowEnvelope(int envelope_nr)
1888 int element = EL_ENVELOPE_1 + envelope_nr;
1889 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1890 int sound_opening = element_info[element].sound[ACTION_OPENING];
1891 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1892 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1893 boolean no_delay = (tape.warp_forward);
1894 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1895 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1896 int anim_mode = graphic_info[graphic].anim_mode;
1897 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1898 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1900 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1902 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1904 if (anim_mode == ANIM_DEFAULT)
1905 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1907 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1910 Delay(wait_delay_value);
1912 WaitForEventToContinue();
1914 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1916 if (anim_mode != ANIM_NONE)
1917 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1919 if (anim_mode == ANIM_DEFAULT)
1920 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1922 game.envelope_active = FALSE;
1924 SetDrawtoField(DRAW_BUFFERED);
1926 redraw_mask |= REDRAW_FIELD;
1930 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1934 int graphic = el2preimg(element);
1936 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
1937 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1945 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
1946 SetDrawBackgroundMask(REDRAW_FIELD);
1948 SetDrawBackgroundMask(REDRAW_NONE);
1953 for (x = BX1; x <= BX2; x++)
1954 for (y = BY1; y <= BY2; y++)
1955 DrawScreenField(x, y);
1957 redraw_mask |= REDRAW_FIELD;
1960 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1964 for (x = 0; x < size_x; x++)
1965 for (y = 0; y < size_y; y++)
1966 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1968 redraw_mask |= REDRAW_FIELD;
1971 static void DrawPreviewLevelExt(int from_x, int from_y)
1973 boolean show_level_border = (BorderElement != EL_EMPTY);
1974 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1975 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1976 int tile_size = preview.tile_size;
1977 int preview_width = preview.xsize * tile_size;
1978 int preview_height = preview.ysize * tile_size;
1979 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1980 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1981 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1982 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1985 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1987 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1988 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1990 for (x = 0; x < real_preview_xsize; x++)
1992 for (y = 0; y < real_preview_ysize; y++)
1994 int lx = from_x + x + (show_level_border ? -1 : 0);
1995 int ly = from_y + y + (show_level_border ? -1 : 0);
1996 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1997 getBorderElement(lx, ly));
1999 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2000 element, tile_size);
2004 redraw_mask |= REDRAW_MICROLEVEL;
2007 #define MICROLABEL_EMPTY 0
2008 #define MICROLABEL_LEVEL_NAME 1
2009 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2010 #define MICROLABEL_LEVEL_AUTHOR 3
2011 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2012 #define MICROLABEL_IMPORTED_FROM 5
2013 #define MICROLABEL_IMPORTED_BY_HEAD 6
2014 #define MICROLABEL_IMPORTED_BY 7
2016 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2018 int max_text_width = SXSIZE;
2019 int font_width = getFontWidth(font_nr);
2021 if (pos->align == ALIGN_CENTER)
2022 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2023 else if (pos->align == ALIGN_RIGHT)
2024 max_text_width = pos->x;
2026 max_text_width = SXSIZE - pos->x;
2028 return max_text_width / font_width;
2031 static void DrawPreviewLevelLabelExt(int mode)
2033 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2034 char label_text[MAX_OUTPUT_LINESIZE + 1];
2035 int max_len_label_text;
2037 int font_nr = pos->font;
2040 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2041 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2042 mode == MICROLABEL_IMPORTED_BY_HEAD)
2043 font_nr = pos->font_alt;
2045 int font_nr = FONT_TEXT_2;
2048 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2049 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2050 mode == MICROLABEL_IMPORTED_BY_HEAD)
2051 font_nr = FONT_TEXT_3;
2055 max_len_label_text = getMaxTextLength(pos, font_nr);
2057 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2061 if (pos->size != -1)
2062 max_len_label_text = pos->size;
2065 for (i = 0; i < max_len_label_text; i++)
2066 label_text[i] = ' ';
2067 label_text[max_len_label_text] = '\0';
2069 if (strlen(label_text) > 0)
2072 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2074 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2075 int lypos = MICROLABEL2_YPOS;
2077 DrawText(lxpos, lypos, label_text, font_nr);
2082 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2083 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2084 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2085 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2086 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2087 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2088 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2089 max_len_label_text);
2090 label_text[max_len_label_text] = '\0';
2092 if (strlen(label_text) > 0)
2095 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2097 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2098 int lypos = MICROLABEL2_YPOS;
2100 DrawText(lxpos, lypos, label_text, font_nr);
2104 redraw_mask |= REDRAW_MICROLEVEL;
2107 void DrawPreviewLevel(boolean restart)
2109 static unsigned long scroll_delay = 0;
2110 static unsigned long label_delay = 0;
2111 static int from_x, from_y, scroll_direction;
2112 static int label_state, label_counter;
2113 unsigned long scroll_delay_value = preview.step_delay;
2114 boolean show_level_border = (BorderElement != EL_EMPTY);
2115 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2116 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2117 int last_game_status = game_status; /* save current game status */
2120 /* force PREVIEW font on preview level */
2121 game_status = GAME_MODE_PSEUDO_PREVIEW;
2129 if (preview.anim_mode == ANIM_CENTERED)
2131 if (level_xsize > preview.xsize)
2132 from_x = (level_xsize - preview.xsize) / 2;
2133 if (level_ysize > preview.ysize)
2134 from_y = (level_ysize - preview.ysize) / 2;
2137 from_x += preview.xoffset;
2138 from_y += preview.yoffset;
2140 scroll_direction = MV_RIGHT;
2144 DrawPreviewLevelExt(from_x, from_y);
2145 DrawPreviewLevelLabelExt(label_state);
2147 /* initialize delay counters */
2148 DelayReached(&scroll_delay, 0);
2149 DelayReached(&label_delay, 0);
2151 if (leveldir_current->name)
2153 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2154 char label_text[MAX_OUTPUT_LINESIZE + 1];
2156 int font_nr = pos->font;
2158 int font_nr = FONT_TEXT_1;
2161 int max_len_label_text = getMaxTextLength(pos, font_nr);
2163 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2171 if (pos->size != -1)
2172 max_len_label_text = pos->size;
2175 strncpy(label_text, leveldir_current->name, max_len_label_text);
2176 label_text[max_len_label_text] = '\0';
2179 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2181 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2182 lypos = SY + MICROLABEL1_YPOS;
2184 DrawText(lxpos, lypos, label_text, font_nr);
2188 game_status = last_game_status; /* restore current game status */
2193 /* scroll preview level, if needed */
2194 if (preview.anim_mode != ANIM_NONE &&
2195 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2196 DelayReached(&scroll_delay, scroll_delay_value))
2198 switch (scroll_direction)
2203 from_x -= preview.step_offset;
2204 from_x = (from_x < 0 ? 0 : from_x);
2207 scroll_direction = MV_UP;
2211 if (from_x < level_xsize - preview.xsize)
2213 from_x += preview.step_offset;
2214 from_x = (from_x > level_xsize - preview.xsize ?
2215 level_xsize - preview.xsize : from_x);
2218 scroll_direction = MV_DOWN;
2224 from_y -= preview.step_offset;
2225 from_y = (from_y < 0 ? 0 : from_y);
2228 scroll_direction = MV_RIGHT;
2232 if (from_y < level_ysize - preview.ysize)
2234 from_y += preview.step_offset;
2235 from_y = (from_y > level_ysize - preview.ysize ?
2236 level_ysize - preview.ysize : from_y);
2239 scroll_direction = MV_LEFT;
2246 DrawPreviewLevelExt(from_x, from_y);
2249 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2250 /* redraw micro level label, if needed */
2251 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2252 !strEqual(level.author, ANONYMOUS_NAME) &&
2253 !strEqual(level.author, leveldir_current->name) &&
2254 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2256 int max_label_counter = 23;
2258 if (leveldir_current->imported_from != NULL &&
2259 strlen(leveldir_current->imported_from) > 0)
2260 max_label_counter += 14;
2261 if (leveldir_current->imported_by != NULL &&
2262 strlen(leveldir_current->imported_by) > 0)
2263 max_label_counter += 14;
2265 label_counter = (label_counter + 1) % max_label_counter;
2266 label_state = (label_counter >= 0 && label_counter <= 7 ?
2267 MICROLABEL_LEVEL_NAME :
2268 label_counter >= 9 && label_counter <= 12 ?
2269 MICROLABEL_LEVEL_AUTHOR_HEAD :
2270 label_counter >= 14 && label_counter <= 21 ?
2271 MICROLABEL_LEVEL_AUTHOR :
2272 label_counter >= 23 && label_counter <= 26 ?
2273 MICROLABEL_IMPORTED_FROM_HEAD :
2274 label_counter >= 28 && label_counter <= 35 ?
2275 MICROLABEL_IMPORTED_FROM :
2276 label_counter >= 37 && label_counter <= 40 ?
2277 MICROLABEL_IMPORTED_BY_HEAD :
2278 label_counter >= 42 && label_counter <= 49 ?
2279 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2281 if (leveldir_current->imported_from == NULL &&
2282 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2283 label_state == MICROLABEL_IMPORTED_FROM))
2284 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2285 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2287 DrawPreviewLevelLabelExt(label_state);
2290 game_status = last_game_status; /* restore current game status */
2293 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2294 int graphic, int sync_frame, int mask_mode)
2296 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2298 if (mask_mode == USE_MASKING)
2299 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2301 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2304 inline void DrawGraphicAnimation(int x, int y, int graphic)
2306 int lx = LEVELX(x), ly = LEVELY(y);
2308 if (!IN_SCR_FIELD(x, y))
2311 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2312 graphic, GfxFrame[lx][ly], NO_MASKING);
2313 MarkTileDirty(x, y);
2316 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2318 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2321 void DrawLevelElementAnimation(int x, int y, int element)
2323 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2325 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2328 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2330 int sx = SCREENX(x), sy = SCREENY(y);
2332 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2335 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2338 DrawGraphicAnimation(sx, sy, graphic);
2341 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2342 DrawLevelFieldCrumbledSand(x, y);
2344 if (GFX_CRUMBLED(Feld[x][y]))
2345 DrawLevelFieldCrumbledSand(x, y);
2349 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2351 int sx = SCREENX(x), sy = SCREENY(y);
2354 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2357 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2359 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2362 DrawGraphicAnimation(sx, sy, graphic);
2364 if (GFX_CRUMBLED(element))
2365 DrawLevelFieldCrumbledSand(x, y);
2368 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2370 if (player->use_murphy)
2372 /* this works only because currently only one player can be "murphy" ... */
2373 static int last_horizontal_dir = MV_LEFT;
2374 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2376 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2377 last_horizontal_dir = move_dir;
2379 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2381 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2383 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2389 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2392 static boolean equalGraphics(int graphic1, int graphic2)
2394 struct GraphicInfo *g1 = &graphic_info[graphic1];
2395 struct GraphicInfo *g2 = &graphic_info[graphic2];
2397 return (g1->bitmap == g2->bitmap &&
2398 g1->src_x == g2->src_x &&
2399 g1->src_y == g2->src_y &&
2400 g1->anim_frames == g2->anim_frames &&
2401 g1->anim_delay == g2->anim_delay &&
2402 g1->anim_mode == g2->anim_mode);
2405 void DrawAllPlayers()
2409 for (i = 0; i < MAX_PLAYERS; i++)
2410 if (stored_player[i].active)
2411 DrawPlayer(&stored_player[i]);
2414 void DrawPlayerField(int x, int y)
2416 if (!IS_PLAYER(x, y))
2419 DrawPlayer(PLAYERINFO(x, y));
2422 void DrawPlayer(struct PlayerInfo *player)
2424 int jx = player->jx;
2425 int jy = player->jy;
2426 int move_dir = player->MovDir;
2427 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2428 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2429 int last_jx = (player->is_moving ? jx - dx : jx);
2430 int last_jy = (player->is_moving ? jy - dy : jy);
2431 int next_jx = jx + dx;
2432 int next_jy = jy + dy;
2433 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2434 boolean player_is_opaque = FALSE;
2435 int sx = SCREENX(jx), sy = SCREENY(jy);
2436 int sxx = 0, syy = 0;
2437 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2439 int action = ACTION_DEFAULT;
2440 int last_player_graphic = getPlayerGraphic(player, move_dir);
2441 int last_player_frame = player->Frame;
2444 /* GfxElement[][] is set to the element the player is digging or collecting;
2445 remove also for off-screen player if the player is not moving anymore */
2446 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2447 GfxElement[jx][jy] = EL_UNDEFINED;
2449 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2453 if (!IN_LEV_FIELD(jx, jy))
2455 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2456 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2457 printf("DrawPlayerField(): This should never happen!\n");
2462 if (element == EL_EXPLOSION)
2465 action = (player->is_pushing ? ACTION_PUSHING :
2466 player->is_digging ? ACTION_DIGGING :
2467 player->is_collecting ? ACTION_COLLECTING :
2468 player->is_moving ? ACTION_MOVING :
2469 player->is_snapping ? ACTION_SNAPPING :
2470 player->is_dropping ? ACTION_DROPPING :
2471 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2473 if (player->is_waiting)
2474 move_dir = player->dir_waiting;
2476 InitPlayerGfxAnimation(player, action, move_dir);
2478 /* ----------------------------------------------------------------------- */
2479 /* draw things in the field the player is leaving, if needed */
2480 /* ----------------------------------------------------------------------- */
2482 if (player->is_moving)
2484 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2486 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2488 if (last_element == EL_DYNAMITE_ACTIVE ||
2489 last_element == EL_EM_DYNAMITE_ACTIVE ||
2490 last_element == EL_SP_DISK_RED_ACTIVE)
2491 DrawDynamite(last_jx, last_jy);
2493 DrawLevelFieldThruMask(last_jx, last_jy);
2495 else if (last_element == EL_DYNAMITE_ACTIVE ||
2496 last_element == EL_EM_DYNAMITE_ACTIVE ||
2497 last_element == EL_SP_DISK_RED_ACTIVE)
2498 DrawDynamite(last_jx, last_jy);
2500 /* !!! this is not enough to prevent flickering of players which are
2501 moving next to each others without a free tile between them -- this
2502 can only be solved by drawing all players layer by layer (first the
2503 background, then the foreground etc.) !!! => TODO */
2504 else if (!IS_PLAYER(last_jx, last_jy))
2505 DrawLevelField(last_jx, last_jy);
2508 DrawLevelField(last_jx, last_jy);
2511 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2512 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2515 if (!IN_SCR_FIELD(sx, sy))
2518 /* ----------------------------------------------------------------------- */
2519 /* draw things behind the player, if needed */
2520 /* ----------------------------------------------------------------------- */
2523 DrawLevelElement(jx, jy, Back[jx][jy]);
2524 else if (IS_ACTIVE_BOMB(element))
2525 DrawLevelElement(jx, jy, EL_EMPTY);
2528 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2530 int old_element = GfxElement[jx][jy];
2531 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2532 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2534 if (GFX_CRUMBLED(old_element))
2535 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2537 DrawGraphic(sx, sy, old_graphic, frame);
2539 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2540 player_is_opaque = TRUE;
2544 GfxElement[jx][jy] = EL_UNDEFINED;
2546 /* make sure that pushed elements are drawn with correct frame rate */
2548 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2550 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2551 GfxFrame[jx][jy] = player->StepFrame;
2553 if (player->is_pushing && player->is_moving)
2554 GfxFrame[jx][jy] = player->StepFrame;
2557 DrawLevelField(jx, jy);
2561 /* ----------------------------------------------------------------------- */
2562 /* draw player himself */
2563 /* ----------------------------------------------------------------------- */
2565 graphic = getPlayerGraphic(player, move_dir);
2567 /* in the case of changed player action or direction, prevent the current
2568 animation frame from being restarted for identical animations */
2569 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2570 player->Frame = last_player_frame;
2572 frame = getGraphicAnimationFrame(graphic, player->Frame);
2576 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2577 sxx = player->GfxPos;
2579 syy = player->GfxPos;
2582 if (!setup.soft_scrolling && ScreenMovPos)
2585 if (player_is_opaque)
2586 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2588 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2590 if (SHIELD_ON(player))
2592 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2593 IMG_SHIELD_NORMAL_ACTIVE);
2594 int frame = getGraphicAnimationFrame(graphic, -1);
2596 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2599 /* ----------------------------------------------------------------------- */
2600 /* draw things the player is pushing, if needed */
2601 /* ----------------------------------------------------------------------- */
2604 printf("::: %d, %d [%d, %d] [%d]\n",
2605 player->is_pushing, player_is_moving, player->GfxAction,
2606 player->is_moving, player_is_moving);
2610 if (player->is_pushing && player->is_moving)
2612 int px = SCREENX(jx), py = SCREENY(jy);
2613 int pxx = (TILEX - ABS(sxx)) * dx;
2614 int pyy = (TILEY - ABS(syy)) * dy;
2615 int gfx_frame = GfxFrame[jx][jy];
2621 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2623 element = Feld[next_jx][next_jy];
2624 gfx_frame = GfxFrame[next_jx][next_jy];
2627 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2630 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2631 frame = getGraphicAnimationFrame(graphic, sync_frame);
2633 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2636 /* draw background element under pushed element (like the Sokoban field) */
2637 if (Back[next_jx][next_jy])
2638 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2640 /* masked drawing is needed for EMC style (double) movement graphics */
2641 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2645 /* ----------------------------------------------------------------------- */
2646 /* draw things in front of player (active dynamite or dynabombs) */
2647 /* ----------------------------------------------------------------------- */
2649 if (IS_ACTIVE_BOMB(element))
2651 graphic = el2img(element);
2652 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2654 if (game.emulation == EMU_SUPAPLEX)
2655 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2657 DrawGraphicThruMask(sx, sy, graphic, frame);
2660 if (player_is_moving && last_element == EL_EXPLOSION)
2662 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2663 GfxElement[last_jx][last_jy] : EL_EMPTY);
2664 int graphic = el_act2img(element, ACTION_EXPLODING);
2665 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2666 int phase = ExplodePhase[last_jx][last_jy] - 1;
2667 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2670 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2673 /* ----------------------------------------------------------------------- */
2674 /* draw elements the player is just walking/passing through/under */
2675 /* ----------------------------------------------------------------------- */
2677 if (player_is_moving)
2679 /* handle the field the player is leaving ... */
2680 if (IS_ACCESSIBLE_INSIDE(last_element))
2681 DrawLevelField(last_jx, last_jy);
2682 else if (IS_ACCESSIBLE_UNDER(last_element))
2683 DrawLevelFieldThruMask(last_jx, last_jy);
2686 /* do not redraw accessible elements if the player is just pushing them */
2687 if (!player_is_moving || !player->is_pushing)
2689 /* ... and the field the player is entering */
2690 if (IS_ACCESSIBLE_INSIDE(element))
2691 DrawLevelField(jx, jy);
2692 else if (IS_ACCESSIBLE_UNDER(element))
2693 DrawLevelFieldThruMask(jx, jy);
2696 MarkTileDirty(sx, sy);
2699 /* ------------------------------------------------------------------------- */
2701 void WaitForEventToContinue()
2703 boolean still_wait = TRUE;
2705 /* simulate releasing mouse button over last gadget, if still pressed */
2707 HandleGadgets(-1, -1, 0);
2709 button_status = MB_RELEASED;
2725 case EVENT_BUTTONPRESS:
2726 case EVENT_KEYPRESS:
2730 case EVENT_KEYRELEASE:
2731 ClearPlayerAction();
2735 HandleOtherEvents(&event);
2739 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2746 /* don't eat all CPU time */
2751 #define MAX_REQUEST_LINES 13
2752 #define MAX_REQUEST_LINE_FONT1_LEN 7
2753 #define MAX_REQUEST_LINE_FONT2_LEN 10
2755 boolean Request(char *text, unsigned int req_state)
2757 int mx, my, ty, result = -1;
2758 unsigned int old_door_state;
2759 int last_game_status = game_status; /* save current game status */
2760 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2761 int font_nr = FONT_TEXT_2;
2762 int max_word_len = 0;
2765 for (text_ptr = text; *text_ptr; text_ptr++)
2767 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2769 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2771 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2773 font_nr = FONT_TEXT_1;
2775 font_nr = FONT_LEVEL_NUMBER;
2782 if (game_status == GAME_MODE_PLAYING &&
2783 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2784 BlitScreenToBitmap_EM(backbuffer);
2786 /* disable deactivated drawing when quick-loading level tape recording */
2787 if (tape.playing && tape.deactivate_display)
2788 TapeDeactivateDisplayOff(TRUE);
2790 SetMouseCursor(CURSOR_DEFAULT);
2792 #if defined(NETWORK_AVALIABLE)
2793 /* pause network game while waiting for request to answer */
2794 if (options.network &&
2795 game_status == GAME_MODE_PLAYING &&
2796 req_state & REQUEST_WAIT_FOR_INPUT)
2797 SendToServer_PausePlaying();
2800 old_door_state = GetDoorState();
2802 /* simulate releasing mouse button over last gadget, if still pressed */
2804 HandleGadgets(-1, -1, 0);
2808 if (old_door_state & DOOR_OPEN_1)
2810 CloseDoor(DOOR_CLOSE_1);
2812 /* save old door content */
2813 BlitBitmap(bitmap_db_door, bitmap_db_door,
2814 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2815 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2819 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2822 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2824 /* clear door drawing field */
2825 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2827 /* force DOOR font inside door area */
2828 game_status = GAME_MODE_PSEUDO_DOOR;
2830 /* write text for request */
2831 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2833 char text_line[max_request_line_len + 1];
2839 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2842 if (!tc || tc == ' ')
2853 strncpy(text_line, text, tl);
2856 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2857 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2858 text_line, font_nr);
2860 text += tl + (tc == ' ' ? 1 : 0);
2863 game_status = last_game_status; /* restore current game status */
2865 if (req_state & REQ_ASK)
2867 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2868 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2870 else if (req_state & REQ_CONFIRM)
2872 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2874 else if (req_state & REQ_PLAYER)
2876 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2877 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2878 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2879 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2882 /* copy request gadgets to door backbuffer */
2883 BlitBitmap(drawto, bitmap_db_door,
2884 DX, DY, DXSIZE, DYSIZE,
2885 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2887 OpenDoor(DOOR_OPEN_1);
2889 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2891 if (game_status == GAME_MODE_PLAYING)
2893 SetPanelBackground();
2894 SetDrawBackgroundMask(REDRAW_DOOR_1);
2898 SetDrawBackgroundMask(REDRAW_FIELD);
2904 if (game_status != GAME_MODE_MAIN)
2907 button_status = MB_RELEASED;
2909 request_gadget_id = -1;
2911 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2923 case EVENT_BUTTONPRESS:
2924 case EVENT_BUTTONRELEASE:
2925 case EVENT_MOTIONNOTIFY:
2927 if (event.type == EVENT_MOTIONNOTIFY)
2929 if (!PointerInWindow(window))
2930 continue; /* window and pointer are on different screens */
2935 motion_status = TRUE;
2936 mx = ((MotionEvent *) &event)->x;
2937 my = ((MotionEvent *) &event)->y;
2941 motion_status = FALSE;
2942 mx = ((ButtonEvent *) &event)->x;
2943 my = ((ButtonEvent *) &event)->y;
2944 if (event.type == EVENT_BUTTONPRESS)
2945 button_status = ((ButtonEvent *) &event)->button;
2947 button_status = MB_RELEASED;
2950 /* this sets 'request_gadget_id' */
2951 HandleGadgets(mx, my, button_status);
2953 switch (request_gadget_id)
2955 case TOOL_CTRL_ID_YES:
2958 case TOOL_CTRL_ID_NO:
2961 case TOOL_CTRL_ID_CONFIRM:
2962 result = TRUE | FALSE;
2965 case TOOL_CTRL_ID_PLAYER_1:
2968 case TOOL_CTRL_ID_PLAYER_2:
2971 case TOOL_CTRL_ID_PLAYER_3:
2974 case TOOL_CTRL_ID_PLAYER_4:
2985 case EVENT_KEYPRESS:
2986 switch (GetEventKey((KeyEvent *)&event, TRUE))
2989 if (req_state & REQ_CONFIRM)
3005 if (req_state & REQ_PLAYER)
3009 case EVENT_KEYRELEASE:
3010 ClearPlayerAction();
3014 HandleOtherEvents(&event);
3018 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3020 int joy = AnyJoystick();
3022 if (joy & JOY_BUTTON_1)
3024 else if (joy & JOY_BUTTON_2)
3030 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3032 HandleGameActions();
3038 if (!PendingEvent()) /* delay only if no pending events */
3049 if (!PendingEvent()) /* delay only if no pending events */
3052 /* don't eat all CPU time */
3059 if (game_status != GAME_MODE_MAIN)
3064 if (!(req_state & REQ_STAY_OPEN))
3066 CloseDoor(DOOR_CLOSE_1);
3068 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3069 (req_state & REQ_REOPEN))
3070 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3075 if (game_status == GAME_MODE_PLAYING)
3077 SetPanelBackground();
3078 SetDrawBackgroundMask(REDRAW_DOOR_1);
3082 SetDrawBackgroundMask(REDRAW_FIELD);
3085 #if defined(NETWORK_AVALIABLE)
3086 /* continue network game after request */
3087 if (options.network &&
3088 game_status == GAME_MODE_PLAYING &&
3089 req_state & REQUEST_WAIT_FOR_INPUT)
3090 SendToServer_ContinuePlaying();
3093 /* restore deactivated drawing when quick-loading level tape recording */
3094 if (tape.playing && tape.deactivate_display)
3095 TapeDeactivateDisplayOn();
3100 unsigned int OpenDoor(unsigned int door_state)
3102 if (door_state & DOOR_COPY_BACK)
3104 if (door_state & DOOR_OPEN_1)
3105 BlitBitmap(bitmap_db_door, bitmap_db_door,
3106 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3107 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3109 if (door_state & DOOR_OPEN_2)
3110 BlitBitmap(bitmap_db_door, bitmap_db_door,
3111 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3112 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3114 door_state &= ~DOOR_COPY_BACK;
3117 return MoveDoor(door_state);
3120 unsigned int CloseDoor(unsigned int door_state)
3122 unsigned int old_door_state = GetDoorState();
3124 if (!(door_state & DOOR_NO_COPY_BACK))
3126 if (old_door_state & DOOR_OPEN_1)
3127 BlitBitmap(backbuffer, bitmap_db_door,
3128 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3130 if (old_door_state & DOOR_OPEN_2)
3131 BlitBitmap(backbuffer, bitmap_db_door,
3132 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3134 door_state &= ~DOOR_NO_COPY_BACK;
3137 return MoveDoor(door_state);
3140 unsigned int GetDoorState()
3142 return MoveDoor(DOOR_GET_STATE);
3145 unsigned int SetDoorState(unsigned int door_state)
3147 return MoveDoor(door_state | DOOR_SET_STATE);
3150 unsigned int MoveDoor(unsigned int door_state)
3152 static int door1 = DOOR_OPEN_1;
3153 static int door2 = DOOR_CLOSE_2;
3154 unsigned long door_delay = 0;
3155 unsigned long door_delay_value;
3158 if (door_1.width < 0 || door_1.width > DXSIZE)
3159 door_1.width = DXSIZE;
3160 if (door_1.height < 0 || door_1.height > DYSIZE)
3161 door_1.height = DYSIZE;
3162 if (door_2.width < 0 || door_2.width > VXSIZE)
3163 door_2.width = VXSIZE;
3164 if (door_2.height < 0 || door_2.height > VYSIZE)
3165 door_2.height = VYSIZE;
3167 if (door_state == DOOR_GET_STATE)
3168 return (door1 | door2);
3170 if (door_state & DOOR_SET_STATE)
3172 if (door_state & DOOR_ACTION_1)
3173 door1 = door_state & DOOR_ACTION_1;
3174 if (door_state & DOOR_ACTION_2)
3175 door2 = door_state & DOOR_ACTION_2;
3177 return (door1 | door2);
3180 if (!(door_state & DOOR_FORCE_REDRAW))
3182 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3183 door_state &= ~DOOR_OPEN_1;
3184 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3185 door_state &= ~DOOR_CLOSE_1;
3186 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3187 door_state &= ~DOOR_OPEN_2;
3188 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3189 door_state &= ~DOOR_CLOSE_2;
3192 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3195 if (setup.quick_doors)
3197 stepsize = 20; /* must be chosen to always draw last frame */
3198 door_delay_value = 0;
3201 if (global.autoplay_leveldir)
3203 door_state |= DOOR_NO_DELAY;
3204 door_state &= ~DOOR_CLOSE_ALL;
3208 if (game_status == GAME_MODE_EDITOR)
3209 door_state |= DOOR_NO_DELAY;
3212 if (door_state & DOOR_ACTION)
3214 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3215 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3216 boolean door_1_done = (!handle_door_1);
3217 boolean door_2_done = (!handle_door_2);
3218 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3219 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3220 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3221 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3222 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3223 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3224 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3225 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3226 int door_skip = max_door_size - door_size;
3227 int end = door_size;
3228 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3231 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3233 /* opening door sound has priority over simultaneously closing door */
3234 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3235 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3236 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3237 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3240 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3243 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3244 GC gc = bitmap->stored_clip_gc;
3246 if (door_state & DOOR_ACTION_1)
3248 int a = MIN(x * door_1.step_offset, end);
3249 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3250 int i = p + door_skip;
3252 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3254 BlitBitmap(bitmap_db_door, drawto,
3255 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3256 DXSIZE, DYSIZE, DX, DY);
3260 BlitBitmap(bitmap_db_door, drawto,
3261 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3262 DXSIZE, DYSIZE - p / 2, DX, DY);
3264 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3267 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3269 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3270 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3271 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3272 int dst2_x = DX, dst2_y = DY;
3273 int width = i, height = DYSIZE;
3275 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3276 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3279 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3280 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3283 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3285 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3286 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3287 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3288 int dst2_x = DX, dst2_y = DY;
3289 int width = DXSIZE, height = i;
3291 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3292 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3295 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3296 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3299 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3301 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3303 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3304 BlitBitmapMasked(bitmap, drawto,
3305 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3306 DX + DXSIZE - i, DY + j);
3307 BlitBitmapMasked(bitmap, drawto,
3308 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3309 DX + DXSIZE - i, DY + 140 + j);
3310 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3311 DY - (DOOR_GFX_PAGEY1 + j));
3312 BlitBitmapMasked(bitmap, drawto,
3313 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3315 BlitBitmapMasked(bitmap, drawto,
3316 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3319 BlitBitmapMasked(bitmap, drawto,
3320 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3322 BlitBitmapMasked(bitmap, drawto,
3323 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3325 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3326 BlitBitmapMasked(bitmap, drawto,
3327 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3328 DX + DXSIZE - i, DY + 77 + j);
3329 BlitBitmapMasked(bitmap, drawto,
3330 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3331 DX + DXSIZE - i, DY + 203 + j);
3334 redraw_mask |= REDRAW_DOOR_1;
3335 door_1_done = (a == end);
3338 if (door_state & DOOR_ACTION_2)
3340 int a = MIN(x * door_2.step_offset, door_size);
3341 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3342 int i = p + door_skip;
3344 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3346 BlitBitmap(bitmap_db_door, drawto,
3347 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3348 VXSIZE, VYSIZE, VX, VY);
3350 else if (x <= VYSIZE)
3352 BlitBitmap(bitmap_db_door, drawto,
3353 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3354 VXSIZE, VYSIZE - p / 2, VX, VY);
3356 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3359 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3361 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3362 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3363 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3364 int dst2_x = VX, dst2_y = VY;
3365 int width = i, height = VYSIZE;
3367 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3368 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3371 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3372 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3375 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3377 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3378 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3379 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3380 int dst2_x = VX, dst2_y = VY;
3381 int width = VXSIZE, height = i;
3383 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3384 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3387 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3388 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3391 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3393 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3395 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3396 BlitBitmapMasked(bitmap, drawto,
3397 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3398 VX + VXSIZE - i, VY + j);
3399 SetClipOrigin(bitmap, gc,
3400 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3401 BlitBitmapMasked(bitmap, drawto,
3402 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3405 BlitBitmapMasked(bitmap, drawto,
3406 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3407 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3408 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3409 BlitBitmapMasked(bitmap, drawto,
3410 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3412 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3415 redraw_mask |= REDRAW_DOOR_2;
3416 door_2_done = (a == VXSIZE);
3419 if (!(door_state & DOOR_NO_DELAY))
3423 if (game_status == GAME_MODE_MAIN)
3426 WaitUntilDelayReached(&door_delay, door_delay_value);
3431 if (door_state & DOOR_ACTION_1)
3432 door1 = door_state & DOOR_ACTION_1;
3433 if (door_state & DOOR_ACTION_2)
3434 door2 = door_state & DOOR_ACTION_2;
3436 return (door1 | door2);
3439 void DrawSpecialEditorDoor()
3441 /* draw bigger toolbox window */
3442 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3443 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3445 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3446 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3449 redraw_mask |= REDRAW_ALL;
3452 void UndrawSpecialEditorDoor()
3454 /* draw normal tape recorder window */
3455 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3456 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3459 redraw_mask |= REDRAW_ALL;
3463 /* ---------- new tool button stuff ---------------------------------------- */
3465 /* graphic position values for tool buttons */
3466 #define TOOL_BUTTON_YES_XPOS 2
3467 #define TOOL_BUTTON_YES_YPOS 250
3468 #define TOOL_BUTTON_YES_GFX_YPOS 0
3469 #define TOOL_BUTTON_YES_XSIZE 46
3470 #define TOOL_BUTTON_YES_YSIZE 28
3471 #define TOOL_BUTTON_NO_XPOS 52
3472 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3473 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3474 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3475 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3476 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3477 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3478 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3479 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3480 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3481 #define TOOL_BUTTON_PLAYER_XSIZE 30
3482 #define TOOL_BUTTON_PLAYER_YSIZE 30
3483 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3484 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3485 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3486 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3487 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3488 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3489 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3490 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3491 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3492 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3493 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3494 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3495 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3496 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3497 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3498 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3499 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3500 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3501 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3502 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3511 } toolbutton_info[NUM_TOOL_BUTTONS] =
3514 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3515 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3516 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3521 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3522 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3523 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3528 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3529 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3530 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3531 TOOL_CTRL_ID_CONFIRM,
3535 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3536 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3537 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3538 TOOL_CTRL_ID_PLAYER_1,
3542 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3543 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3544 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3545 TOOL_CTRL_ID_PLAYER_2,
3549 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3550 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3551 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3552 TOOL_CTRL_ID_PLAYER_3,
3556 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3557 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3558 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3559 TOOL_CTRL_ID_PLAYER_4,
3564 void CreateToolButtons()
3568 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3570 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3571 Bitmap *deco_bitmap = None;
3572 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3573 struct GadgetInfo *gi;
3574 unsigned long event_mask;
3575 int gd_xoffset, gd_yoffset;
3576 int gd_x1, gd_x2, gd_y;
3579 event_mask = GD_EVENT_RELEASED;
3581 gd_xoffset = toolbutton_info[i].xpos;
3582 gd_yoffset = toolbutton_info[i].ypos;
3583 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3584 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3585 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3587 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3589 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3591 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3592 &deco_bitmap, &deco_x, &deco_y);
3593 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3594 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3597 gi = CreateGadget(GDI_CUSTOM_ID, id,
3598 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3599 GDI_X, DX + toolbutton_info[i].x,
3600 GDI_Y, DY + toolbutton_info[i].y,
3601 GDI_WIDTH, toolbutton_info[i].width,
3602 GDI_HEIGHT, toolbutton_info[i].height,
3603 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3604 GDI_STATE, GD_BUTTON_UNPRESSED,
3605 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3606 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3607 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3608 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3609 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3610 GDI_DECORATION_SHIFTING, 1, 1,
3611 GDI_DIRECT_DRAW, FALSE,
3612 GDI_EVENT_MASK, event_mask,
3613 GDI_CALLBACK_ACTION, HandleToolButtons,
3617 Error(ERR_EXIT, "cannot create gadget");
3619 tool_gadget[id] = gi;
3623 void FreeToolButtons()
3627 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3628 FreeGadget(tool_gadget[i]);
3631 static void UnmapToolButtons()
3635 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3636 UnmapGadget(tool_gadget[i]);
3639 static void HandleToolButtons(struct GadgetInfo *gi)
3641 request_gadget_id = gi->custom_id;
3644 static struct Mapping_EM_to_RND_object
3647 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3648 boolean is_backside; /* backside of moving element */
3654 em_object_mapping_list[] =
3657 Xblank, TRUE, FALSE,
3661 Yacid_splash_eB, FALSE, FALSE,
3662 EL_ACID_SPLASH_RIGHT, -1, -1
3665 Yacid_splash_wB, FALSE, FALSE,
3666 EL_ACID_SPLASH_LEFT, -1, -1
3669 #ifdef EM_ENGINE_BAD_ROLL
3671 Xstone_force_e, FALSE, FALSE,
3672 EL_ROCK, -1, MV_BIT_RIGHT
3675 Xstone_force_w, FALSE, FALSE,
3676 EL_ROCK, -1, MV_BIT_LEFT
3679 Xnut_force_e, FALSE, FALSE,
3680 EL_NUT, -1, MV_BIT_RIGHT
3683 Xnut_force_w, FALSE, FALSE,
3684 EL_NUT, -1, MV_BIT_LEFT
3687 Xspring_force_e, FALSE, FALSE,
3688 EL_SPRING, -1, MV_BIT_RIGHT
3691 Xspring_force_w, FALSE, FALSE,
3692 EL_SPRING, -1, MV_BIT_LEFT
3695 Xemerald_force_e, FALSE, FALSE,
3696 EL_EMERALD, -1, MV_BIT_RIGHT
3699 Xemerald_force_w, FALSE, FALSE,
3700 EL_EMERALD, -1, MV_BIT_LEFT
3703 Xdiamond_force_e, FALSE, FALSE,
3704 EL_DIAMOND, -1, MV_BIT_RIGHT
3707 Xdiamond_force_w, FALSE, FALSE,
3708 EL_DIAMOND, -1, MV_BIT_LEFT
3711 Xbomb_force_e, FALSE, FALSE,
3712 EL_BOMB, -1, MV_BIT_RIGHT
3715 Xbomb_force_w, FALSE, FALSE,
3716 EL_BOMB, -1, MV_BIT_LEFT
3718 #endif /* EM_ENGINE_BAD_ROLL */
3721 Xstone, TRUE, FALSE,
3725 Xstone_pause, FALSE, FALSE,
3729 Xstone_fall, FALSE, FALSE,
3733 Ystone_s, FALSE, FALSE,
3734 EL_ROCK, ACTION_FALLING, -1
3737 Ystone_sB, FALSE, TRUE,
3738 EL_ROCK, ACTION_FALLING, -1
3741 Ystone_e, FALSE, FALSE,
3742 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3745 Ystone_eB, FALSE, TRUE,
3746 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3749 Ystone_w, FALSE, FALSE,
3750 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3753 Ystone_wB, FALSE, TRUE,
3754 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3761 Xnut_pause, FALSE, FALSE,
3765 Xnut_fall, FALSE, FALSE,
3769 Ynut_s, FALSE, FALSE,
3770 EL_NUT, ACTION_FALLING, -1
3773 Ynut_sB, FALSE, TRUE,
3774 EL_NUT, ACTION_FALLING, -1
3777 Ynut_e, FALSE, FALSE,
3778 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3781 Ynut_eB, FALSE, TRUE,
3782 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3785 Ynut_w, FALSE, FALSE,
3786 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3789 Ynut_wB, FALSE, TRUE,
3790 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3793 Xbug_n, TRUE, FALSE,
3797 Xbug_e, TRUE, FALSE,
3798 EL_BUG_RIGHT, -1, -1
3801 Xbug_s, TRUE, FALSE,
3805 Xbug_w, TRUE, FALSE,
3809 Xbug_gon, FALSE, FALSE,
3813 Xbug_goe, FALSE, FALSE,
3814 EL_BUG_RIGHT, -1, -1
3817 Xbug_gos, FALSE, FALSE,
3821 Xbug_gow, FALSE, FALSE,
3825 Ybug_n, FALSE, FALSE,
3826 EL_BUG, ACTION_MOVING, MV_BIT_UP
3829 Ybug_nB, FALSE, TRUE,
3830 EL_BUG, ACTION_MOVING, MV_BIT_UP
3833 Ybug_e, FALSE, FALSE,
3834 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3837 Ybug_eB, FALSE, TRUE,
3838 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3841 Ybug_s, FALSE, FALSE,
3842 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3845 Ybug_sB, FALSE, TRUE,
3846 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3849 Ybug_w, FALSE, FALSE,
3850 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3853 Ybug_wB, FALSE, TRUE,
3854 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3857 Ybug_w_n, FALSE, FALSE,
3858 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3861 Ybug_n_e, FALSE, FALSE,
3862 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3865 Ybug_e_s, FALSE, FALSE,
3866 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3869 Ybug_s_w, FALSE, FALSE,
3870 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3873 Ybug_e_n, FALSE, FALSE,
3874 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3877 Ybug_s_e, FALSE, FALSE,
3878 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3881 Ybug_w_s, FALSE, FALSE,
3882 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3885 Ybug_n_w, FALSE, FALSE,
3886 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3889 Ybug_stone, FALSE, FALSE,
3890 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3893 Ybug_spring, FALSE, FALSE,
3894 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3897 Xtank_n, TRUE, FALSE,
3898 EL_SPACESHIP_UP, -1, -1
3901 Xtank_e, TRUE, FALSE,
3902 EL_SPACESHIP_RIGHT, -1, -1
3905 Xtank_s, TRUE, FALSE,
3906 EL_SPACESHIP_DOWN, -1, -1
3909 Xtank_w, TRUE, FALSE,
3910 EL_SPACESHIP_LEFT, -1, -1
3913 Xtank_gon, FALSE, FALSE,
3914 EL_SPACESHIP_UP, -1, -1
3917 Xtank_goe, FALSE, FALSE,
3918 EL_SPACESHIP_RIGHT, -1, -1
3921 Xtank_gos, FALSE, FALSE,
3922 EL_SPACESHIP_DOWN, -1, -1
3925 Xtank_gow, FALSE, FALSE,
3926 EL_SPACESHIP_LEFT, -1, -1
3929 Ytank_n, FALSE, FALSE,
3930 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3933 Ytank_nB, FALSE, TRUE,
3934 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3937 Ytank_e, FALSE, FALSE,
3938 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3941 Ytank_eB, FALSE, TRUE,
3942 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3945 Ytank_s, FALSE, FALSE,
3946 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3949 Ytank_sB, FALSE, TRUE,
3950 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3953 Ytank_w, FALSE, FALSE,
3954 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3957 Ytank_wB, FALSE, TRUE,
3958 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3961 Ytank_w_n, FALSE, FALSE,
3962 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3965 Ytank_n_e, FALSE, FALSE,
3966 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3969 Ytank_e_s, FALSE, FALSE,
3970 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3973 Ytank_s_w, FALSE, FALSE,
3974 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3977 Ytank_e_n, FALSE, FALSE,
3978 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3981 Ytank_s_e, FALSE, FALSE,
3982 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3985 Ytank_w_s, FALSE, FALSE,
3986 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3989 Ytank_n_w, FALSE, FALSE,
3990 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3993 Ytank_stone, FALSE, FALSE,
3994 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3997 Ytank_spring, FALSE, FALSE,
3998 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4001 Xandroid, TRUE, FALSE,
4002 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4005 Xandroid_1_n, FALSE, FALSE,
4006 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4009 Xandroid_2_n, FALSE, FALSE,
4010 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4013 Xandroid_1_e, FALSE, FALSE,
4014 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4017 Xandroid_2_e, FALSE, FALSE,
4018 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4021 Xandroid_1_w, FALSE, FALSE,
4022 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4025 Xandroid_2_w, FALSE, FALSE,
4026 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4029 Xandroid_1_s, FALSE, FALSE,
4030 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4033 Xandroid_2_s, FALSE, FALSE,
4034 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4037 Yandroid_n, FALSE, FALSE,
4038 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4041 Yandroid_nB, FALSE, TRUE,
4042 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4045 Yandroid_ne, FALSE, FALSE,
4046 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4049 Yandroid_neB, FALSE, TRUE,
4050 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4053 Yandroid_e, FALSE, FALSE,
4054 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4057 Yandroid_eB, FALSE, TRUE,
4058 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4061 Yandroid_se, FALSE, FALSE,
4062 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4065 Yandroid_seB, FALSE, TRUE,
4066 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4069 Yandroid_s, FALSE, FALSE,
4070 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4073 Yandroid_sB, FALSE, TRUE,
4074 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4077 Yandroid_sw, FALSE, FALSE,
4078 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4081 Yandroid_swB, FALSE, TRUE,
4082 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4085 Yandroid_w, FALSE, FALSE,
4086 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4089 Yandroid_wB, FALSE, TRUE,
4090 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4093 Yandroid_nw, FALSE, FALSE,
4094 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4097 Yandroid_nwB, FALSE, TRUE,
4098 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4101 Xspring, TRUE, FALSE,
4105 Xspring_pause, FALSE, FALSE,
4109 Xspring_e, FALSE, FALSE,
4113 Xspring_w, FALSE, FALSE,
4117 Xspring_fall, FALSE, FALSE,
4121 Yspring_s, FALSE, FALSE,
4122 EL_SPRING, ACTION_FALLING, -1
4125 Yspring_sB, FALSE, TRUE,
4126 EL_SPRING, ACTION_FALLING, -1
4129 Yspring_e, FALSE, FALSE,
4130 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4133 Yspring_eB, FALSE, TRUE,
4134 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4137 Yspring_w, FALSE, FALSE,
4138 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4141 Yspring_wB, FALSE, TRUE,
4142 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4145 Yspring_kill_e, FALSE, FALSE,
4146 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4149 Yspring_kill_eB, FALSE, TRUE,
4150 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4153 Yspring_kill_w, FALSE, FALSE,
4154 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4157 Yspring_kill_wB, FALSE, TRUE,
4158 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4161 Xeater_n, TRUE, FALSE,
4162 EL_YAMYAM_UP, -1, -1
4165 Xeater_e, TRUE, FALSE,
4166 EL_YAMYAM_RIGHT, -1, -1
4169 Xeater_w, TRUE, FALSE,
4170 EL_YAMYAM_LEFT, -1, -1
4173 Xeater_s, TRUE, FALSE,
4174 EL_YAMYAM_DOWN, -1, -1
4177 Yeater_n, FALSE, FALSE,
4178 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4181 Yeater_nB, FALSE, TRUE,
4182 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4185 Yeater_e, FALSE, FALSE,
4186 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4189 Yeater_eB, FALSE, TRUE,
4190 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4193 Yeater_s, FALSE, FALSE,
4194 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4197 Yeater_sB, FALSE, TRUE,
4198 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4201 Yeater_w, FALSE, FALSE,
4202 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4205 Yeater_wB, FALSE, TRUE,
4206 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4209 Yeater_stone, FALSE, FALSE,
4210 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4213 Yeater_spring, FALSE, FALSE,
4214 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4217 Xalien, TRUE, FALSE,
4221 Xalien_pause, FALSE, FALSE,
4225 Yalien_n, FALSE, FALSE,
4226 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4229 Yalien_nB, FALSE, TRUE,
4230 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4233 Yalien_e, FALSE, FALSE,
4234 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4237 Yalien_eB, FALSE, TRUE,
4238 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4241 Yalien_s, FALSE, FALSE,
4242 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4245 Yalien_sB, FALSE, TRUE,
4246 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4249 Yalien_w, FALSE, FALSE,
4250 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4253 Yalien_wB, FALSE, TRUE,
4254 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4257 Yalien_stone, FALSE, FALSE,
4258 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4261 Yalien_spring, FALSE, FALSE,
4262 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4265 Xemerald, TRUE, FALSE,
4269 Xemerald_pause, FALSE, FALSE,
4273 Xemerald_fall, FALSE, FALSE,
4277 Xemerald_shine, FALSE, FALSE,
4278 EL_EMERALD, ACTION_TWINKLING, -1
4281 Yemerald_s, FALSE, FALSE,
4282 EL_EMERALD, ACTION_FALLING, -1
4285 Yemerald_sB, FALSE, TRUE,
4286 EL_EMERALD, ACTION_FALLING, -1
4289 Yemerald_e, FALSE, FALSE,
4290 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4293 Yemerald_eB, FALSE, TRUE,
4294 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4297 Yemerald_w, FALSE, FALSE,
4298 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4301 Yemerald_wB, FALSE, TRUE,
4302 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4305 Yemerald_eat, FALSE, FALSE,
4306 EL_EMERALD, ACTION_COLLECTING, -1
4309 Yemerald_stone, FALSE, FALSE,
4310 EL_NUT, ACTION_BREAKING, -1
4313 Xdiamond, TRUE, FALSE,
4317 Xdiamond_pause, FALSE, FALSE,
4321 Xdiamond_fall, FALSE, FALSE,
4325 Xdiamond_shine, FALSE, FALSE,
4326 EL_DIAMOND, ACTION_TWINKLING, -1
4329 Ydiamond_s, FALSE, FALSE,
4330 EL_DIAMOND, ACTION_FALLING, -1
4333 Ydiamond_sB, FALSE, TRUE,
4334 EL_DIAMOND, ACTION_FALLING, -1
4337 Ydiamond_e, FALSE, FALSE,
4338 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4341 Ydiamond_eB, FALSE, TRUE,
4342 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4345 Ydiamond_w, FALSE, FALSE,
4346 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4349 Ydiamond_wB, FALSE, TRUE,
4350 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4353 Ydiamond_eat, FALSE, FALSE,
4354 EL_DIAMOND, ACTION_COLLECTING, -1
4357 Ydiamond_stone, FALSE, FALSE,
4358 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4361 Xdrip_fall, TRUE, FALSE,
4362 EL_AMOEBA_DROP, -1, -1
4365 Xdrip_stretch, FALSE, FALSE,
4366 EL_AMOEBA_DROP, ACTION_FALLING, -1
4369 Xdrip_stretchB, FALSE, TRUE,
4370 EL_AMOEBA_DROP, ACTION_FALLING, -1
4373 Xdrip_eat, FALSE, FALSE,
4374 EL_AMOEBA_DROP, ACTION_GROWING, -1
4377 Ydrip_s1, FALSE, FALSE,
4378 EL_AMOEBA_DROP, ACTION_FALLING, -1
4381 Ydrip_s1B, FALSE, TRUE,
4382 EL_AMOEBA_DROP, ACTION_FALLING, -1
4385 Ydrip_s2, FALSE, FALSE,
4386 EL_AMOEBA_DROP, ACTION_FALLING, -1
4389 Ydrip_s2B, FALSE, TRUE,
4390 EL_AMOEBA_DROP, ACTION_FALLING, -1
4397 Xbomb_pause, FALSE, FALSE,
4401 Xbomb_fall, FALSE, FALSE,
4405 Ybomb_s, FALSE, FALSE,
4406 EL_BOMB, ACTION_FALLING, -1
4409 Ybomb_sB, FALSE, TRUE,
4410 EL_BOMB, ACTION_FALLING, -1
4413 Ybomb_e, FALSE, FALSE,
4414 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4417 Ybomb_eB, FALSE, TRUE,
4418 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4421 Ybomb_w, FALSE, FALSE,
4422 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4425 Ybomb_wB, FALSE, TRUE,
4426 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4429 Ybomb_eat, FALSE, FALSE,
4430 EL_BOMB, ACTION_ACTIVATING, -1
4433 Xballoon, TRUE, FALSE,
4437 Yballoon_n, FALSE, FALSE,
4438 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4441 Yballoon_nB, FALSE, TRUE,
4442 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4445 Yballoon_e, FALSE, FALSE,
4446 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4449 Yballoon_eB, FALSE, TRUE,
4450 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4453 Yballoon_s, FALSE, FALSE,
4454 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4457 Yballoon_sB, FALSE, TRUE,
4458 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4461 Yballoon_w, FALSE, FALSE,
4462 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4465 Yballoon_wB, FALSE, TRUE,
4466 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4469 Xgrass, TRUE, FALSE,
4470 EL_EMC_GRASS, -1, -1
4473 Ygrass_nB, FALSE, FALSE,
4474 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4477 Ygrass_eB, FALSE, FALSE,
4478 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4481 Ygrass_sB, FALSE, FALSE,
4482 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4485 Ygrass_wB, FALSE, FALSE,
4486 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4493 Ydirt_nB, FALSE, FALSE,
4494 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4497 Ydirt_eB, FALSE, FALSE,
4498 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4501 Ydirt_sB, FALSE, FALSE,
4502 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4505 Ydirt_wB, FALSE, FALSE,
4506 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4509 Xacid_ne, TRUE, FALSE,
4510 EL_ACID_POOL_TOPRIGHT, -1, -1
4513 Xacid_se, TRUE, FALSE,
4514 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4517 Xacid_s, TRUE, FALSE,
4518 EL_ACID_POOL_BOTTOM, -1, -1
4521 Xacid_sw, TRUE, FALSE,
4522 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4525 Xacid_nw, TRUE, FALSE,
4526 EL_ACID_POOL_TOPLEFT, -1, -1
4529 Xacid_1, TRUE, FALSE,
4533 Xacid_2, FALSE, FALSE,
4537 Xacid_3, FALSE, FALSE,
4541 Xacid_4, FALSE, FALSE,
4545 Xacid_5, FALSE, FALSE,
4549 Xacid_6, FALSE, FALSE,
4553 Xacid_7, FALSE, FALSE,
4557 Xacid_8, FALSE, FALSE,
4561 Xball_1, TRUE, FALSE,
4562 EL_EMC_MAGIC_BALL, -1, -1
4565 Xball_1B, FALSE, FALSE,
4566 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4569 Xball_2, FALSE, FALSE,
4570 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4573 Xball_2B, FALSE, FALSE,
4574 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4577 Yball_eat, FALSE, FALSE,
4578 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4581 Ykey_1_eat, FALSE, FALSE,
4582 EL_EM_KEY_1, ACTION_COLLECTING, -1
4585 Ykey_2_eat, FALSE, FALSE,
4586 EL_EM_KEY_2, ACTION_COLLECTING, -1
4589 Ykey_3_eat, FALSE, FALSE,
4590 EL_EM_KEY_3, ACTION_COLLECTING, -1
4593 Ykey_4_eat, FALSE, FALSE,
4594 EL_EM_KEY_4, ACTION_COLLECTING, -1
4597 Ykey_5_eat, FALSE, FALSE,
4598 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4601 Ykey_6_eat, FALSE, FALSE,
4602 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4605 Ykey_7_eat, FALSE, FALSE,
4606 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4609 Ykey_8_eat, FALSE, FALSE,
4610 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4613 Ylenses_eat, FALSE, FALSE,
4614 EL_EMC_LENSES, ACTION_COLLECTING, -1
4617 Ymagnify_eat, FALSE, FALSE,
4618 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4621 Ygrass_eat, FALSE, FALSE,
4622 EL_EMC_GRASS, ACTION_SNAPPING, -1
4625 Ydirt_eat, FALSE, FALSE,
4626 EL_SAND, ACTION_SNAPPING, -1
4629 Xgrow_ns, TRUE, FALSE,
4630 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4633 Ygrow_ns_eat, FALSE, FALSE,
4634 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4637 Xgrow_ew, TRUE, FALSE,
4638 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4641 Ygrow_ew_eat, FALSE, FALSE,
4642 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4645 Xwonderwall, TRUE, FALSE,
4646 EL_MAGIC_WALL, -1, -1
4649 XwonderwallB, FALSE, FALSE,
4650 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4653 Xamoeba_1, TRUE, FALSE,
4654 EL_AMOEBA_DRY, ACTION_OTHER, -1
4657 Xamoeba_2, FALSE, FALSE,
4658 EL_AMOEBA_DRY, ACTION_OTHER, -1
4661 Xamoeba_3, FALSE, FALSE,
4662 EL_AMOEBA_DRY, ACTION_OTHER, -1
4665 Xamoeba_4, FALSE, FALSE,
4666 EL_AMOEBA_DRY, ACTION_OTHER, -1
4669 Xamoeba_5, TRUE, FALSE,
4670 EL_AMOEBA_WET, ACTION_OTHER, -1
4673 Xamoeba_6, FALSE, FALSE,
4674 EL_AMOEBA_WET, ACTION_OTHER, -1
4677 Xamoeba_7, FALSE, FALSE,
4678 EL_AMOEBA_WET, ACTION_OTHER, -1
4681 Xamoeba_8, FALSE, FALSE,
4682 EL_AMOEBA_WET, ACTION_OTHER, -1
4685 Xdoor_1, TRUE, FALSE,
4686 EL_EM_GATE_1, -1, -1
4689 Xdoor_2, TRUE, FALSE,
4690 EL_EM_GATE_2, -1, -1
4693 Xdoor_3, TRUE, FALSE,
4694 EL_EM_GATE_3, -1, -1
4697 Xdoor_4, TRUE, FALSE,
4698 EL_EM_GATE_4, -1, -1
4701 Xdoor_5, TRUE, FALSE,
4702 EL_EMC_GATE_5, -1, -1
4705 Xdoor_6, TRUE, FALSE,
4706 EL_EMC_GATE_6, -1, -1
4709 Xdoor_7, TRUE, FALSE,
4710 EL_EMC_GATE_7, -1, -1
4713 Xdoor_8, TRUE, FALSE,
4714 EL_EMC_GATE_8, -1, -1
4717 Xkey_1, TRUE, FALSE,
4721 Xkey_2, TRUE, FALSE,
4725 Xkey_3, TRUE, FALSE,
4729 Xkey_4, TRUE, FALSE,
4733 Xkey_5, TRUE, FALSE,
4734 EL_EMC_KEY_5, -1, -1
4737 Xkey_6, TRUE, FALSE,
4738 EL_EMC_KEY_6, -1, -1
4741 Xkey_7, TRUE, FALSE,
4742 EL_EMC_KEY_7, -1, -1
4745 Xkey_8, TRUE, FALSE,
4746 EL_EMC_KEY_8, -1, -1
4749 Xwind_n, TRUE, FALSE,
4750 EL_BALLOON_SWITCH_UP, -1, -1
4753 Xwind_e, TRUE, FALSE,
4754 EL_BALLOON_SWITCH_RIGHT, -1, -1
4757 Xwind_s, TRUE, FALSE,
4758 EL_BALLOON_SWITCH_DOWN, -1, -1
4761 Xwind_w, TRUE, FALSE,
4762 EL_BALLOON_SWITCH_LEFT, -1, -1
4765 Xwind_nesw, TRUE, FALSE,
4766 EL_BALLOON_SWITCH_ANY, -1, -1
4769 Xwind_stop, TRUE, FALSE,
4770 EL_BALLOON_SWITCH_NONE, -1, -1
4774 EL_EM_EXIT_CLOSED, -1, -1
4777 Xexit_1, TRUE, FALSE,
4778 EL_EM_EXIT_OPEN, -1, -1
4781 Xexit_2, FALSE, FALSE,
4782 EL_EM_EXIT_OPEN, -1, -1
4785 Xexit_3, FALSE, FALSE,
4786 EL_EM_EXIT_OPEN, -1, -1
4789 Xdynamite, TRUE, FALSE,
4790 EL_EM_DYNAMITE, -1, -1
4793 Ydynamite_eat, FALSE, FALSE,
4794 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4797 Xdynamite_1, TRUE, FALSE,
4798 EL_EM_DYNAMITE_ACTIVE, -1, -1
4801 Xdynamite_2, FALSE, FALSE,
4802 EL_EM_DYNAMITE_ACTIVE, -1, -1
4805 Xdynamite_3, FALSE, FALSE,
4806 EL_EM_DYNAMITE_ACTIVE, -1, -1
4809 Xdynamite_4, FALSE, FALSE,
4810 EL_EM_DYNAMITE_ACTIVE, -1, -1
4813 Xbumper, TRUE, FALSE,
4814 EL_EMC_SPRING_BUMPER, -1, -1
4817 XbumperB, FALSE, FALSE,
4818 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4821 Xwheel, TRUE, FALSE,
4822 EL_ROBOT_WHEEL, -1, -1
4825 XwheelB, FALSE, FALSE,
4826 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4829 Xswitch, TRUE, FALSE,
4830 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4833 XswitchB, FALSE, FALSE,
4834 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4838 EL_QUICKSAND_EMPTY, -1, -1
4841 Xsand_stone, TRUE, FALSE,
4842 EL_QUICKSAND_FULL, -1, -1
4845 Xsand_stonein_1, FALSE, TRUE,
4846 EL_ROCK, ACTION_FILLING, -1
4849 Xsand_stonein_2, FALSE, TRUE,
4850 EL_ROCK, ACTION_FILLING, -1
4853 Xsand_stonein_3, FALSE, TRUE,
4854 EL_ROCK, ACTION_FILLING, -1
4857 Xsand_stonein_4, FALSE, TRUE,
4858 EL_ROCK, ACTION_FILLING, -1
4862 Xsand_stonesand_1, FALSE, FALSE,
4863 EL_QUICKSAND_EMPTYING, -1, -1
4866 Xsand_stonesand_2, FALSE, FALSE,
4867 EL_QUICKSAND_EMPTYING, -1, -1
4870 Xsand_stonesand_3, FALSE, FALSE,
4871 EL_QUICKSAND_EMPTYING, -1, -1
4874 Xsand_stonesand_4, FALSE, FALSE,
4875 EL_QUICKSAND_EMPTYING, -1, -1
4878 Xsand_stonesand_quickout_1, FALSE, FALSE,
4879 EL_QUICKSAND_EMPTYING, -1, -1
4882 Xsand_stonesand_quickout_2, FALSE, FALSE,
4883 EL_QUICKSAND_EMPTYING, -1, -1
4887 Xsand_stonesand_1, FALSE, FALSE,
4888 EL_QUICKSAND_FULL, -1, -1
4891 Xsand_stonesand_2, FALSE, FALSE,
4892 EL_QUICKSAND_FULL, -1, -1
4895 Xsand_stonesand_3, FALSE, FALSE,
4896 EL_QUICKSAND_FULL, -1, -1
4899 Xsand_stonesand_4, FALSE, FALSE,
4900 EL_QUICKSAND_FULL, -1, -1
4904 Xsand_stoneout_1, FALSE, FALSE,
4905 EL_ROCK, ACTION_EMPTYING, -1
4908 Xsand_stoneout_2, FALSE, FALSE,
4909 EL_ROCK, ACTION_EMPTYING, -1
4913 Xsand_sandstone_1, FALSE, FALSE,
4914 EL_QUICKSAND_FILLING, -1, -1
4917 Xsand_sandstone_2, FALSE, FALSE,
4918 EL_QUICKSAND_FILLING, -1, -1
4921 Xsand_sandstone_3, FALSE, FALSE,
4922 EL_QUICKSAND_FILLING, -1, -1
4925 Xsand_sandstone_4, FALSE, FALSE,
4926 EL_QUICKSAND_FILLING, -1, -1
4930 Xsand_sandstone_1, FALSE, FALSE,
4931 EL_QUICKSAND_FULL, -1, -1
4934 Xsand_sandstone_2, FALSE, FALSE,
4935 EL_QUICKSAND_FULL, -1, -1
4938 Xsand_sandstone_3, FALSE, FALSE,
4939 EL_QUICKSAND_FULL, -1, -1
4942 Xsand_sandstone_4, FALSE, FALSE,
4943 EL_QUICKSAND_FULL, -1, -1
4947 Xplant, TRUE, FALSE,
4948 EL_EMC_PLANT, -1, -1
4951 Yplant, FALSE, FALSE,
4952 EL_EMC_PLANT, -1, -1
4955 Xlenses, TRUE, FALSE,
4956 EL_EMC_LENSES, -1, -1
4959 Xmagnify, TRUE, FALSE,
4960 EL_EMC_MAGNIFIER, -1, -1
4963 Xdripper, TRUE, FALSE,
4964 EL_EMC_DRIPPER, -1, -1
4967 XdripperB, FALSE, FALSE,
4968 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4971 Xfake_blank, TRUE, FALSE,
4972 EL_INVISIBLE_WALL, -1, -1
4975 Xfake_blankB, FALSE, FALSE,
4976 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4979 Xfake_grass, TRUE, FALSE,
4980 EL_EMC_FAKE_GRASS, -1, -1
4983 Xfake_grassB, FALSE, FALSE,
4984 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4987 Xfake_door_1, TRUE, FALSE,
4988 EL_EM_GATE_1_GRAY, -1, -1
4991 Xfake_door_2, TRUE, FALSE,
4992 EL_EM_GATE_2_GRAY, -1, -1
4995 Xfake_door_3, TRUE, FALSE,
4996 EL_EM_GATE_3_GRAY, -1, -1
4999 Xfake_door_4, TRUE, FALSE,
5000 EL_EM_GATE_4_GRAY, -1, -1
5003 Xfake_door_5, TRUE, FALSE,
5004 EL_EMC_GATE_5_GRAY, -1, -1
5007 Xfake_door_6, TRUE, FALSE,
5008 EL_EMC_GATE_6_GRAY, -1, -1
5011 Xfake_door_7, TRUE, FALSE,
5012 EL_EMC_GATE_7_GRAY, -1, -1
5015 Xfake_door_8, TRUE, FALSE,
5016 EL_EMC_GATE_8_GRAY, -1, -1
5019 Xfake_acid_1, TRUE, FALSE,
5020 EL_EMC_FAKE_ACID, -1, -1
5023 Xfake_acid_2, FALSE, FALSE,
5024 EL_EMC_FAKE_ACID, -1, -1
5027 Xfake_acid_3, FALSE, FALSE,
5028 EL_EMC_FAKE_ACID, -1, -1
5031 Xfake_acid_4, FALSE, FALSE,
5032 EL_EMC_FAKE_ACID, -1, -1
5035 Xfake_acid_5, FALSE, FALSE,
5036 EL_EMC_FAKE_ACID, -1, -1
5039 Xfake_acid_6, FALSE, FALSE,
5040 EL_EMC_FAKE_ACID, -1, -1
5043 Xfake_acid_7, FALSE, FALSE,
5044 EL_EMC_FAKE_ACID, -1, -1
5047 Xfake_acid_8, FALSE, FALSE,
5048 EL_EMC_FAKE_ACID, -1, -1
5051 Xsteel_1, TRUE, FALSE,
5052 EL_STEELWALL, -1, -1
5055 Xsteel_2, TRUE, FALSE,
5056 EL_EMC_STEELWALL_2, -1, -1
5059 Xsteel_3, TRUE, FALSE,
5060 EL_EMC_STEELWALL_3, -1, -1
5063 Xsteel_4, TRUE, FALSE,
5064 EL_EMC_STEELWALL_4, -1, -1
5067 Xwall_1, TRUE, FALSE,
5071 Xwall_2, TRUE, FALSE,
5072 EL_EMC_WALL_14, -1, -1
5075 Xwall_3, TRUE, FALSE,
5076 EL_EMC_WALL_15, -1, -1
5079 Xwall_4, TRUE, FALSE,
5080 EL_EMC_WALL_16, -1, -1
5083 Xround_wall_1, TRUE, FALSE,
5084 EL_WALL_SLIPPERY, -1, -1
5087 Xround_wall_2, TRUE, FALSE,
5088 EL_EMC_WALL_SLIPPERY_2, -1, -1
5091 Xround_wall_3, TRUE, FALSE,
5092 EL_EMC_WALL_SLIPPERY_3, -1, -1
5095 Xround_wall_4, TRUE, FALSE,
5096 EL_EMC_WALL_SLIPPERY_4, -1, -1
5099 Xdecor_1, TRUE, FALSE,
5100 EL_EMC_WALL_8, -1, -1
5103 Xdecor_2, TRUE, FALSE,
5104 EL_EMC_WALL_6, -1, -1
5107 Xdecor_3, TRUE, FALSE,
5108 EL_EMC_WALL_4, -1, -1
5111 Xdecor_4, TRUE, FALSE,
5112 EL_EMC_WALL_7, -1, -1
5115 Xdecor_5, TRUE, FALSE,
5116 EL_EMC_WALL_5, -1, -1
5119 Xdecor_6, TRUE, FALSE,
5120 EL_EMC_WALL_9, -1, -1
5123 Xdecor_7, TRUE, FALSE,
5124 EL_EMC_WALL_10, -1, -1
5127 Xdecor_8, TRUE, FALSE,
5128 EL_EMC_WALL_1, -1, -1
5131 Xdecor_9, TRUE, FALSE,
5132 EL_EMC_WALL_2, -1, -1
5135 Xdecor_10, TRUE, FALSE,
5136 EL_EMC_WALL_3, -1, -1
5139 Xdecor_11, TRUE, FALSE,
5140 EL_EMC_WALL_11, -1, -1
5143 Xdecor_12, TRUE, FALSE,
5144 EL_EMC_WALL_12, -1, -1
5147 Xalpha_0, TRUE, FALSE,
5148 EL_CHAR('0'), -1, -1
5151 Xalpha_1, TRUE, FALSE,
5152 EL_CHAR('1'), -1, -1
5155 Xalpha_2, TRUE, FALSE,
5156 EL_CHAR('2'), -1, -1
5159 Xalpha_3, TRUE, FALSE,
5160 EL_CHAR('3'), -1, -1
5163 Xalpha_4, TRUE, FALSE,
5164 EL_CHAR('4'), -1, -1
5167 Xalpha_5, TRUE, FALSE,
5168 EL_CHAR('5'), -1, -1
5171 Xalpha_6, TRUE, FALSE,
5172 EL_CHAR('6'), -1, -1
5175 Xalpha_7, TRUE, FALSE,
5176 EL_CHAR('7'), -1, -1
5179 Xalpha_8, TRUE, FALSE,
5180 EL_CHAR('8'), -1, -1
5183 Xalpha_9, TRUE, FALSE,
5184 EL_CHAR('9'), -1, -1
5187 Xalpha_excla, TRUE, FALSE,
5188 EL_CHAR('!'), -1, -1
5191 Xalpha_quote, TRUE, FALSE,
5192 EL_CHAR('"'), -1, -1
5195 Xalpha_comma, TRUE, FALSE,
5196 EL_CHAR(','), -1, -1
5199 Xalpha_minus, TRUE, FALSE,
5200 EL_CHAR('-'), -1, -1
5203 Xalpha_perio, TRUE, FALSE,
5204 EL_CHAR('.'), -1, -1
5207 Xalpha_colon, TRUE, FALSE,
5208 EL_CHAR(':'), -1, -1
5211 Xalpha_quest, TRUE, FALSE,
5212 EL_CHAR('?'), -1, -1
5215 Xalpha_a, TRUE, FALSE,
5216 EL_CHAR('A'), -1, -1
5219 Xalpha_b, TRUE, FALSE,
5220 EL_CHAR('B'), -1, -1
5223 Xalpha_c, TRUE, FALSE,
5224 EL_CHAR('C'), -1, -1
5227 Xalpha_d, TRUE, FALSE,
5228 EL_CHAR('D'), -1, -1
5231 Xalpha_e, TRUE, FALSE,
5232 EL_CHAR('E'), -1, -1
5235 Xalpha_f, TRUE, FALSE,
5236 EL_CHAR('F'), -1, -1
5239 Xalpha_g, TRUE, FALSE,
5240 EL_CHAR('G'), -1, -1
5243 Xalpha_h, TRUE, FALSE,
5244 EL_CHAR('H'), -1, -1
5247 Xalpha_i, TRUE, FALSE,
5248 EL_CHAR('I'), -1, -1
5251 Xalpha_j, TRUE, FALSE,
5252 EL_CHAR('J'), -1, -1
5255 Xalpha_k, TRUE, FALSE,
5256 EL_CHAR('K'), -1, -1
5259 Xalpha_l, TRUE, FALSE,
5260 EL_CHAR('L'), -1, -1
5263 Xalpha_m, TRUE, FALSE,
5264 EL_CHAR('M'), -1, -1
5267 Xalpha_n, TRUE, FALSE,
5268 EL_CHAR('N'), -1, -1
5271 Xalpha_o, TRUE, FALSE,
5272 EL_CHAR('O'), -1, -1
5275 Xalpha_p, TRUE, FALSE,
5276 EL_CHAR('P'), -1, -1
5279 Xalpha_q, TRUE, FALSE,
5280 EL_CHAR('Q'), -1, -1
5283 Xalpha_r, TRUE, FALSE,
5284 EL_CHAR('R'), -1, -1
5287 Xalpha_s, TRUE, FALSE,
5288 EL_CHAR('S'), -1, -1
5291 Xalpha_t, TRUE, FALSE,
5292 EL_CHAR('T'), -1, -1
5295 Xalpha_u, TRUE, FALSE,
5296 EL_CHAR('U'), -1, -1
5299 Xalpha_v, TRUE, FALSE,
5300 EL_CHAR('V'), -1, -1
5303 Xalpha_w, TRUE, FALSE,
5304 EL_CHAR('W'), -1, -1
5307 Xalpha_x, TRUE, FALSE,
5308 EL_CHAR('X'), -1, -1
5311 Xalpha_y, TRUE, FALSE,
5312 EL_CHAR('Y'), -1, -1
5315 Xalpha_z, TRUE, FALSE,
5316 EL_CHAR('Z'), -1, -1
5319 Xalpha_arrow_e, TRUE, FALSE,
5320 EL_CHAR('>'), -1, -1
5323 Xalpha_arrow_w, TRUE, FALSE,
5324 EL_CHAR('<'), -1, -1
5327 Xalpha_copyr, TRUE, FALSE,
5328 EL_CHAR('©'), -1, -1
5332 Xboom_bug, FALSE, FALSE,
5333 EL_BUG, ACTION_EXPLODING, -1
5336 Xboom_bomb, FALSE, FALSE,
5337 EL_BOMB, ACTION_EXPLODING, -1
5340 Xboom_android, FALSE, FALSE,
5341 EL_EMC_ANDROID, ACTION_OTHER, -1
5344 Xboom_1, FALSE, FALSE,
5345 EL_DEFAULT, ACTION_EXPLODING, -1
5348 Xboom_2, FALSE, FALSE,
5349 EL_DEFAULT, ACTION_EXPLODING, -1
5352 Znormal, FALSE, FALSE,
5356 Zdynamite, FALSE, FALSE,
5360 Zplayer, FALSE, FALSE,
5364 ZBORDER, FALSE, FALSE,
5374 static struct Mapping_EM_to_RND_player
5383 em_player_mapping_list[] =
5387 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5391 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5395 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5399 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5403 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5407 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5411 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5415 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5419 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5423 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5427 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5431 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5435 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5439 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5443 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5447 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5451 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5455 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5459 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5463 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5467 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5471 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5475 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5479 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5483 EL_PLAYER_1, ACTION_DEFAULT, -1,
5487 EL_PLAYER_2, ACTION_DEFAULT, -1,
5491 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5495 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5499 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5503 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5507 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5511 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5515 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5519 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5523 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5527 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5531 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5535 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5539 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5543 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5547 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5551 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5555 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5559 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5563 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5567 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5571 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5575 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5579 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5583 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5587 EL_PLAYER_3, ACTION_DEFAULT, -1,
5591 EL_PLAYER_4, ACTION_DEFAULT, -1,
5600 int map_element_RND_to_EM(int element_rnd)
5602 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5603 static boolean mapping_initialized = FALSE;
5605 if (!mapping_initialized)
5609 /* return "Xalpha_quest" for all undefined elements in mapping array */
5610 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5611 mapping_RND_to_EM[i] = Xalpha_quest;
5613 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5614 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5615 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5616 em_object_mapping_list[i].element_em;
5618 mapping_initialized = TRUE;
5621 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5622 return mapping_RND_to_EM[element_rnd];
5624 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5629 int map_element_EM_to_RND(int element_em)
5631 static unsigned short mapping_EM_to_RND[TILE_MAX];
5632 static boolean mapping_initialized = FALSE;
5634 if (!mapping_initialized)
5638 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5639 for (i = 0; i < TILE_MAX; i++)
5640 mapping_EM_to_RND[i] = EL_UNKNOWN;
5642 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5643 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5644 em_object_mapping_list[i].element_rnd;
5646 mapping_initialized = TRUE;
5649 if (element_em >= 0 && element_em < TILE_MAX)
5650 return mapping_EM_to_RND[element_em];
5652 Error(ERR_WARN, "invalid EM level element %d", element_em);
5657 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5659 struct LevelInfo_EM *level_em = level->native_em_level;
5660 struct LEVEL *lev = level_em->lev;
5663 for (i = 0; i < TILE_MAX; i++)
5664 lev->android_array[i] = Xblank;
5666 for (i = 0; i < level->num_android_clone_elements; i++)
5668 int element_rnd = level->android_clone_element[i];
5669 int element_em = map_element_RND_to_EM(element_rnd);
5671 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5672 if (em_object_mapping_list[j].element_rnd == element_rnd)
5673 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5677 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5679 struct LevelInfo_EM *level_em = level->native_em_level;
5680 struct LEVEL *lev = level_em->lev;
5683 level->num_android_clone_elements = 0;
5685 for (i = 0; i < TILE_MAX; i++)
5687 int element_em = lev->android_array[i];
5689 boolean element_found = FALSE;
5691 if (element_em == Xblank)
5694 element_rnd = map_element_EM_to_RND(element_em);
5696 for (j = 0; j < level->num_android_clone_elements; j++)
5697 if (level->android_clone_element[j] == element_rnd)
5698 element_found = TRUE;
5702 level->android_clone_element[level->num_android_clone_elements++] =
5705 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5710 if (level->num_android_clone_elements == 0)
5712 level->num_android_clone_elements = 1;
5713 level->android_clone_element[0] = EL_EMPTY;
5717 int map_direction_RND_to_EM(int direction)
5719 return (direction == MV_UP ? 0 :
5720 direction == MV_RIGHT ? 1 :
5721 direction == MV_DOWN ? 2 :
5722 direction == MV_LEFT ? 3 :
5726 int map_direction_EM_to_RND(int direction)
5728 return (direction == 0 ? MV_UP :
5729 direction == 1 ? MV_RIGHT :
5730 direction == 2 ? MV_DOWN :
5731 direction == 3 ? MV_LEFT :
5735 int get_next_element(int element)
5739 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5740 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5741 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5742 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5743 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5744 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5745 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5746 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5747 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5748 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5749 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5751 default: return element;
5756 int el_act_dir2img(int element, int action, int direction)
5758 element = GFX_ELEMENT(element);
5760 if (direction == MV_NONE)
5761 return element_info[element].graphic[action];
5763 direction = MV_DIR_TO_BIT(direction);
5765 return element_info[element].direction_graphic[action][direction];
5768 int el_act_dir2img(int element, int action, int direction)
5770 element = GFX_ELEMENT(element);
5771 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5773 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5774 return element_info[element].direction_graphic[action][direction];
5779 static int el_act_dir2crm(int element, int action, int direction)
5781 element = GFX_ELEMENT(element);
5783 if (direction == MV_NONE)
5784 return element_info[element].crumbled[action];
5786 direction = MV_DIR_TO_BIT(direction);
5788 return element_info[element].direction_crumbled[action][direction];
5791 static int el_act_dir2crm(int element, int action, int direction)
5793 element = GFX_ELEMENT(element);
5794 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5796 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5797 return element_info[element].direction_crumbled[action][direction];
5801 int el_act2img(int element, int action)
5803 element = GFX_ELEMENT(element);
5805 return element_info[element].graphic[action];
5808 int el_act2crm(int element, int action)
5810 element = GFX_ELEMENT(element);
5812 return element_info[element].crumbled[action];
5815 int el_dir2img(int element, int direction)
5817 element = GFX_ELEMENT(element);
5819 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5822 int el2baseimg(int element)
5824 return element_info[element].graphic[ACTION_DEFAULT];
5827 int el2img(int element)
5829 element = GFX_ELEMENT(element);
5831 return element_info[element].graphic[ACTION_DEFAULT];
5834 int el2edimg(int element)
5836 element = GFX_ELEMENT(element);
5838 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5841 int el2preimg(int element)
5843 element = GFX_ELEMENT(element);
5845 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5848 int el2panelimg(int element)
5850 element = GFX_ELEMENT(element);
5852 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5855 int font2baseimg(int font_nr)
5857 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5860 int getBeltNrFromBeltElement(int element)
5862 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5863 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5864 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5867 int getBeltNrFromBeltActiveElement(int element)
5869 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5870 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5871 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5874 int getBeltNrFromBeltSwitchElement(int element)
5876 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5877 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5878 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5881 int getBeltDirNrFromBeltElement(int element)
5883 static int belt_base_element[4] =
5885 EL_CONVEYOR_BELT_1_LEFT,
5886 EL_CONVEYOR_BELT_2_LEFT,
5887 EL_CONVEYOR_BELT_3_LEFT,
5888 EL_CONVEYOR_BELT_4_LEFT
5891 int belt_nr = getBeltNrFromBeltElement(element);
5892 int belt_dir_nr = element - belt_base_element[belt_nr];
5894 return (belt_dir_nr % 3);
5897 int getBeltDirNrFromBeltSwitchElement(int element)
5899 static int belt_base_element[4] =
5901 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5902 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5903 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5904 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5907 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5908 int belt_dir_nr = element - belt_base_element[belt_nr];
5910 return (belt_dir_nr % 3);
5913 int getBeltDirFromBeltElement(int element)
5915 static int belt_move_dir[3] =
5922 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5924 return belt_move_dir[belt_dir_nr];
5927 int getBeltDirFromBeltSwitchElement(int element)
5929 static int belt_move_dir[3] =
5936 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5938 return belt_move_dir[belt_dir_nr];
5941 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5943 static int belt_base_element[4] =
5945 EL_CONVEYOR_BELT_1_LEFT,
5946 EL_CONVEYOR_BELT_2_LEFT,
5947 EL_CONVEYOR_BELT_3_LEFT,
5948 EL_CONVEYOR_BELT_4_LEFT
5951 return belt_base_element[belt_nr] + belt_dir_nr;
5954 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5956 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5958 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5961 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5963 static int belt_base_element[4] =
5965 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5966 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5967 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5968 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5971 return belt_base_element[belt_nr] + belt_dir_nr;
5974 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5976 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5978 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5981 int getNumActivePlayers_EM()
5983 int num_players = 0;
5989 for (i = 0; i < MAX_PLAYERS; i++)
5990 if (tape.player_participates[i])
5996 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5998 int game_frame_delay_value;
6000 game_frame_delay_value =
6001 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6002 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6005 if (tape.playing && tape.warp_forward && !tape.pausing)
6006 game_frame_delay_value = 0;
6008 return game_frame_delay_value;
6011 unsigned int InitRND(long seed)
6013 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6014 return InitEngineRandom_EM(seed);
6016 return InitEngineRandom_RND(seed);
6020 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6021 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6024 inline static int get_effective_element_EM(int tile, int frame_em)
6026 int element = object_mapping[tile].element_rnd;
6027 int action = object_mapping[tile].action;
6028 boolean is_backside = object_mapping[tile].is_backside;
6029 boolean action_removing = (action == ACTION_DIGGING ||
6030 action == ACTION_SNAPPING ||
6031 action == ACTION_COLLECTING);
6037 case Yacid_splash_eB:
6038 case Yacid_splash_wB:
6039 return (frame_em > 5 ? EL_EMPTY : element);
6045 else /* frame_em == 7 */
6049 case Yacid_splash_eB:
6050 case Yacid_splash_wB:
6053 case Yemerald_stone:
6056 case Ydiamond_stone:
6060 case Xdrip_stretchB:
6079 case Xsand_stonein_1:
6080 case Xsand_stonein_2:
6081 case Xsand_stonein_3:
6082 case Xsand_stonein_4:
6086 return (is_backside || action_removing ? EL_EMPTY : element);
6091 inline static boolean check_linear_animation_EM(int tile)
6095 case Xsand_stonesand_1:
6096 case Xsand_stonesand_quickout_1:
6097 case Xsand_sandstone_1:
6098 case Xsand_stonein_1:
6099 case Xsand_stoneout_1:
6124 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6125 boolean has_crumbled_graphics,
6126 int crumbled, int sync_frame)
6128 /* if element can be crumbled, but certain action graphics are just empty
6129 space (like instantly snapping sand to empty space in 1 frame), do not
6130 treat these empty space graphics as crumbled graphics in EMC engine */
6131 if (crumbled == IMG_EMPTY_SPACE)
6132 has_crumbled_graphics = FALSE;
6134 if (has_crumbled_graphics)
6136 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6137 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6138 g_crumbled->anim_delay,
6139 g_crumbled->anim_mode,
6140 g_crumbled->anim_start_frame,
6143 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6144 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6146 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6148 g_em->has_crumbled_graphics = TRUE;
6152 g_em->crumbled_bitmap = NULL;
6153 g_em->crumbled_src_x = 0;
6154 g_em->crumbled_src_y = 0;
6155 g_em->crumbled_border_size = 0;
6157 g_em->has_crumbled_graphics = FALSE;
6161 void ResetGfxAnimation_EM(int x, int y, int tile)
6166 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6167 int tile, int frame_em, int x, int y)
6169 int action = object_mapping[tile].action;
6171 int direction = object_mapping[tile].direction;
6172 int effective_element = get_effective_element_EM(tile, frame_em);
6173 int graphic = (direction == MV_NONE ?
6174 el_act2img(effective_element, action) :
6175 el_act_dir2img(effective_element, action, direction));
6176 struct GraphicInfo *g = &graphic_info[graphic];
6179 boolean action_removing = (action == ACTION_DIGGING ||
6180 action == ACTION_SNAPPING ||
6181 action == ACTION_COLLECTING);
6182 boolean action_moving = (action == ACTION_FALLING ||
6183 action == ACTION_MOVING ||
6184 action == ACTION_PUSHING ||
6185 action == ACTION_EATING ||
6186 action == ACTION_FILLING ||
6187 action == ACTION_EMPTYING);
6188 boolean action_falling = (action == ACTION_FALLING ||
6189 action == ACTION_FILLING ||
6190 action == ACTION_EMPTYING);
6193 if (tile == Xsand_stonesand_1 ||
6194 tile == Xsand_stonesand_2 ||
6195 tile == Xsand_stonesand_3 ||
6196 tile == Xsand_stonesand_4)
6197 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6201 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6205 // printf("::: resetting... [%d]\n", tile);
6208 if (action_removing || check_linear_animation_EM(tile))
6210 GfxFrame[x][y] = frame_em;
6212 // printf("::: resetting... [%d]\n", tile);
6215 else if (action_moving)
6217 boolean is_backside = object_mapping[tile].is_backside;
6221 int direction = object_mapping[tile].direction;
6222 int move_dir = (action_falling ? MV_DOWN : direction);
6226 if (move_dir == MV_LEFT)
6227 GfxFrame[x - 1][y] = GfxFrame[x][y];
6228 else if (move_dir == MV_RIGHT)
6229 GfxFrame[x + 1][y] = GfxFrame[x][y];
6230 else if (move_dir == MV_UP)
6231 GfxFrame[x][y - 1] = GfxFrame[x][y];
6232 else if (move_dir == MV_DOWN)
6233 GfxFrame[x][y + 1] = GfxFrame[x][y];
6240 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6241 if (tile == Xsand_stonesand_quickout_1 ||
6242 tile == Xsand_stonesand_quickout_2)
6247 if (tile == Xsand_stonesand_1 ||
6248 tile == Xsand_stonesand_2 ||
6249 tile == Xsand_stonesand_3 ||
6250 tile == Xsand_stonesand_4)
6251 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6255 if (graphic_info[graphic].anim_global_sync)
6256 sync_frame = FrameCounter;
6257 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6258 sync_frame = GfxFrame[x][y];
6260 sync_frame = 0; /* playfield border (pseudo steel) */
6262 SetRandomAnimationValue(x, y);
6264 int frame = getAnimationFrame(g->anim_frames,
6267 g->anim_start_frame,
6270 g_em->unique_identifier =
6271 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6275 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6276 int tile, int frame_em, int x, int y)
6278 int action = object_mapping[tile].action;
6279 int direction = object_mapping[tile].direction;
6280 int effective_element = get_effective_element_EM(tile, frame_em);
6281 int graphic = (direction == MV_NONE ?
6282 el_act2img(effective_element, action) :
6283 el_act_dir2img(effective_element, action, direction));
6284 int crumbled = (direction == MV_NONE ?
6285 el_act2crm(effective_element, action) :
6286 el_act_dir2crm(effective_element, action, direction));
6287 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6288 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6289 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6290 struct GraphicInfo *g = &graphic_info[graphic];
6292 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6297 if (frame_em == 0) /* reset animation frame for certain elements */
6299 if (check_linear_animation_EM(tile))
6304 if (graphic_info[graphic].anim_global_sync)
6305 sync_frame = FrameCounter;
6306 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6307 sync_frame = GfxFrame[x][y];
6309 sync_frame = 0; /* playfield border (pseudo steel) */
6311 SetRandomAnimationValue(x, y);
6313 int frame = getAnimationFrame(g->anim_frames,
6316 g->anim_start_frame,
6319 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6320 &g_em->src_x, &g_em->src_y, FALSE);
6322 /* (updating the "crumbled" graphic definitions is probably not really needed,
6323 as animations for crumbled graphics can't be longer than one EMC cycle) */
6325 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6330 g_em->crumbled_bitmap = NULL;
6331 g_em->crumbled_src_x = 0;
6332 g_em->crumbled_src_y = 0;
6334 g_em->has_crumbled_graphics = FALSE;
6336 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6338 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6339 g_crumbled->anim_delay,
6340 g_crumbled->anim_mode,
6341 g_crumbled->anim_start_frame,
6344 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6345 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6347 g_em->has_crumbled_graphics = TRUE;
6352 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
6353 int player_nr, int anim, int frame_em)
6355 int element = player_mapping[player_nr][anim].element_rnd;
6356 int action = player_mapping[player_nr][anim].action;
6357 int direction = player_mapping[player_nr][anim].direction;
6358 int graphic = (direction == MV_NONE ?
6359 el_act2img(element, action) :
6360 el_act_dir2img(element, action, direction));
6361 struct GraphicInfo *g = &graphic_info[graphic];
6364 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6366 stored_player[player_nr].StepFrame = frame_em;
6368 sync_frame = stored_player[player_nr].Frame;
6370 int frame = getAnimationFrame(g->anim_frames,
6373 g->anim_start_frame,
6376 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6377 &g_em->src_x, &g_em->src_y, FALSE);
6380 printf("::: %d: %d, %d [%d]\n",
6382 stored_player[player_nr].Frame,
6383 stored_player[player_nr].StepFrame,
6388 void InitGraphicInfo_EM(void)
6391 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6392 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6397 int num_em_gfx_errors = 0;
6399 if (graphic_info_em_object[0][0].bitmap == NULL)
6401 /* EM graphics not yet initialized in em_open_all() */
6406 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6409 /* always start with reliable default values */
6410 for (i = 0; i < TILE_MAX; i++)
6412 object_mapping[i].element_rnd = EL_UNKNOWN;
6413 object_mapping[i].is_backside = FALSE;
6414 object_mapping[i].action = ACTION_DEFAULT;
6415 object_mapping[i].direction = MV_NONE;
6418 /* always start with reliable default values */
6419 for (p = 0; p < MAX_PLAYERS; p++)
6421 for (i = 0; i < SPR_MAX; i++)
6423 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6424 player_mapping[p][i].action = ACTION_DEFAULT;
6425 player_mapping[p][i].direction = MV_NONE;
6429 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6431 int e = em_object_mapping_list[i].element_em;
6433 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6434 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6436 if (em_object_mapping_list[i].action != -1)
6437 object_mapping[e].action = em_object_mapping_list[i].action;
6439 if (em_object_mapping_list[i].direction != -1)
6440 object_mapping[e].direction =
6441 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6444 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6446 int a = em_player_mapping_list[i].action_em;
6447 int p = em_player_mapping_list[i].player_nr;
6449 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6451 if (em_player_mapping_list[i].action != -1)
6452 player_mapping[p][a].action = em_player_mapping_list[i].action;
6454 if (em_player_mapping_list[i].direction != -1)
6455 player_mapping[p][a].direction =
6456 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6459 for (i = 0; i < TILE_MAX; i++)
6461 int element = object_mapping[i].element_rnd;
6462 int action = object_mapping[i].action;
6463 int direction = object_mapping[i].direction;
6464 boolean is_backside = object_mapping[i].is_backside;
6466 boolean action_removing = (action == ACTION_DIGGING ||
6467 action == ACTION_SNAPPING ||
6468 action == ACTION_COLLECTING);
6470 boolean action_exploding = ((action == ACTION_EXPLODING ||
6471 action == ACTION_SMASHED_BY_ROCK ||
6472 action == ACTION_SMASHED_BY_SPRING) &&
6473 element != EL_DIAMOND);
6474 boolean action_active = (action == ACTION_ACTIVE);
6475 boolean action_other = (action == ACTION_OTHER);
6477 for (j = 0; j < 8; j++)
6480 int effective_element = get_effective_element_EM(i, j);
6482 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6483 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6485 i == Xdrip_stretch ? element :
6486 i == Xdrip_stretchB ? element :
6487 i == Ydrip_s1 ? element :
6488 i == Ydrip_s1B ? element :
6489 i == Xball_1B ? element :
6490 i == Xball_2 ? element :
6491 i == Xball_2B ? element :
6492 i == Yball_eat ? element :
6493 i == Ykey_1_eat ? element :
6494 i == Ykey_2_eat ? element :
6495 i == Ykey_3_eat ? element :
6496 i == Ykey_4_eat ? element :
6497 i == Ykey_5_eat ? element :
6498 i == Ykey_6_eat ? element :
6499 i == Ykey_7_eat ? element :
6500 i == Ykey_8_eat ? element :
6501 i == Ylenses_eat ? element :
6502 i == Ymagnify_eat ? element :
6503 i == Ygrass_eat ? element :
6504 i == Ydirt_eat ? element :
6505 i == Yemerald_stone ? EL_EMERALD :
6506 i == Ydiamond_stone ? EL_ROCK :
6507 i == Xsand_stonein_1 ? element :
6508 i == Xsand_stonein_2 ? element :
6509 i == Xsand_stonein_3 ? element :
6510 i == Xsand_stonein_4 ? element :
6511 is_backside ? EL_EMPTY :
6512 action_removing ? EL_EMPTY :
6515 int effective_action = (j < 7 ? action :
6516 i == Xdrip_stretch ? action :
6517 i == Xdrip_stretchB ? action :
6518 i == Ydrip_s1 ? action :
6519 i == Ydrip_s1B ? action :
6520 i == Xball_1B ? action :
6521 i == Xball_2 ? action :
6522 i == Xball_2B ? action :
6523 i == Yball_eat ? action :
6524 i == Ykey_1_eat ? action :
6525 i == Ykey_2_eat ? action :
6526 i == Ykey_3_eat ? action :
6527 i == Ykey_4_eat ? action :
6528 i == Ykey_5_eat ? action :
6529 i == Ykey_6_eat ? action :
6530 i == Ykey_7_eat ? action :
6531 i == Ykey_8_eat ? action :
6532 i == Ylenses_eat ? action :
6533 i == Ymagnify_eat ? action :
6534 i == Ygrass_eat ? action :
6535 i == Ydirt_eat ? action :
6536 i == Xsand_stonein_1 ? action :
6537 i == Xsand_stonein_2 ? action :
6538 i == Xsand_stonein_3 ? action :
6539 i == Xsand_stonein_4 ? action :
6540 i == Xsand_stoneout_1 ? action :
6541 i == Xsand_stoneout_2 ? action :
6542 i == Xboom_android ? ACTION_EXPLODING :
6543 action_exploding ? ACTION_EXPLODING :
6544 action_active ? action :
6545 action_other ? action :
6547 int graphic = (el_act_dir2img(effective_element, effective_action,
6549 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6551 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6552 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6553 boolean has_action_graphics = (graphic != base_graphic);
6554 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6555 struct GraphicInfo *g = &graphic_info[graphic];
6557 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6559 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6562 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6563 boolean special_animation = (action != ACTION_DEFAULT &&
6564 g->anim_frames == 3 &&
6565 g->anim_delay == 2 &&
6566 g->anim_mode & ANIM_LINEAR);
6567 int sync_frame = (i == Xdrip_stretch ? 7 :
6568 i == Xdrip_stretchB ? 7 :
6569 i == Ydrip_s2 ? j + 8 :
6570 i == Ydrip_s2B ? j + 8 :
6579 i == Xfake_acid_1 ? 0 :
6580 i == Xfake_acid_2 ? 10 :
6581 i == Xfake_acid_3 ? 20 :
6582 i == Xfake_acid_4 ? 30 :
6583 i == Xfake_acid_5 ? 40 :
6584 i == Xfake_acid_6 ? 50 :
6585 i == Xfake_acid_7 ? 60 :
6586 i == Xfake_acid_8 ? 70 :
6588 i == Xball_2B ? j + 8 :
6589 i == Yball_eat ? j + 1 :
6590 i == Ykey_1_eat ? j + 1 :
6591 i == Ykey_2_eat ? j + 1 :
6592 i == Ykey_3_eat ? j + 1 :
6593 i == Ykey_4_eat ? j + 1 :
6594 i == Ykey_5_eat ? j + 1 :
6595 i == Ykey_6_eat ? j + 1 :
6596 i == Ykey_7_eat ? j + 1 :
6597 i == Ykey_8_eat ? j + 1 :
6598 i == Ylenses_eat ? j + 1 :
6599 i == Ymagnify_eat ? j + 1 :
6600 i == Ygrass_eat ? j + 1 :
6601 i == Ydirt_eat ? j + 1 :
6602 i == Xamoeba_1 ? 0 :
6603 i == Xamoeba_2 ? 1 :
6604 i == Xamoeba_3 ? 2 :
6605 i == Xamoeba_4 ? 3 :
6606 i == Xamoeba_5 ? 0 :
6607 i == Xamoeba_6 ? 1 :
6608 i == Xamoeba_7 ? 2 :
6609 i == Xamoeba_8 ? 3 :
6610 i == Xexit_2 ? j + 8 :
6611 i == Xexit_3 ? j + 16 :
6612 i == Xdynamite_1 ? 0 :
6613 i == Xdynamite_2 ? 8 :
6614 i == Xdynamite_3 ? 16 :
6615 i == Xdynamite_4 ? 24 :
6616 i == Xsand_stonein_1 ? j + 1 :
6617 i == Xsand_stonein_2 ? j + 9 :
6618 i == Xsand_stonein_3 ? j + 17 :
6619 i == Xsand_stonein_4 ? j + 25 :
6620 i == Xsand_stoneout_1 && j == 0 ? 0 :
6621 i == Xsand_stoneout_1 && j == 1 ? 0 :
6622 i == Xsand_stoneout_1 && j == 2 ? 1 :
6623 i == Xsand_stoneout_1 && j == 3 ? 2 :
6624 i == Xsand_stoneout_1 && j == 4 ? 2 :
6625 i == Xsand_stoneout_1 && j == 5 ? 3 :
6626 i == Xsand_stoneout_1 && j == 6 ? 4 :
6627 i == Xsand_stoneout_1 && j == 7 ? 4 :
6628 i == Xsand_stoneout_2 && j == 0 ? 5 :
6629 i == Xsand_stoneout_2 && j == 1 ? 6 :
6630 i == Xsand_stoneout_2 && j == 2 ? 7 :
6631 i == Xsand_stoneout_2 && j == 3 ? 8 :
6632 i == Xsand_stoneout_2 && j == 4 ? 9 :
6633 i == Xsand_stoneout_2 && j == 5 ? 11 :
6634 i == Xsand_stoneout_2 && j == 6 ? 13 :
6635 i == Xsand_stoneout_2 && j == 7 ? 15 :
6636 i == Xboom_bug && j == 1 ? 2 :
6637 i == Xboom_bug && j == 2 ? 2 :
6638 i == Xboom_bug && j == 3 ? 4 :
6639 i == Xboom_bug && j == 4 ? 4 :
6640 i == Xboom_bug && j == 5 ? 2 :
6641 i == Xboom_bug && j == 6 ? 2 :
6642 i == Xboom_bug && j == 7 ? 0 :
6643 i == Xboom_bomb && j == 1 ? 2 :
6644 i == Xboom_bomb && j == 2 ? 2 :
6645 i == Xboom_bomb && j == 3 ? 4 :
6646 i == Xboom_bomb && j == 4 ? 4 :
6647 i == Xboom_bomb && j == 5 ? 2 :
6648 i == Xboom_bomb && j == 6 ? 2 :
6649 i == Xboom_bomb && j == 7 ? 0 :
6650 i == Xboom_android && j == 7 ? 6 :
6651 i == Xboom_1 && j == 1 ? 2 :
6652 i == Xboom_1 && j == 2 ? 2 :
6653 i == Xboom_1 && j == 3 ? 4 :
6654 i == Xboom_1 && j == 4 ? 4 :
6655 i == Xboom_1 && j == 5 ? 6 :
6656 i == Xboom_1 && j == 6 ? 6 :
6657 i == Xboom_1 && j == 7 ? 8 :
6658 i == Xboom_2 && j == 0 ? 8 :
6659 i == Xboom_2 && j == 1 ? 8 :
6660 i == Xboom_2 && j == 2 ? 10 :
6661 i == Xboom_2 && j == 3 ? 10 :
6662 i == Xboom_2 && j == 4 ? 10 :
6663 i == Xboom_2 && j == 5 ? 12 :
6664 i == Xboom_2 && j == 6 ? 12 :
6665 i == Xboom_2 && j == 7 ? 12 :
6666 special_animation && j == 4 ? 3 :
6667 effective_action != action ? 0 :
6671 Bitmap *debug_bitmap = g_em->bitmap;
6672 int debug_src_x = g_em->src_x;
6673 int debug_src_y = g_em->src_y;
6676 int frame = getAnimationFrame(g->anim_frames,
6679 g->anim_start_frame,
6682 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6683 g->double_movement && is_backside);
6685 g_em->bitmap = src_bitmap;
6686 g_em->src_x = src_x;
6687 g_em->src_y = src_y;
6688 g_em->src_offset_x = 0;
6689 g_em->src_offset_y = 0;
6690 g_em->dst_offset_x = 0;
6691 g_em->dst_offset_y = 0;
6692 g_em->width = TILEX;
6693 g_em->height = TILEY;
6695 g_em->preserve_background = FALSE;
6698 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6703 g_em->crumbled_bitmap = NULL;
6704 g_em->crumbled_src_x = 0;
6705 g_em->crumbled_src_y = 0;
6706 g_em->crumbled_border_size = 0;
6708 g_em->has_crumbled_graphics = FALSE;
6711 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6712 printf("::: empty crumbled: %d [%s], %d, %d\n",
6713 effective_element, element_info[effective_element].token_name,
6714 effective_action, direction);
6717 /* if element can be crumbled, but certain action graphics are just empty
6718 space (like instantly snapping sand to empty space in 1 frame), do not
6719 treat these empty space graphics as crumbled graphics in EMC engine */
6720 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6722 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6723 g_crumbled->anim_delay,
6724 g_crumbled->anim_mode,
6725 g_crumbled->anim_start_frame,
6728 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
6730 g_em->has_crumbled_graphics = TRUE;
6731 g_em->crumbled_bitmap = src_bitmap;
6732 g_em->crumbled_src_x = src_x;
6733 g_em->crumbled_src_y = src_y;
6734 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6738 if (g_em == &graphic_info_em_object[207][0])
6739 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
6740 graphic_info_em_object[207][0].crumbled_src_x,
6741 graphic_info_em_object[207][0].crumbled_src_y,
6743 crumbled, frame, src_x, src_y,
6748 g->anim_start_frame,
6750 gfx.anim_random_frame,
6755 printf("::: EMC tile %d is crumbled\n", i);
6761 if (element == EL_ROCK &&
6762 effective_action == ACTION_FILLING)
6763 printf("::: has_action_graphics == %d\n", has_action_graphics);
6766 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6767 effective_action == ACTION_MOVING ||
6768 effective_action == ACTION_PUSHING ||
6769 effective_action == ACTION_EATING)) ||
6770 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6771 effective_action == ACTION_EMPTYING)))
6774 (effective_action == ACTION_FALLING ||
6775 effective_action == ACTION_FILLING ||
6776 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6777 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6778 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6779 int num_steps = (i == Ydrip_s1 ? 16 :
6780 i == Ydrip_s1B ? 16 :
6781 i == Ydrip_s2 ? 16 :
6782 i == Ydrip_s2B ? 16 :
6783 i == Xsand_stonein_1 ? 32 :
6784 i == Xsand_stonein_2 ? 32 :
6785 i == Xsand_stonein_3 ? 32 :
6786 i == Xsand_stonein_4 ? 32 :
6787 i == Xsand_stoneout_1 ? 16 :
6788 i == Xsand_stoneout_2 ? 16 : 8);
6789 int cx = ABS(dx) * (TILEX / num_steps);
6790 int cy = ABS(dy) * (TILEY / num_steps);
6791 int step_frame = (i == Ydrip_s2 ? j + 8 :
6792 i == Ydrip_s2B ? j + 8 :
6793 i == Xsand_stonein_2 ? j + 8 :
6794 i == Xsand_stonein_3 ? j + 16 :
6795 i == Xsand_stonein_4 ? j + 24 :
6796 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6797 int step = (is_backside ? step_frame : num_steps - step_frame);
6799 if (is_backside) /* tile where movement starts */
6801 if (dx < 0 || dy < 0)
6803 g_em->src_offset_x = cx * step;
6804 g_em->src_offset_y = cy * step;
6808 g_em->dst_offset_x = cx * step;
6809 g_em->dst_offset_y = cy * step;
6812 else /* tile where movement ends */
6814 if (dx < 0 || dy < 0)
6816 g_em->dst_offset_x = cx * step;
6817 g_em->dst_offset_y = cy * step;
6821 g_em->src_offset_x = cx * step;
6822 g_em->src_offset_y = cy * step;
6826 g_em->width = TILEX - cx * step;
6827 g_em->height = TILEY - cy * step;
6830 /* create unique graphic identifier to decide if tile must be redrawn */
6831 /* bit 31 - 16 (16 bit): EM style graphic
6832 bit 15 - 12 ( 4 bit): EM style frame
6833 bit 11 - 6 ( 6 bit): graphic width
6834 bit 5 - 0 ( 6 bit): graphic height */
6835 g_em->unique_identifier =
6836 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6840 /* skip check for EMC elements not contained in original EMC artwork */
6841 if (element == EL_EMC_FAKE_ACID)
6844 if (g_em->bitmap != debug_bitmap ||
6845 g_em->src_x != debug_src_x ||
6846 g_em->src_y != debug_src_y ||
6847 g_em->src_offset_x != 0 ||
6848 g_em->src_offset_y != 0 ||
6849 g_em->dst_offset_x != 0 ||
6850 g_em->dst_offset_y != 0 ||
6851 g_em->width != TILEX ||
6852 g_em->height != TILEY)
6854 static int last_i = -1;
6862 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6863 i, element, element_info[element].token_name,
6864 element_action_info[effective_action].suffix, direction);
6866 if (element != effective_element)
6867 printf(" [%d ('%s')]",
6869 element_info[effective_element].token_name);
6873 if (g_em->bitmap != debug_bitmap)
6874 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6875 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6877 if (g_em->src_x != debug_src_x ||
6878 g_em->src_y != debug_src_y)
6879 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6880 j, (is_backside ? 'B' : 'F'),
6881 g_em->src_x, g_em->src_y,
6882 g_em->src_x / 32, g_em->src_y / 32,
6883 debug_src_x, debug_src_y,
6884 debug_src_x / 32, debug_src_y / 32);
6886 if (g_em->src_offset_x != 0 ||
6887 g_em->src_offset_y != 0 ||
6888 g_em->dst_offset_x != 0 ||
6889 g_em->dst_offset_y != 0)
6890 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6892 g_em->src_offset_x, g_em->src_offset_y,
6893 g_em->dst_offset_x, g_em->dst_offset_y);
6895 if (g_em->width != TILEX ||
6896 g_em->height != TILEY)
6897 printf(" %d (%d): size %d,%d should be %d,%d\n",
6899 g_em->width, g_em->height, TILEX, TILEY);
6901 num_em_gfx_errors++;
6908 for (i = 0; i < TILE_MAX; i++)
6910 for (j = 0; j < 8; j++)
6912 int element = object_mapping[i].element_rnd;
6913 int action = object_mapping[i].action;
6914 int direction = object_mapping[i].direction;
6915 boolean is_backside = object_mapping[i].is_backside;
6916 int graphic_action = el_act_dir2img(element, action, direction);
6917 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6919 if ((action == ACTION_SMASHED_BY_ROCK ||
6920 action == ACTION_SMASHED_BY_SPRING ||
6921 action == ACTION_EATING) &&
6922 graphic_action == graphic_default)
6924 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6925 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6926 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6927 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6930 /* no separate animation for "smashed by rock" -- use rock instead */
6931 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6932 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6934 g_em->bitmap = g_xx->bitmap;
6935 g_em->src_x = g_xx->src_x;
6936 g_em->src_y = g_xx->src_y;
6937 g_em->src_offset_x = g_xx->src_offset_x;
6938 g_em->src_offset_y = g_xx->src_offset_y;
6939 g_em->dst_offset_x = g_xx->dst_offset_x;
6940 g_em->dst_offset_y = g_xx->dst_offset_y;
6941 g_em->width = g_xx->width;
6942 g_em->height = g_xx->height;
6943 g_em->unique_identifier = g_xx->unique_identifier;
6946 g_em->preserve_background = TRUE;
6951 for (p = 0; p < MAX_PLAYERS; p++)
6953 for (i = 0; i < SPR_MAX; i++)
6955 int element = player_mapping[p][i].element_rnd;
6956 int action = player_mapping[p][i].action;
6957 int direction = player_mapping[p][i].direction;
6959 for (j = 0; j < 8; j++)
6961 int effective_element = element;
6962 int effective_action = action;
6963 int graphic = (direction == MV_NONE ?
6964 el_act2img(effective_element, effective_action) :
6965 el_act_dir2img(effective_element, effective_action,
6967 struct GraphicInfo *g = &graphic_info[graphic];
6968 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6974 Bitmap *debug_bitmap = g_em->bitmap;
6975 int debug_src_x = g_em->src_x;
6976 int debug_src_y = g_em->src_y;
6979 int frame = getAnimationFrame(g->anim_frames,
6982 g->anim_start_frame,
6985 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6987 g_em->bitmap = src_bitmap;
6988 g_em->src_x = src_x;
6989 g_em->src_y = src_y;
6990 g_em->src_offset_x = 0;
6991 g_em->src_offset_y = 0;
6992 g_em->dst_offset_x = 0;
6993 g_em->dst_offset_y = 0;
6994 g_em->width = TILEX;
6995 g_em->height = TILEY;
6999 /* skip check for EMC elements not contained in original EMC artwork */
7000 if (element == EL_PLAYER_3 ||
7001 element == EL_PLAYER_4)
7004 if (g_em->bitmap != debug_bitmap ||
7005 g_em->src_x != debug_src_x ||
7006 g_em->src_y != debug_src_y)
7008 static int last_i = -1;
7016 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7017 p, i, element, element_info[element].token_name,
7018 element_action_info[effective_action].suffix, direction);
7020 if (element != effective_element)
7021 printf(" [%d ('%s')]",
7023 element_info[effective_element].token_name);
7027 if (g_em->bitmap != debug_bitmap)
7028 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7029 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7031 if (g_em->src_x != debug_src_x ||
7032 g_em->src_y != debug_src_y)
7033 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7035 g_em->src_x, g_em->src_y,
7036 g_em->src_x / 32, g_em->src_y / 32,
7037 debug_src_x, debug_src_y,
7038 debug_src_x / 32, debug_src_y / 32);
7040 num_em_gfx_errors++;
7050 printf("::: [%d errors found]\n", num_em_gfx_errors);
7056 void PlayMenuSoundExt(int sound)
7058 if (sound == SND_UNDEFINED)
7061 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7062 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7065 if (IS_LOOP_SOUND(sound))
7066 PlaySoundLoop(sound);
7071 void PlayMenuSound()
7073 PlayMenuSoundExt(menu.sound[game_status]);
7076 void PlayMenuSoundStereo(int sound, int stereo_position)
7078 if (sound == SND_UNDEFINED)
7081 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7082 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7085 if (IS_LOOP_SOUND(sound))
7086 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7088 PlaySoundStereo(sound, stereo_position);
7091 void PlayMenuSoundIfLoopExt(int sound)
7093 if (sound == SND_UNDEFINED)
7096 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7097 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7100 if (IS_LOOP_SOUND(sound))
7101 PlaySoundLoop(sound);
7104 void PlayMenuSoundIfLoop()
7106 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7109 void PlayMenuMusicExt(int music)
7111 if (music == MUS_UNDEFINED)
7114 if (!setup.sound_music)
7120 void PlayMenuMusic()
7122 PlayMenuMusicExt(menu.music[game_status]);
7125 void PlaySoundActivating()
7128 PlaySound(SND_MENU_ITEM_ACTIVATING);
7132 void PlaySoundSelecting()
7135 PlaySound(SND_MENU_ITEM_SELECTING);
7139 void ToggleFullscreenIfNeeded()
7141 boolean change_fullscreen = (setup.fullscreen !=
7142 video.fullscreen_enabled);
7143 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7144 !strEqual(setup.fullscreen_mode,
7145 video.fullscreen_mode_current));
7147 if (!video.fullscreen_available)
7151 if (change_fullscreen || change_fullscreen_mode)
7153 if (setup.fullscreen != video.fullscreen_enabled ||
7154 setup.fullscreen_mode != video.fullscreen_mode_current)
7157 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7159 /* save backbuffer content which gets lost when toggling fullscreen mode */
7160 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7163 if (change_fullscreen_mode)
7165 if (setup.fullscreen && video.fullscreen_enabled)
7168 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7170 /* (this is now set in sdl.c) */
7172 video.fullscreen_mode_current = setup.fullscreen_mode;
7174 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7177 /* toggle fullscreen */
7178 ChangeVideoModeIfNeeded(setup.fullscreen);
7180 setup.fullscreen = video.fullscreen_enabled;
7182 /* restore backbuffer content from temporary backbuffer backup bitmap */
7183 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7185 FreeBitmap(tmp_backbuffer);
7188 /* update visible window/screen */
7189 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7191 redraw_mask = REDRAW_ALL;