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, "%04.1f fps%s", global.frames_per_second, info1);
432 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
434 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
440 for (x = 0; x < MAX_BUF_XSIZE; x++)
441 for (y = 0; y < MAX_BUF_YSIZE; y++)
444 redraw_mask = REDRAW_NONE;
447 static void FadeCrossSaveBackbuffer()
449 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
452 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
454 static int fade_type_skip = FADE_TYPE_NONE;
455 void (*draw_border_function)(void) = NULL;
456 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
457 int x, y, width, height;
458 int fade_delay, post_delay;
460 if (fade_type == FADE_TYPE_FADE_OUT)
462 if (fade_type_skip != FADE_TYPE_NONE)
465 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
468 /* skip all fade operations until specified fade operation */
469 if (fade_type & fade_type_skip)
470 fade_type_skip = FADE_TYPE_NONE;
475 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
477 FadeCrossSaveBackbuffer();
483 redraw_mask |= fade_mask;
485 if (fade_type == FADE_TYPE_SKIP)
488 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
491 fade_type_skip = fade_mode;
496 if (fade_type_skip != FADE_TYPE_NONE)
499 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
502 /* skip all fade operations until specified fade operation */
503 if (fade_type & fade_type_skip)
504 fade_type_skip = FADE_TYPE_NONE;
510 if (global.autoplay_leveldir)
512 // fading.fade_mode = FADE_MODE_NONE;
519 if (fading.fade_mode == FADE_MODE_NONE)
527 /* !!! what abount fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
530 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
534 if (fade_mask == REDRAW_NONE)
535 fade_mask = REDRAW_FIELD;
538 // if (fade_mask & REDRAW_FIELD)
539 if (fade_mask == REDRAW_FIELD)
544 height = FULL_SYSIZE;
546 fade_delay = fading.fade_delay;
547 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
549 if (border.draw_masked_when_fading)
550 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
552 DrawMaskedBorder_FIELD(); /* draw once */
554 else /* REDRAW_ALL */
561 fade_delay = fading.fade_delay;
562 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
566 if (!setup.fade_screens ||
568 fading.fade_mode == FADE_MODE_NONE)
570 if (!setup.fade_screens || fade_delay == 0)
573 if (fade_mode == FADE_MODE_FADE_OUT)
577 if (fade_mode == FADE_MODE_FADE_OUT &&
578 fading.fade_mode != FADE_MODE_NONE)
579 ClearRectangle(backbuffer, x, y, width, height);
583 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
584 redraw_mask = REDRAW_NONE;
592 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
593 draw_border_function);
595 redraw_mask &= ~fade_mask;
598 void FadeIn(int fade_mask)
600 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
601 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
603 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
606 void FadeOut(int fade_mask)
608 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
609 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
611 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
613 global.border_status = game_status;
616 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
618 static struct TitleFadingInfo fading_leave_stored;
621 fading_leave_stored = fading_leave;
623 fading = fading_leave_stored;
626 void FadeSetEnterMenu()
628 fading = menu.enter_menu;
631 printf("::: storing enter_menu\n");
634 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
637 void FadeSetLeaveMenu()
639 fading = menu.leave_menu;
642 printf("::: storing leave_menu\n");
645 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
648 void FadeSetEnterScreen()
650 fading = menu.enter_screen[game_status];
653 printf("::: storing leave_screen[%d]\n", game_status);
656 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
659 void FadeSetNextScreen()
661 fading = menu.next_screen;
664 printf("::: storing next_screen\n");
667 // (do not overwrite fade mode set by FadeSetEnterScreen)
668 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
671 void FadeSetLeaveScreen()
674 printf("::: recalling last stored value\n");
677 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
680 void FadeSetFromType(int type)
682 if (type & TYPE_ENTER_SCREEN)
683 FadeSetEnterScreen();
684 else if (type & TYPE_ENTER)
686 else if (type & TYPE_LEAVE)
690 void FadeSetDisabled()
692 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
694 fading = fading_none;
697 void FadeSkipNextFadeIn()
699 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
702 void FadeSkipNextFadeOut()
704 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
707 void SetWindowBackgroundImageIfDefined(int graphic)
709 if (graphic_info[graphic].bitmap)
710 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
713 void SetMainBackgroundImageIfDefined(int graphic)
715 if (graphic_info[graphic].bitmap)
716 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
719 void SetDoorBackgroundImageIfDefined(int graphic)
721 if (graphic_info[graphic].bitmap)
722 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
725 void SetWindowBackgroundImage(int graphic)
727 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
728 graphic_info[graphic].bitmap ?
729 graphic_info[graphic].bitmap :
730 graphic_info[IMG_BACKGROUND].bitmap);
733 void SetMainBackgroundImage(int graphic)
735 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
736 graphic_info[graphic].bitmap ?
737 graphic_info[graphic].bitmap :
738 graphic_info[IMG_BACKGROUND].bitmap);
741 void SetDoorBackgroundImage(int graphic)
743 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
744 graphic_info[graphic].bitmap ?
745 graphic_info[graphic].bitmap :
746 graphic_info[IMG_BACKGROUND].bitmap);
749 void SetPanelBackground()
751 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
752 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
754 SetDoorBackgroundBitmap(bitmap_db_panel);
757 void DrawBackground(int x, int y, int width, int height)
759 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
760 /* (when entering hall of fame after playing) */
762 ClearRectangleOnBackground(drawto, x, y, width, height);
764 ClearRectangleOnBackground(backbuffer, x, y, width, height);
767 redraw_mask |= REDRAW_FIELD;
770 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
772 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
774 if (font->bitmap == NULL)
777 DrawBackground(x, y, width, height);
780 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
782 struct GraphicInfo *g = &graphic_info[graphic];
784 if (g->bitmap == NULL)
787 DrawBackground(x, y, width, height);
792 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
793 /* (when entering hall of fame after playing) */
794 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
796 /* !!! maybe this should be done before clearing the background !!! */
797 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
799 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
800 SetDrawtoField(DRAW_BUFFERED);
803 SetDrawtoField(DRAW_BACKBUFFER);
806 void MarkTileDirty(int x, int y)
808 int xx = redraw_x1 + x;
809 int yy = redraw_y1 + y;
814 redraw[xx][yy] = TRUE;
815 redraw_mask |= REDRAW_TILES;
818 void SetBorderElement()
822 BorderElement = EL_EMPTY;
824 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
826 for (x = 0; x < lev_fieldx; x++)
828 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
829 BorderElement = EL_STEELWALL;
831 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
837 void FloodFillLevel(int from_x, int from_y, int fill_element,
838 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
839 int max_fieldx, int max_fieldy)
843 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
844 static int safety = 0;
846 /* check if starting field still has the desired content */
847 if (field[from_x][from_y] == fill_element)
852 if (safety > max_fieldx * max_fieldy)
853 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
855 old_element = field[from_x][from_y];
856 field[from_x][from_y] = fill_element;
858 for (i = 0; i < 4; i++)
860 x = from_x + check[i][0];
861 y = from_y + check[i][1];
863 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
864 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
870 void SetRandomAnimationValue(int x, int y)
872 gfx.anim_random_frame = GfxRandom[x][y];
875 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
877 /* animation synchronized with global frame counter, not move position */
878 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
879 sync_frame = FrameCounter;
881 return getAnimationFrame(graphic_info[graphic].anim_frames,
882 graphic_info[graphic].anim_delay,
883 graphic_info[graphic].anim_mode,
884 graphic_info[graphic].anim_start_frame,
888 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
889 Bitmap **bitmap, int *x, int *y)
893 int width_mult, width_div;
894 int height_mult, height_div;
898 { 15, 16, 2, 3 }, /* 1 x 1 */
899 { 7, 8, 2, 3 }, /* 2 x 2 */
900 { 3, 4, 2, 3 }, /* 4 x 4 */
901 { 1, 2, 2, 3 }, /* 8 x 8 */
902 { 0, 1, 2, 3 }, /* 16 x 16 */
903 { 0, 1, 0, 1 }, /* 32 x 32 */
905 struct GraphicInfo *g = &graphic_info[graphic];
906 Bitmap *src_bitmap = g->bitmap;
907 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
908 int offset_calc_pos = log_2(tilesize);
909 int width_mult = offset_calc[offset_calc_pos].width_mult;
910 int width_div = offset_calc[offset_calc_pos].width_div;
911 int height_mult = offset_calc[offset_calc_pos].height_mult;
912 int height_div = offset_calc[offset_calc_pos].height_div;
913 int startx = src_bitmap->width * width_mult / width_div;
914 int starty = src_bitmap->height * height_mult / height_div;
915 int src_x = g->src_x * tilesize / TILESIZE;
916 int src_y = g->src_y * tilesize / TILESIZE;
917 int width = g->width * tilesize / TILESIZE;
918 int height = g->height * tilesize / TILESIZE;
919 int offset_x = g->offset_x * tilesize / TILESIZE;
920 int offset_y = g->offset_y * tilesize / TILESIZE;
922 if (g->offset_y == 0) /* frames are ordered horizontally */
924 int max_width = g->anim_frames_per_line * width;
925 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
927 src_x = pos % max_width;
928 src_y = src_y % height + pos / max_width * height;
930 else if (g->offset_x == 0) /* frames are ordered vertically */
932 int max_height = g->anim_frames_per_line * height;
933 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
935 src_x = src_x % width + pos / max_height * width;
936 src_y = pos % max_height;
938 else /* frames are ordered diagonally */
940 src_x = src_x + frame * offset_x;
941 src_y = src_y + frame * offset_y;
944 *bitmap = src_bitmap;
949 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
952 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
954 struct GraphicInfo *g = &graphic_info[graphic];
956 int mini_starty = g->bitmap->height * 2 / 3;
959 *x = mini_startx + g->src_x / 2;
960 *y = mini_starty + g->src_y / 2;
964 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
965 int *x, int *y, boolean get_backside)
967 struct GraphicInfo *g = &graphic_info[graphic];
968 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
969 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
973 if (g->offset_y == 0) /* frames are ordered horizontally */
975 int max_width = g->anim_frames_per_line * g->width;
976 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
978 *x = pos % max_width;
979 *y = src_y % g->height + pos / max_width * g->height;
981 else if (g->offset_x == 0) /* frames are ordered vertically */
983 int max_height = g->anim_frames_per_line * g->height;
984 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
986 *x = src_x % g->width + pos / max_height * g->width;
987 *y = pos % max_height;
989 else /* frames are ordered diagonally */
991 *x = src_x + frame * g->offset_x;
992 *y = src_y + frame * g->offset_y;
996 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
998 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1001 void DrawGraphic(int x, int y, int graphic, int frame)
1004 if (!IN_SCR_FIELD(x, y))
1006 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1007 printf("DrawGraphic(): This should never happen!\n");
1012 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1013 MarkTileDirty(x, y);
1016 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1022 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1023 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1026 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1029 if (!IN_SCR_FIELD(x, y))
1031 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1032 printf("DrawGraphicThruMask(): This should never happen!\n");
1037 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1039 MarkTileDirty(x, y);
1042 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1048 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1050 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1051 dst_x - src_x, dst_y - src_y);
1052 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1055 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1057 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1059 MarkTileDirty(x / tilesize, y / tilesize);
1062 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1068 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1069 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1072 void DrawMiniGraphic(int x, int y, int graphic)
1074 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1075 MarkTileDirty(x / 2, y / 2);
1078 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1083 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1084 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1087 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1088 int graphic, int frame,
1089 int cut_mode, int mask_mode)
1094 int width = TILEX, height = TILEY;
1097 if (dx || dy) /* shifted graphic */
1099 if (x < BX1) /* object enters playfield from the left */
1106 else if (x > BX2) /* object enters playfield from the right */
1112 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1118 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1120 else if (dx) /* general horizontal movement */
1121 MarkTileDirty(x + SIGN(dx), y);
1123 if (y < BY1) /* object enters playfield from the top */
1125 if (cut_mode==CUT_BELOW) /* object completely above top border */
1133 else if (y > BY2) /* object enters playfield from the bottom */
1139 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1145 else if (dy > 0 && cut_mode == CUT_ABOVE)
1147 if (y == BY2) /* object completely above bottom border */
1153 MarkTileDirty(x, y + 1);
1154 } /* object leaves playfield to the bottom */
1155 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1157 else if (dy) /* general vertical movement */
1158 MarkTileDirty(x, y + SIGN(dy));
1162 if (!IN_SCR_FIELD(x, y))
1164 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1165 printf("DrawGraphicShifted(): This should never happen!\n");
1170 if (width > 0 && height > 0)
1172 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1177 dst_x = FX + x * TILEX + dx;
1178 dst_y = FY + y * TILEY + dy;
1180 if (mask_mode == USE_MASKING)
1182 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1183 dst_x - src_x, dst_y - src_y);
1184 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1188 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1191 MarkTileDirty(x, y);
1195 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1196 int graphic, int frame,
1197 int cut_mode, int mask_mode)
1202 int width = TILEX, height = TILEY;
1205 int x2 = x + SIGN(dx);
1206 int y2 = y + SIGN(dy);
1207 int anim_frames = graphic_info[graphic].anim_frames;
1208 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1209 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1210 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1212 /* re-calculate animation frame for two-tile movement animation */
1213 frame = getGraphicAnimationFrame(graphic, sync_frame);
1215 /* check if movement start graphic inside screen area and should be drawn */
1216 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1218 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1220 dst_x = FX + x1 * TILEX;
1221 dst_y = FY + y1 * TILEY;
1223 if (mask_mode == USE_MASKING)
1225 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1226 dst_x - src_x, dst_y - src_y);
1227 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1231 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1234 MarkTileDirty(x1, y1);
1237 /* check if movement end graphic inside screen area and should be drawn */
1238 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1240 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1242 dst_x = FX + x2 * TILEX;
1243 dst_y = FY + y2 * TILEY;
1245 if (mask_mode == USE_MASKING)
1247 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1248 dst_x - src_x, dst_y - src_y);
1249 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1253 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1256 MarkTileDirty(x2, y2);
1260 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1261 int graphic, int frame,
1262 int cut_mode, int mask_mode)
1266 DrawGraphic(x, y, graphic, frame);
1271 if (graphic_info[graphic].double_movement) /* EM style movement images */
1272 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1274 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1277 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1278 int frame, int cut_mode)
1280 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1283 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1284 int cut_mode, int mask_mode)
1286 int lx = LEVELX(x), ly = LEVELY(y);
1290 if (IN_LEV_FIELD(lx, ly))
1292 SetRandomAnimationValue(lx, ly);
1294 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1295 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1297 /* do not use double (EM style) movement graphic when not moving */
1298 if (graphic_info[graphic].double_movement && !dx && !dy)
1300 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1301 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1304 else /* border element */
1306 graphic = el2img(element);
1307 frame = getGraphicAnimationFrame(graphic, -1);
1310 if (element == EL_EXPANDABLE_WALL)
1312 boolean left_stopped = FALSE, right_stopped = FALSE;
1314 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1315 left_stopped = TRUE;
1316 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1317 right_stopped = TRUE;
1319 if (left_stopped && right_stopped)
1321 else if (left_stopped)
1323 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1324 frame = graphic_info[graphic].anim_frames - 1;
1326 else if (right_stopped)
1328 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1329 frame = graphic_info[graphic].anim_frames - 1;
1334 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1335 else if (mask_mode == USE_MASKING)
1336 DrawGraphicThruMask(x, y, graphic, frame);
1338 DrawGraphic(x, y, graphic, frame);
1341 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1342 int cut_mode, int mask_mode)
1344 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1345 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1346 cut_mode, mask_mode);
1349 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1352 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1355 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1358 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1361 void DrawLevelElementThruMask(int x, int y, int element)
1363 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1366 void DrawLevelFieldThruMask(int x, int y)
1368 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1371 /* !!! implementation of quicksand is totally broken !!! */
1372 #define IS_CRUMBLED_TILE(x, y, e) \
1373 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1374 !IS_MOVING(x, y) || \
1375 (e) == EL_QUICKSAND_EMPTYING || \
1376 (e) == EL_QUICKSAND_FAST_EMPTYING))
1378 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1382 int sx = SCREENX(x), sy = SCREENY(y);
1384 int width, height, cx, cy, i;
1385 int crumbled_border_size = graphic_info[graphic].border_size;
1386 static int xy[4][2] =
1394 if (!IN_LEV_FIELD(x, y))
1397 element = TILE_GFX_ELEMENT(x, y);
1399 /* crumble field itself */
1401 if (IS_CRUMBLED_TILE(x, y, element))
1403 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1406 if (!IN_SCR_FIELD(sx, sy))
1409 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1411 for (i = 0; i < 4; i++)
1413 int xx = x + xy[i][0];
1414 int yy = y + xy[i][1];
1416 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1419 /* check if neighbour field is of same type */
1421 if (IS_CRUMBLED_TILE(xx, yy, element))
1424 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1428 if (i == 1 || i == 2)
1430 width = crumbled_border_size;
1432 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1438 height = crumbled_border_size;
1440 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1443 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1444 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1447 MarkTileDirty(sx, sy);
1449 else /* crumble neighbour fields */
1451 for (i = 0; i < 4; i++)
1453 int xx = x + xy[i][0];
1454 int yy = y + xy[i][1];
1455 int sxx = sx + xy[i][0];
1456 int syy = sy + xy[i][1];
1459 if (!IN_LEV_FIELD(xx, yy) ||
1460 !IN_SCR_FIELD(sxx, syy))
1463 if (!IN_LEV_FIELD(xx, yy) ||
1464 !IN_SCR_FIELD(sxx, syy) ||
1469 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1472 element = TILE_GFX_ELEMENT(xx, yy);
1475 if (!IS_CRUMBLED_TILE(xx, yy, element))
1478 if (!GFX_CRUMBLED(element))
1482 graphic = el_act2crm(element, ACTION_DEFAULT);
1483 crumbled_border_size = graphic_info[graphic].border_size;
1485 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1487 if (i == 1 || i == 2)
1489 width = crumbled_border_size;
1491 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1497 height = crumbled_border_size;
1499 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1502 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1503 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1505 MarkTileDirty(sxx, syy);
1510 void DrawLevelFieldCrumbledSand(int x, int y)
1514 if (!IN_LEV_FIELD(x, y))
1518 /* !!! CHECK THIS !!! */
1521 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1522 GFX_CRUMBLED(GfxElement[x][y]))
1525 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1526 GfxElement[x][y] != EL_UNDEFINED &&
1527 GFX_CRUMBLED(GfxElement[x][y]))
1529 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1536 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1538 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1541 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1544 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1547 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1548 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1549 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1550 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1551 int sx = SCREENX(x), sy = SCREENY(y);
1553 DrawGraphic(sx, sy, graphic1, frame1);
1554 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1557 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1559 int sx = SCREENX(x), sy = SCREENY(y);
1560 static int xy[4][2] =
1569 for (i = 0; i < 4; i++)
1571 int xx = x + xy[i][0];
1572 int yy = y + xy[i][1];
1573 int sxx = sx + xy[i][0];
1574 int syy = sy + xy[i][1];
1576 if (!IN_LEV_FIELD(xx, yy) ||
1577 !IN_SCR_FIELD(sxx, syy) ||
1578 !GFX_CRUMBLED(Feld[xx][yy]) ||
1582 DrawLevelField(xx, yy);
1586 static int getBorderElement(int x, int y)
1590 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1591 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1592 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1593 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1594 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1595 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1596 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1598 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1599 int steel_position = (x == -1 && y == -1 ? 0 :
1600 x == lev_fieldx && y == -1 ? 1 :
1601 x == -1 && y == lev_fieldy ? 2 :
1602 x == lev_fieldx && y == lev_fieldy ? 3 :
1603 x == -1 || x == lev_fieldx ? 4 :
1604 y == -1 || y == lev_fieldy ? 5 : 6);
1606 return border[steel_position][steel_type];
1609 void DrawScreenElement(int x, int y, int element)
1611 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1612 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1615 void DrawLevelElement(int x, int y, int element)
1617 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1618 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1621 void DrawScreenField(int x, int y)
1623 int lx = LEVELX(x), ly = LEVELY(y);
1624 int element, content;
1626 if (!IN_LEV_FIELD(lx, ly))
1628 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1631 element = getBorderElement(lx, ly);
1633 DrawScreenElement(x, y, element);
1638 element = Feld[lx][ly];
1639 content = Store[lx][ly];
1641 if (IS_MOVING(lx, ly))
1643 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1644 boolean cut_mode = NO_CUTTING;
1646 if (element == EL_QUICKSAND_EMPTYING ||
1647 element == EL_QUICKSAND_FAST_EMPTYING ||
1648 element == EL_MAGIC_WALL_EMPTYING ||
1649 element == EL_BD_MAGIC_WALL_EMPTYING ||
1650 element == EL_DC_MAGIC_WALL_EMPTYING ||
1651 element == EL_AMOEBA_DROPPING)
1652 cut_mode = CUT_ABOVE;
1653 else if (element == EL_QUICKSAND_FILLING ||
1654 element == EL_QUICKSAND_FAST_FILLING ||
1655 element == EL_MAGIC_WALL_FILLING ||
1656 element == EL_BD_MAGIC_WALL_FILLING ||
1657 element == EL_DC_MAGIC_WALL_FILLING)
1658 cut_mode = CUT_BELOW;
1661 if (lx == 9 && ly == 1)
1662 printf("::: %s [%d] [%d, %d] [%d]\n",
1663 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1664 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1665 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1666 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1667 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1670 if (cut_mode == CUT_ABOVE)
1672 DrawScreenElement(x, y, element);
1674 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1677 DrawScreenElement(x, y, EL_EMPTY);
1680 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1681 else if (cut_mode == NO_CUTTING)
1682 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1685 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1688 if (cut_mode == CUT_BELOW &&
1689 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1690 DrawLevelElement(lx, ly + 1, element);
1694 if (content == EL_ACID)
1696 int dir = MovDir[lx][ly];
1697 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1698 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1700 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1703 else if (IS_BLOCKED(lx, ly))
1708 boolean cut_mode = NO_CUTTING;
1709 int element_old, content_old;
1711 Blocked2Moving(lx, ly, &oldx, &oldy);
1714 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1715 MovDir[oldx][oldy] == MV_RIGHT);
1717 element_old = Feld[oldx][oldy];
1718 content_old = Store[oldx][oldy];
1720 if (element_old == EL_QUICKSAND_EMPTYING ||
1721 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1722 element_old == EL_MAGIC_WALL_EMPTYING ||
1723 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1724 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1725 element_old == EL_AMOEBA_DROPPING)
1726 cut_mode = CUT_ABOVE;
1728 DrawScreenElement(x, y, EL_EMPTY);
1731 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1733 else if (cut_mode == NO_CUTTING)
1734 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1737 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1740 else if (IS_DRAWABLE(element))
1741 DrawScreenElement(x, y, element);
1743 DrawScreenElement(x, y, EL_EMPTY);
1746 void DrawLevelField(int x, int y)
1748 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1749 DrawScreenField(SCREENX(x), SCREENY(y));
1750 else if (IS_MOVING(x, y))
1754 Moving2Blocked(x, y, &newx, &newy);
1755 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1756 DrawScreenField(SCREENX(newx), SCREENY(newy));
1758 else if (IS_BLOCKED(x, y))
1762 Blocked2Moving(x, y, &oldx, &oldy);
1763 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1764 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1768 void DrawMiniElement(int x, int y, int element)
1772 graphic = el2edimg(element);
1773 DrawMiniGraphic(x, y, graphic);
1776 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1778 int x = sx + scroll_x, y = sy + scroll_y;
1780 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1781 DrawMiniElement(sx, sy, EL_EMPTY);
1782 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1783 DrawMiniElement(sx, sy, Feld[x][y]);
1785 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1788 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1789 int x, int y, int xsize, int ysize, int font_nr)
1791 int font_width = getFontWidth(font_nr);
1792 int font_height = getFontHeight(font_nr);
1793 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1796 int dst_x = SX + startx + x * font_width;
1797 int dst_y = SY + starty + y * font_height;
1798 int width = graphic_info[graphic].width;
1799 int height = graphic_info[graphic].height;
1800 int inner_width = MAX(width - 2 * font_width, font_width);
1801 int inner_height = MAX(height - 2 * font_height, font_height);
1802 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1803 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1804 boolean draw_masked = graphic_info[graphic].draw_masked;
1806 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1808 if (src_bitmap == NULL || width < font_width || height < font_height)
1810 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1814 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1815 inner_sx + (x - 1) * font_width % inner_width);
1816 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1817 inner_sy + (y - 1) * font_height % inner_height);
1821 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1822 dst_x - src_x, dst_y - src_y);
1823 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1827 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1831 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1833 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1834 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1835 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1836 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1837 boolean no_delay = (tape.warp_forward);
1838 unsigned long anim_delay = 0;
1839 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1840 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1841 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1842 int font_width = getFontWidth(font_nr);
1843 int font_height = getFontHeight(font_nr);
1844 int max_xsize = level.envelope[envelope_nr].xsize;
1845 int max_ysize = level.envelope[envelope_nr].ysize;
1846 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1847 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1848 int xend = max_xsize;
1849 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1850 int xstep = (xstart < xend ? 1 : 0);
1851 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1854 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1856 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1857 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1858 int sx = (SXSIZE - xsize * font_width) / 2;
1859 int sy = (SYSIZE - ysize * font_height) / 2;
1862 SetDrawtoField(DRAW_BUFFERED);
1864 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1866 SetDrawtoField(DRAW_BACKBUFFER);
1868 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1869 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1872 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1873 level.envelope[envelope_nr].text, font_nr, max_xsize,
1874 xsize - 2, ysize - 2, mask_mode,
1875 level.envelope[envelope_nr].autowrap,
1876 level.envelope[envelope_nr].centered, FALSE);
1878 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1879 level.envelope[envelope_nr].text, font_nr, max_xsize,
1880 xsize - 2, ysize - 2, mask_mode);
1883 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1886 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1890 void ShowEnvelope(int envelope_nr)
1892 int element = EL_ENVELOPE_1 + envelope_nr;
1893 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1894 int sound_opening = element_info[element].sound[ACTION_OPENING];
1895 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1896 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1897 boolean no_delay = (tape.warp_forward);
1898 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1899 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1900 int anim_mode = graphic_info[graphic].anim_mode;
1901 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1902 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1904 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1906 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1908 if (anim_mode == ANIM_DEFAULT)
1909 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1911 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1914 Delay(wait_delay_value);
1916 WaitForEventToContinue();
1918 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1920 if (anim_mode != ANIM_NONE)
1921 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1923 if (anim_mode == ANIM_DEFAULT)
1924 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1926 game.envelope_active = FALSE;
1928 SetDrawtoField(DRAW_BUFFERED);
1930 redraw_mask |= REDRAW_FIELD;
1934 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1938 int graphic = el2preimg(element);
1940 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
1941 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1949 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
1950 SetDrawBackgroundMask(REDRAW_FIELD);
1952 SetDrawBackgroundMask(REDRAW_NONE);
1957 for (x = BX1; x <= BX2; x++)
1958 for (y = BY1; y <= BY2; y++)
1959 DrawScreenField(x, y);
1961 redraw_mask |= REDRAW_FIELD;
1964 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1968 for (x = 0; x < size_x; x++)
1969 for (y = 0; y < size_y; y++)
1970 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1972 redraw_mask |= REDRAW_FIELD;
1975 static void DrawPreviewLevelExt(int from_x, int from_y)
1977 boolean show_level_border = (BorderElement != EL_EMPTY);
1978 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1979 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1980 int tile_size = preview.tile_size;
1981 int preview_width = preview.xsize * tile_size;
1982 int preview_height = preview.ysize * tile_size;
1983 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1984 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1985 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1986 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1989 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1991 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1992 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1994 for (x = 0; x < real_preview_xsize; x++)
1996 for (y = 0; y < real_preview_ysize; y++)
1998 int lx = from_x + x + (show_level_border ? -1 : 0);
1999 int ly = from_y + y + (show_level_border ? -1 : 0);
2000 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2001 getBorderElement(lx, ly));
2003 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2004 element, tile_size);
2008 redraw_mask |= REDRAW_MICROLEVEL;
2011 #define MICROLABEL_EMPTY 0
2012 #define MICROLABEL_LEVEL_NAME 1
2013 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2014 #define MICROLABEL_LEVEL_AUTHOR 3
2015 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2016 #define MICROLABEL_IMPORTED_FROM 5
2017 #define MICROLABEL_IMPORTED_BY_HEAD 6
2018 #define MICROLABEL_IMPORTED_BY 7
2020 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2022 int max_text_width = SXSIZE;
2023 int font_width = getFontWidth(font_nr);
2025 if (pos->align == ALIGN_CENTER)
2026 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2027 else if (pos->align == ALIGN_RIGHT)
2028 max_text_width = pos->x;
2030 max_text_width = SXSIZE - pos->x;
2032 return max_text_width / font_width;
2035 static void DrawPreviewLevelLabelExt(int mode)
2037 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2038 char label_text[MAX_OUTPUT_LINESIZE + 1];
2039 int max_len_label_text;
2041 int font_nr = pos->font;
2044 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2045 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2046 mode == MICROLABEL_IMPORTED_BY_HEAD)
2047 font_nr = pos->font_alt;
2049 int font_nr = FONT_TEXT_2;
2052 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2053 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2054 mode == MICROLABEL_IMPORTED_BY_HEAD)
2055 font_nr = FONT_TEXT_3;
2059 max_len_label_text = getMaxTextLength(pos, font_nr);
2061 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2065 if (pos->size != -1)
2066 max_len_label_text = pos->size;
2069 for (i = 0; i < max_len_label_text; i++)
2070 label_text[i] = ' ';
2071 label_text[max_len_label_text] = '\0';
2073 if (strlen(label_text) > 0)
2076 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2078 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2079 int lypos = MICROLABEL2_YPOS;
2081 DrawText(lxpos, lypos, label_text, font_nr);
2086 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2087 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2088 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2089 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2090 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2091 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2092 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2093 max_len_label_text);
2094 label_text[max_len_label_text] = '\0';
2096 if (strlen(label_text) > 0)
2099 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2101 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2102 int lypos = MICROLABEL2_YPOS;
2104 DrawText(lxpos, lypos, label_text, font_nr);
2108 redraw_mask |= REDRAW_MICROLEVEL;
2111 void DrawPreviewLevel(boolean restart)
2113 static unsigned long scroll_delay = 0;
2114 static unsigned long label_delay = 0;
2115 static int from_x, from_y, scroll_direction;
2116 static int label_state, label_counter;
2117 unsigned long scroll_delay_value = preview.step_delay;
2118 boolean show_level_border = (BorderElement != EL_EMPTY);
2119 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2120 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2121 int last_game_status = game_status; /* save current game status */
2124 /* force PREVIEW font on preview level */
2125 game_status = GAME_MODE_PSEUDO_PREVIEW;
2133 if (preview.anim_mode == ANIM_CENTERED)
2135 if (level_xsize > preview.xsize)
2136 from_x = (level_xsize - preview.xsize) / 2;
2137 if (level_ysize > preview.ysize)
2138 from_y = (level_ysize - preview.ysize) / 2;
2141 from_x += preview.xoffset;
2142 from_y += preview.yoffset;
2144 scroll_direction = MV_RIGHT;
2148 DrawPreviewLevelExt(from_x, from_y);
2149 DrawPreviewLevelLabelExt(label_state);
2151 /* initialize delay counters */
2152 DelayReached(&scroll_delay, 0);
2153 DelayReached(&label_delay, 0);
2155 if (leveldir_current->name)
2157 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2158 char label_text[MAX_OUTPUT_LINESIZE + 1];
2160 int font_nr = pos->font;
2162 int font_nr = FONT_TEXT_1;
2165 int max_len_label_text = getMaxTextLength(pos, font_nr);
2167 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2175 if (pos->size != -1)
2176 max_len_label_text = pos->size;
2179 strncpy(label_text, leveldir_current->name, max_len_label_text);
2180 label_text[max_len_label_text] = '\0';
2183 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2185 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2186 lypos = SY + MICROLABEL1_YPOS;
2188 DrawText(lxpos, lypos, label_text, font_nr);
2192 game_status = last_game_status; /* restore current game status */
2197 /* scroll preview level, if needed */
2198 if (preview.anim_mode != ANIM_NONE &&
2199 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2200 DelayReached(&scroll_delay, scroll_delay_value))
2202 switch (scroll_direction)
2207 from_x -= preview.step_offset;
2208 from_x = (from_x < 0 ? 0 : from_x);
2211 scroll_direction = MV_UP;
2215 if (from_x < level_xsize - preview.xsize)
2217 from_x += preview.step_offset;
2218 from_x = (from_x > level_xsize - preview.xsize ?
2219 level_xsize - preview.xsize : from_x);
2222 scroll_direction = MV_DOWN;
2228 from_y -= preview.step_offset;
2229 from_y = (from_y < 0 ? 0 : from_y);
2232 scroll_direction = MV_RIGHT;
2236 if (from_y < level_ysize - preview.ysize)
2238 from_y += preview.step_offset;
2239 from_y = (from_y > level_ysize - preview.ysize ?
2240 level_ysize - preview.ysize : from_y);
2243 scroll_direction = MV_LEFT;
2250 DrawPreviewLevelExt(from_x, from_y);
2253 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2254 /* redraw micro level label, if needed */
2255 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2256 !strEqual(level.author, ANONYMOUS_NAME) &&
2257 !strEqual(level.author, leveldir_current->name) &&
2258 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2260 int max_label_counter = 23;
2262 if (leveldir_current->imported_from != NULL &&
2263 strlen(leveldir_current->imported_from) > 0)
2264 max_label_counter += 14;
2265 if (leveldir_current->imported_by != NULL &&
2266 strlen(leveldir_current->imported_by) > 0)
2267 max_label_counter += 14;
2269 label_counter = (label_counter + 1) % max_label_counter;
2270 label_state = (label_counter >= 0 && label_counter <= 7 ?
2271 MICROLABEL_LEVEL_NAME :
2272 label_counter >= 9 && label_counter <= 12 ?
2273 MICROLABEL_LEVEL_AUTHOR_HEAD :
2274 label_counter >= 14 && label_counter <= 21 ?
2275 MICROLABEL_LEVEL_AUTHOR :
2276 label_counter >= 23 && label_counter <= 26 ?
2277 MICROLABEL_IMPORTED_FROM_HEAD :
2278 label_counter >= 28 && label_counter <= 35 ?
2279 MICROLABEL_IMPORTED_FROM :
2280 label_counter >= 37 && label_counter <= 40 ?
2281 MICROLABEL_IMPORTED_BY_HEAD :
2282 label_counter >= 42 && label_counter <= 49 ?
2283 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2285 if (leveldir_current->imported_from == NULL &&
2286 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2287 label_state == MICROLABEL_IMPORTED_FROM))
2288 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2289 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2291 DrawPreviewLevelLabelExt(label_state);
2294 game_status = last_game_status; /* restore current game status */
2297 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2298 int graphic, int sync_frame, int mask_mode)
2300 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2302 if (mask_mode == USE_MASKING)
2303 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2305 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2308 inline void DrawGraphicAnimation(int x, int y, int graphic)
2310 int lx = LEVELX(x), ly = LEVELY(y);
2312 if (!IN_SCR_FIELD(x, y))
2315 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2316 graphic, GfxFrame[lx][ly], NO_MASKING);
2317 MarkTileDirty(x, y);
2320 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2322 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2325 void DrawLevelElementAnimation(int x, int y, int element)
2327 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2329 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2332 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2334 int sx = SCREENX(x), sy = SCREENY(y);
2336 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2339 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2342 DrawGraphicAnimation(sx, sy, graphic);
2345 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2346 DrawLevelFieldCrumbledSand(x, y);
2348 if (GFX_CRUMBLED(Feld[x][y]))
2349 DrawLevelFieldCrumbledSand(x, y);
2353 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2355 int sx = SCREENX(x), sy = SCREENY(y);
2358 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2361 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2363 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2366 DrawGraphicAnimation(sx, sy, graphic);
2368 if (GFX_CRUMBLED(element))
2369 DrawLevelFieldCrumbledSand(x, y);
2372 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2374 if (player->use_murphy)
2376 /* this works only because currently only one player can be "murphy" ... */
2377 static int last_horizontal_dir = MV_LEFT;
2378 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2380 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2381 last_horizontal_dir = move_dir;
2383 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2385 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2387 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2393 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2396 static boolean equalGraphics(int graphic1, int graphic2)
2398 struct GraphicInfo *g1 = &graphic_info[graphic1];
2399 struct GraphicInfo *g2 = &graphic_info[graphic2];
2401 return (g1->bitmap == g2->bitmap &&
2402 g1->src_x == g2->src_x &&
2403 g1->src_y == g2->src_y &&
2404 g1->anim_frames == g2->anim_frames &&
2405 g1->anim_delay == g2->anim_delay &&
2406 g1->anim_mode == g2->anim_mode);
2409 void DrawAllPlayers()
2413 for (i = 0; i < MAX_PLAYERS; i++)
2414 if (stored_player[i].active)
2415 DrawPlayer(&stored_player[i]);
2418 void DrawPlayerField(int x, int y)
2420 if (!IS_PLAYER(x, y))
2423 DrawPlayer(PLAYERINFO(x, y));
2426 void DrawPlayer(struct PlayerInfo *player)
2428 int jx = player->jx;
2429 int jy = player->jy;
2430 int move_dir = player->MovDir;
2431 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2432 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2433 int last_jx = (player->is_moving ? jx - dx : jx);
2434 int last_jy = (player->is_moving ? jy - dy : jy);
2435 int next_jx = jx + dx;
2436 int next_jy = jy + dy;
2437 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2438 boolean player_is_opaque = FALSE;
2439 int sx = SCREENX(jx), sy = SCREENY(jy);
2440 int sxx = 0, syy = 0;
2441 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2443 int action = ACTION_DEFAULT;
2444 int last_player_graphic = getPlayerGraphic(player, move_dir);
2445 int last_player_frame = player->Frame;
2448 /* GfxElement[][] is set to the element the player is digging or collecting;
2449 remove also for off-screen player if the player is not moving anymore */
2450 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2451 GfxElement[jx][jy] = EL_UNDEFINED;
2453 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2457 if (!IN_LEV_FIELD(jx, jy))
2459 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2460 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2461 printf("DrawPlayerField(): This should never happen!\n");
2466 if (element == EL_EXPLOSION)
2469 action = (player->is_pushing ? ACTION_PUSHING :
2470 player->is_digging ? ACTION_DIGGING :
2471 player->is_collecting ? ACTION_COLLECTING :
2472 player->is_moving ? ACTION_MOVING :
2473 player->is_snapping ? ACTION_SNAPPING :
2474 player->is_dropping ? ACTION_DROPPING :
2475 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2477 if (player->is_waiting)
2478 move_dir = player->dir_waiting;
2480 InitPlayerGfxAnimation(player, action, move_dir);
2482 /* ----------------------------------------------------------------------- */
2483 /* draw things in the field the player is leaving, if needed */
2484 /* ----------------------------------------------------------------------- */
2486 if (player->is_moving)
2488 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2490 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2492 if (last_element == EL_DYNAMITE_ACTIVE ||
2493 last_element == EL_EM_DYNAMITE_ACTIVE ||
2494 last_element == EL_SP_DISK_RED_ACTIVE)
2495 DrawDynamite(last_jx, last_jy);
2497 DrawLevelFieldThruMask(last_jx, last_jy);
2499 else if (last_element == EL_DYNAMITE_ACTIVE ||
2500 last_element == EL_EM_DYNAMITE_ACTIVE ||
2501 last_element == EL_SP_DISK_RED_ACTIVE)
2502 DrawDynamite(last_jx, last_jy);
2504 /* !!! this is not enough to prevent flickering of players which are
2505 moving next to each others without a free tile between them -- this
2506 can only be solved by drawing all players layer by layer (first the
2507 background, then the foreground etc.) !!! => TODO */
2508 else if (!IS_PLAYER(last_jx, last_jy))
2509 DrawLevelField(last_jx, last_jy);
2512 DrawLevelField(last_jx, last_jy);
2515 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2516 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2519 if (!IN_SCR_FIELD(sx, sy))
2522 /* ----------------------------------------------------------------------- */
2523 /* draw things behind the player, if needed */
2524 /* ----------------------------------------------------------------------- */
2527 DrawLevelElement(jx, jy, Back[jx][jy]);
2528 else if (IS_ACTIVE_BOMB(element))
2529 DrawLevelElement(jx, jy, EL_EMPTY);
2532 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2534 int old_element = GfxElement[jx][jy];
2535 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2536 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2538 if (GFX_CRUMBLED(old_element))
2539 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2541 DrawGraphic(sx, sy, old_graphic, frame);
2543 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2544 player_is_opaque = TRUE;
2548 GfxElement[jx][jy] = EL_UNDEFINED;
2550 /* make sure that pushed elements are drawn with correct frame rate */
2552 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2554 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2555 GfxFrame[jx][jy] = player->StepFrame;
2557 if (player->is_pushing && player->is_moving)
2558 GfxFrame[jx][jy] = player->StepFrame;
2561 DrawLevelField(jx, jy);
2565 /* ----------------------------------------------------------------------- */
2566 /* draw player himself */
2567 /* ----------------------------------------------------------------------- */
2569 graphic = getPlayerGraphic(player, move_dir);
2571 /* in the case of changed player action or direction, prevent the current
2572 animation frame from being restarted for identical animations */
2573 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2574 player->Frame = last_player_frame;
2576 frame = getGraphicAnimationFrame(graphic, player->Frame);
2580 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2581 sxx = player->GfxPos;
2583 syy = player->GfxPos;
2586 if (!setup.soft_scrolling && ScreenMovPos)
2589 if (player_is_opaque)
2590 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2592 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2594 if (SHIELD_ON(player))
2596 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2597 IMG_SHIELD_NORMAL_ACTIVE);
2598 int frame = getGraphicAnimationFrame(graphic, -1);
2600 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2603 /* ----------------------------------------------------------------------- */
2604 /* draw things the player is pushing, if needed */
2605 /* ----------------------------------------------------------------------- */
2608 printf("::: %d, %d [%d, %d] [%d]\n",
2609 player->is_pushing, player_is_moving, player->GfxAction,
2610 player->is_moving, player_is_moving);
2614 if (player->is_pushing && player->is_moving)
2616 int px = SCREENX(jx), py = SCREENY(jy);
2617 int pxx = (TILEX - ABS(sxx)) * dx;
2618 int pyy = (TILEY - ABS(syy)) * dy;
2619 int gfx_frame = GfxFrame[jx][jy];
2625 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2627 element = Feld[next_jx][next_jy];
2628 gfx_frame = GfxFrame[next_jx][next_jy];
2631 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2634 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2635 frame = getGraphicAnimationFrame(graphic, sync_frame);
2637 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2640 /* draw background element under pushed element (like the Sokoban field) */
2641 if (Back[next_jx][next_jy])
2642 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2644 /* masked drawing is needed for EMC style (double) movement graphics */
2645 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2649 /* ----------------------------------------------------------------------- */
2650 /* draw things in front of player (active dynamite or dynabombs) */
2651 /* ----------------------------------------------------------------------- */
2653 if (IS_ACTIVE_BOMB(element))
2655 graphic = el2img(element);
2656 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2658 if (game.emulation == EMU_SUPAPLEX)
2659 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2661 DrawGraphicThruMask(sx, sy, graphic, frame);
2664 if (player_is_moving && last_element == EL_EXPLOSION)
2666 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2667 GfxElement[last_jx][last_jy] : EL_EMPTY);
2668 int graphic = el_act2img(element, ACTION_EXPLODING);
2669 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2670 int phase = ExplodePhase[last_jx][last_jy] - 1;
2671 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2674 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2677 /* ----------------------------------------------------------------------- */
2678 /* draw elements the player is just walking/passing through/under */
2679 /* ----------------------------------------------------------------------- */
2681 if (player_is_moving)
2683 /* handle the field the player is leaving ... */
2684 if (IS_ACCESSIBLE_INSIDE(last_element))
2685 DrawLevelField(last_jx, last_jy);
2686 else if (IS_ACCESSIBLE_UNDER(last_element))
2687 DrawLevelFieldThruMask(last_jx, last_jy);
2690 /* do not redraw accessible elements if the player is just pushing them */
2691 if (!player_is_moving || !player->is_pushing)
2693 /* ... and the field the player is entering */
2694 if (IS_ACCESSIBLE_INSIDE(element))
2695 DrawLevelField(jx, jy);
2696 else if (IS_ACCESSIBLE_UNDER(element))
2697 DrawLevelFieldThruMask(jx, jy);
2700 MarkTileDirty(sx, sy);
2703 /* ------------------------------------------------------------------------- */
2705 void WaitForEventToContinue()
2707 boolean still_wait = TRUE;
2709 /* simulate releasing mouse button over last gadget, if still pressed */
2711 HandleGadgets(-1, -1, 0);
2713 button_status = MB_RELEASED;
2729 case EVENT_BUTTONPRESS:
2730 case EVENT_KEYPRESS:
2734 case EVENT_KEYRELEASE:
2735 ClearPlayerAction();
2739 HandleOtherEvents(&event);
2743 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2750 /* don't eat all CPU time */
2755 #define MAX_REQUEST_LINES 13
2756 #define MAX_REQUEST_LINE_FONT1_LEN 7
2757 #define MAX_REQUEST_LINE_FONT2_LEN 10
2759 boolean Request(char *text, unsigned int req_state)
2761 int mx, my, ty, result = -1;
2762 unsigned int old_door_state;
2763 int last_game_status = game_status; /* save current game status */
2764 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2765 int font_nr = FONT_TEXT_2;
2766 int max_word_len = 0;
2769 for (text_ptr = text; *text_ptr; text_ptr++)
2771 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2773 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2775 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2777 font_nr = FONT_TEXT_1;
2779 font_nr = FONT_LEVEL_NUMBER;
2786 if (game_status == GAME_MODE_PLAYING &&
2787 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2788 BlitScreenToBitmap_EM(backbuffer);
2790 /* disable deactivated drawing when quick-loading level tape recording */
2791 if (tape.playing && tape.deactivate_display)
2792 TapeDeactivateDisplayOff(TRUE);
2794 SetMouseCursor(CURSOR_DEFAULT);
2796 #if defined(NETWORK_AVALIABLE)
2797 /* pause network game while waiting for request to answer */
2798 if (options.network &&
2799 game_status == GAME_MODE_PLAYING &&
2800 req_state & REQUEST_WAIT_FOR_INPUT)
2801 SendToServer_PausePlaying();
2804 old_door_state = GetDoorState();
2806 /* simulate releasing mouse button over last gadget, if still pressed */
2808 HandleGadgets(-1, -1, 0);
2812 if (old_door_state & DOOR_OPEN_1)
2814 CloseDoor(DOOR_CLOSE_1);
2816 /* save old door content */
2817 BlitBitmap(bitmap_db_door, bitmap_db_door,
2818 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2819 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2823 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2826 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2828 /* clear door drawing field */
2829 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2831 /* force DOOR font inside door area */
2832 game_status = GAME_MODE_PSEUDO_DOOR;
2834 /* write text for request */
2835 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2837 char text_line[max_request_line_len + 1];
2843 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2846 if (!tc || tc == ' ')
2857 strncpy(text_line, text, tl);
2860 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2861 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2862 text_line, font_nr);
2864 text += tl + (tc == ' ' ? 1 : 0);
2867 game_status = last_game_status; /* restore current game status */
2869 if (req_state & REQ_ASK)
2871 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2872 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2874 else if (req_state & REQ_CONFIRM)
2876 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2878 else if (req_state & REQ_PLAYER)
2880 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2881 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2882 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2883 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2886 /* copy request gadgets to door backbuffer */
2887 BlitBitmap(drawto, bitmap_db_door,
2888 DX, DY, DXSIZE, DYSIZE,
2889 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2891 OpenDoor(DOOR_OPEN_1);
2893 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2895 if (game_status == GAME_MODE_PLAYING)
2897 SetPanelBackground();
2898 SetDrawBackgroundMask(REDRAW_DOOR_1);
2902 SetDrawBackgroundMask(REDRAW_FIELD);
2908 if (game_status != GAME_MODE_MAIN)
2911 button_status = MB_RELEASED;
2913 request_gadget_id = -1;
2915 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2927 case EVENT_BUTTONPRESS:
2928 case EVENT_BUTTONRELEASE:
2929 case EVENT_MOTIONNOTIFY:
2931 if (event.type == EVENT_MOTIONNOTIFY)
2933 if (!PointerInWindow(window))
2934 continue; /* window and pointer are on different screens */
2939 motion_status = TRUE;
2940 mx = ((MotionEvent *) &event)->x;
2941 my = ((MotionEvent *) &event)->y;
2945 motion_status = FALSE;
2946 mx = ((ButtonEvent *) &event)->x;
2947 my = ((ButtonEvent *) &event)->y;
2948 if (event.type == EVENT_BUTTONPRESS)
2949 button_status = ((ButtonEvent *) &event)->button;
2951 button_status = MB_RELEASED;
2954 /* this sets 'request_gadget_id' */
2955 HandleGadgets(mx, my, button_status);
2957 switch (request_gadget_id)
2959 case TOOL_CTRL_ID_YES:
2962 case TOOL_CTRL_ID_NO:
2965 case TOOL_CTRL_ID_CONFIRM:
2966 result = TRUE | FALSE;
2969 case TOOL_CTRL_ID_PLAYER_1:
2972 case TOOL_CTRL_ID_PLAYER_2:
2975 case TOOL_CTRL_ID_PLAYER_3:
2978 case TOOL_CTRL_ID_PLAYER_4:
2989 case EVENT_KEYPRESS:
2990 switch (GetEventKey((KeyEvent *)&event, TRUE))
2993 if (req_state & REQ_CONFIRM)
3009 if (req_state & REQ_PLAYER)
3013 case EVENT_KEYRELEASE:
3014 ClearPlayerAction();
3018 HandleOtherEvents(&event);
3022 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3024 int joy = AnyJoystick();
3026 if (joy & JOY_BUTTON_1)
3028 else if (joy & JOY_BUTTON_2)
3034 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3036 HandleGameActions();
3042 if (!PendingEvent()) /* delay only if no pending events */
3053 if (!PendingEvent()) /* delay only if no pending events */
3056 /* don't eat all CPU time */
3063 if (game_status != GAME_MODE_MAIN)
3068 if (!(req_state & REQ_STAY_OPEN))
3070 CloseDoor(DOOR_CLOSE_1);
3072 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3073 (req_state & REQ_REOPEN))
3074 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3079 if (game_status == GAME_MODE_PLAYING)
3081 SetPanelBackground();
3082 SetDrawBackgroundMask(REDRAW_DOOR_1);
3086 SetDrawBackgroundMask(REDRAW_FIELD);
3089 #if defined(NETWORK_AVALIABLE)
3090 /* continue network game after request */
3091 if (options.network &&
3092 game_status == GAME_MODE_PLAYING &&
3093 req_state & REQUEST_WAIT_FOR_INPUT)
3094 SendToServer_ContinuePlaying();
3097 /* restore deactivated drawing when quick-loading level tape recording */
3098 if (tape.playing && tape.deactivate_display)
3099 TapeDeactivateDisplayOn();
3104 unsigned int OpenDoor(unsigned int door_state)
3106 if (door_state & DOOR_COPY_BACK)
3108 if (door_state & DOOR_OPEN_1)
3109 BlitBitmap(bitmap_db_door, bitmap_db_door,
3110 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3111 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3113 if (door_state & DOOR_OPEN_2)
3114 BlitBitmap(bitmap_db_door, bitmap_db_door,
3115 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3116 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3118 door_state &= ~DOOR_COPY_BACK;
3121 return MoveDoor(door_state);
3124 unsigned int CloseDoor(unsigned int door_state)
3126 unsigned int old_door_state = GetDoorState();
3128 if (!(door_state & DOOR_NO_COPY_BACK))
3130 if (old_door_state & DOOR_OPEN_1)
3131 BlitBitmap(backbuffer, bitmap_db_door,
3132 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3134 if (old_door_state & DOOR_OPEN_2)
3135 BlitBitmap(backbuffer, bitmap_db_door,
3136 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3138 door_state &= ~DOOR_NO_COPY_BACK;
3141 return MoveDoor(door_state);
3144 unsigned int GetDoorState()
3146 return MoveDoor(DOOR_GET_STATE);
3149 unsigned int SetDoorState(unsigned int door_state)
3151 return MoveDoor(door_state | DOOR_SET_STATE);
3154 unsigned int MoveDoor(unsigned int door_state)
3156 static int door1 = DOOR_OPEN_1;
3157 static int door2 = DOOR_CLOSE_2;
3158 unsigned long door_delay = 0;
3159 unsigned long door_delay_value;
3162 if (door_1.width < 0 || door_1.width > DXSIZE)
3163 door_1.width = DXSIZE;
3164 if (door_1.height < 0 || door_1.height > DYSIZE)
3165 door_1.height = DYSIZE;
3166 if (door_2.width < 0 || door_2.width > VXSIZE)
3167 door_2.width = VXSIZE;
3168 if (door_2.height < 0 || door_2.height > VYSIZE)
3169 door_2.height = VYSIZE;
3171 if (door_state == DOOR_GET_STATE)
3172 return (door1 | door2);
3174 if (door_state & DOOR_SET_STATE)
3176 if (door_state & DOOR_ACTION_1)
3177 door1 = door_state & DOOR_ACTION_1;
3178 if (door_state & DOOR_ACTION_2)
3179 door2 = door_state & DOOR_ACTION_2;
3181 return (door1 | door2);
3184 if (!(door_state & DOOR_FORCE_REDRAW))
3186 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3187 door_state &= ~DOOR_OPEN_1;
3188 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3189 door_state &= ~DOOR_CLOSE_1;
3190 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3191 door_state &= ~DOOR_OPEN_2;
3192 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3193 door_state &= ~DOOR_CLOSE_2;
3196 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3199 if (setup.quick_doors)
3201 stepsize = 20; /* must be chosen to always draw last frame */
3202 door_delay_value = 0;
3205 if (global.autoplay_leveldir)
3207 door_state |= DOOR_NO_DELAY;
3208 door_state &= ~DOOR_CLOSE_ALL;
3212 if (game_status == GAME_MODE_EDITOR)
3213 door_state |= DOOR_NO_DELAY;
3216 if (door_state & DOOR_ACTION)
3218 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3219 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3220 boolean door_1_done = (!handle_door_1);
3221 boolean door_2_done = (!handle_door_2);
3222 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3223 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3224 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3225 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3226 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3227 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3228 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3229 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3230 int door_skip = max_door_size - door_size;
3231 int end = door_size;
3232 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3235 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3237 /* opening door sound has priority over simultaneously closing door */
3238 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3239 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3240 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3241 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3244 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3247 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3248 GC gc = bitmap->stored_clip_gc;
3250 if (door_state & DOOR_ACTION_1)
3252 int a = MIN(x * door_1.step_offset, end);
3253 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3254 int i = p + door_skip;
3256 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3258 BlitBitmap(bitmap_db_door, drawto,
3259 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3260 DXSIZE, DYSIZE, DX, DY);
3264 BlitBitmap(bitmap_db_door, drawto,
3265 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3266 DXSIZE, DYSIZE - p / 2, DX, DY);
3268 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3271 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3273 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3274 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3275 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3276 int dst2_x = DX, dst2_y = DY;
3277 int width = i, height = DYSIZE;
3279 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3280 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3283 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3284 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3287 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3289 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3290 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3291 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3292 int dst2_x = DX, dst2_y = DY;
3293 int width = DXSIZE, height = i;
3295 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3296 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3299 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3300 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3303 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3305 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3307 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3308 BlitBitmapMasked(bitmap, drawto,
3309 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3310 DX + DXSIZE - i, DY + j);
3311 BlitBitmapMasked(bitmap, drawto,
3312 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3313 DX + DXSIZE - i, DY + 140 + j);
3314 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3315 DY - (DOOR_GFX_PAGEY1 + j));
3316 BlitBitmapMasked(bitmap, drawto,
3317 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3319 BlitBitmapMasked(bitmap, drawto,
3320 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3323 BlitBitmapMasked(bitmap, drawto,
3324 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3326 BlitBitmapMasked(bitmap, drawto,
3327 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3329 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3330 BlitBitmapMasked(bitmap, drawto,
3331 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3332 DX + DXSIZE - i, DY + 77 + j);
3333 BlitBitmapMasked(bitmap, drawto,
3334 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3335 DX + DXSIZE - i, DY + 203 + j);
3338 redraw_mask |= REDRAW_DOOR_1;
3339 door_1_done = (a == end);
3342 if (door_state & DOOR_ACTION_2)
3344 int a = MIN(x * door_2.step_offset, door_size);
3345 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3346 int i = p + door_skip;
3348 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3350 BlitBitmap(bitmap_db_door, drawto,
3351 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3352 VXSIZE, VYSIZE, VX, VY);
3354 else if (x <= VYSIZE)
3356 BlitBitmap(bitmap_db_door, drawto,
3357 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3358 VXSIZE, VYSIZE - p / 2, VX, VY);
3360 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3363 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3365 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3366 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3367 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3368 int dst2_x = VX, dst2_y = VY;
3369 int width = i, height = VYSIZE;
3371 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3372 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3375 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3376 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3379 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3381 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3382 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3383 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3384 int dst2_x = VX, dst2_y = VY;
3385 int width = VXSIZE, height = i;
3387 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3388 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3391 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3392 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3395 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3397 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3399 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3400 BlitBitmapMasked(bitmap, drawto,
3401 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3402 VX + VXSIZE - i, VY + j);
3403 SetClipOrigin(bitmap, gc,
3404 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3405 BlitBitmapMasked(bitmap, drawto,
3406 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3409 BlitBitmapMasked(bitmap, drawto,
3410 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3411 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3412 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3413 BlitBitmapMasked(bitmap, drawto,
3414 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3416 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3419 redraw_mask |= REDRAW_DOOR_2;
3420 door_2_done = (a == VXSIZE);
3423 if (!(door_state & DOOR_NO_DELAY))
3427 if (game_status == GAME_MODE_MAIN)
3430 WaitUntilDelayReached(&door_delay, door_delay_value);
3435 if (door_state & DOOR_ACTION_1)
3436 door1 = door_state & DOOR_ACTION_1;
3437 if (door_state & DOOR_ACTION_2)
3438 door2 = door_state & DOOR_ACTION_2;
3440 return (door1 | door2);
3443 void DrawSpecialEditorDoor()
3445 /* draw bigger toolbox window */
3446 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3447 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3449 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3450 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3453 redraw_mask |= REDRAW_ALL;
3456 void UndrawSpecialEditorDoor()
3458 /* draw normal tape recorder window */
3459 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3460 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3463 redraw_mask |= REDRAW_ALL;
3467 /* ---------- new tool button stuff ---------------------------------------- */
3469 /* graphic position values for tool buttons */
3470 #define TOOL_BUTTON_YES_XPOS 2
3471 #define TOOL_BUTTON_YES_YPOS 250
3472 #define TOOL_BUTTON_YES_GFX_YPOS 0
3473 #define TOOL_BUTTON_YES_XSIZE 46
3474 #define TOOL_BUTTON_YES_YSIZE 28
3475 #define TOOL_BUTTON_NO_XPOS 52
3476 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3477 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3478 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3479 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3480 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3481 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3482 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3483 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3484 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3485 #define TOOL_BUTTON_PLAYER_XSIZE 30
3486 #define TOOL_BUTTON_PLAYER_YSIZE 30
3487 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3488 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3489 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3490 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3491 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3492 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3493 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3494 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3495 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3496 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3497 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3498 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3499 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3500 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3501 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3502 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3503 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3504 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3505 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3506 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3515 } toolbutton_info[NUM_TOOL_BUTTONS] =
3518 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3519 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3520 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3525 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3526 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3527 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3532 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3533 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3534 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3535 TOOL_CTRL_ID_CONFIRM,
3539 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3540 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3541 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3542 TOOL_CTRL_ID_PLAYER_1,
3546 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3547 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3548 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3549 TOOL_CTRL_ID_PLAYER_2,
3553 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3554 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3555 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3556 TOOL_CTRL_ID_PLAYER_3,
3560 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3561 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3562 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3563 TOOL_CTRL_ID_PLAYER_4,
3568 void CreateToolButtons()
3572 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3574 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3575 Bitmap *deco_bitmap = None;
3576 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3577 struct GadgetInfo *gi;
3578 unsigned long event_mask;
3579 int gd_xoffset, gd_yoffset;
3580 int gd_x1, gd_x2, gd_y;
3583 event_mask = GD_EVENT_RELEASED;
3585 gd_xoffset = toolbutton_info[i].xpos;
3586 gd_yoffset = toolbutton_info[i].ypos;
3587 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3588 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3589 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3591 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3593 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3595 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3596 &deco_bitmap, &deco_x, &deco_y);
3597 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3598 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3601 gi = CreateGadget(GDI_CUSTOM_ID, id,
3602 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3603 GDI_X, DX + toolbutton_info[i].x,
3604 GDI_Y, DY + toolbutton_info[i].y,
3605 GDI_WIDTH, toolbutton_info[i].width,
3606 GDI_HEIGHT, toolbutton_info[i].height,
3607 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3608 GDI_STATE, GD_BUTTON_UNPRESSED,
3609 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3610 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3611 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3612 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3613 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3614 GDI_DECORATION_SHIFTING, 1, 1,
3615 GDI_DIRECT_DRAW, FALSE,
3616 GDI_EVENT_MASK, event_mask,
3617 GDI_CALLBACK_ACTION, HandleToolButtons,
3621 Error(ERR_EXIT, "cannot create gadget");
3623 tool_gadget[id] = gi;
3627 void FreeToolButtons()
3631 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3632 FreeGadget(tool_gadget[i]);
3635 static void UnmapToolButtons()
3639 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3640 UnmapGadget(tool_gadget[i]);
3643 static void HandleToolButtons(struct GadgetInfo *gi)
3645 request_gadget_id = gi->custom_id;
3648 static struct Mapping_EM_to_RND_object
3651 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3652 boolean is_backside; /* backside of moving element */
3658 em_object_mapping_list[] =
3661 Xblank, TRUE, FALSE,
3665 Yacid_splash_eB, FALSE, FALSE,
3666 EL_ACID_SPLASH_RIGHT, -1, -1
3669 Yacid_splash_wB, FALSE, FALSE,
3670 EL_ACID_SPLASH_LEFT, -1, -1
3673 #ifdef EM_ENGINE_BAD_ROLL
3675 Xstone_force_e, FALSE, FALSE,
3676 EL_ROCK, -1, MV_BIT_RIGHT
3679 Xstone_force_w, FALSE, FALSE,
3680 EL_ROCK, -1, MV_BIT_LEFT
3683 Xnut_force_e, FALSE, FALSE,
3684 EL_NUT, -1, MV_BIT_RIGHT
3687 Xnut_force_w, FALSE, FALSE,
3688 EL_NUT, -1, MV_BIT_LEFT
3691 Xspring_force_e, FALSE, FALSE,
3692 EL_SPRING, -1, MV_BIT_RIGHT
3695 Xspring_force_w, FALSE, FALSE,
3696 EL_SPRING, -1, MV_BIT_LEFT
3699 Xemerald_force_e, FALSE, FALSE,
3700 EL_EMERALD, -1, MV_BIT_RIGHT
3703 Xemerald_force_w, FALSE, FALSE,
3704 EL_EMERALD, -1, MV_BIT_LEFT
3707 Xdiamond_force_e, FALSE, FALSE,
3708 EL_DIAMOND, -1, MV_BIT_RIGHT
3711 Xdiamond_force_w, FALSE, FALSE,
3712 EL_DIAMOND, -1, MV_BIT_LEFT
3715 Xbomb_force_e, FALSE, FALSE,
3716 EL_BOMB, -1, MV_BIT_RIGHT
3719 Xbomb_force_w, FALSE, FALSE,
3720 EL_BOMB, -1, MV_BIT_LEFT
3722 #endif /* EM_ENGINE_BAD_ROLL */
3725 Xstone, TRUE, FALSE,
3729 Xstone_pause, FALSE, FALSE,
3733 Xstone_fall, FALSE, FALSE,
3737 Ystone_s, FALSE, FALSE,
3738 EL_ROCK, ACTION_FALLING, -1
3741 Ystone_sB, FALSE, TRUE,
3742 EL_ROCK, ACTION_FALLING, -1
3745 Ystone_e, FALSE, FALSE,
3746 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3749 Ystone_eB, FALSE, TRUE,
3750 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3753 Ystone_w, FALSE, FALSE,
3754 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3757 Ystone_wB, FALSE, TRUE,
3758 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3765 Xnut_pause, FALSE, FALSE,
3769 Xnut_fall, FALSE, FALSE,
3773 Ynut_s, FALSE, FALSE,
3774 EL_NUT, ACTION_FALLING, -1
3777 Ynut_sB, FALSE, TRUE,
3778 EL_NUT, ACTION_FALLING, -1
3781 Ynut_e, FALSE, FALSE,
3782 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3785 Ynut_eB, FALSE, TRUE,
3786 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3789 Ynut_w, FALSE, FALSE,
3790 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3793 Ynut_wB, FALSE, TRUE,
3794 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3797 Xbug_n, TRUE, FALSE,
3801 Xbug_e, TRUE, FALSE,
3802 EL_BUG_RIGHT, -1, -1
3805 Xbug_s, TRUE, FALSE,
3809 Xbug_w, TRUE, FALSE,
3813 Xbug_gon, FALSE, FALSE,
3817 Xbug_goe, FALSE, FALSE,
3818 EL_BUG_RIGHT, -1, -1
3821 Xbug_gos, FALSE, FALSE,
3825 Xbug_gow, FALSE, FALSE,
3829 Ybug_n, FALSE, FALSE,
3830 EL_BUG, ACTION_MOVING, MV_BIT_UP
3833 Ybug_nB, FALSE, TRUE,
3834 EL_BUG, ACTION_MOVING, MV_BIT_UP
3837 Ybug_e, FALSE, FALSE,
3838 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3841 Ybug_eB, FALSE, TRUE,
3842 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3845 Ybug_s, FALSE, FALSE,
3846 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3849 Ybug_sB, FALSE, TRUE,
3850 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3853 Ybug_w, FALSE, FALSE,
3854 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3857 Ybug_wB, FALSE, TRUE,
3858 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3861 Ybug_w_n, FALSE, FALSE,
3862 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3865 Ybug_n_e, FALSE, FALSE,
3866 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3869 Ybug_e_s, FALSE, FALSE,
3870 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3873 Ybug_s_w, FALSE, FALSE,
3874 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3877 Ybug_e_n, FALSE, FALSE,
3878 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3881 Ybug_s_e, FALSE, FALSE,
3882 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3885 Ybug_w_s, FALSE, FALSE,
3886 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3889 Ybug_n_w, FALSE, FALSE,
3890 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3893 Ybug_stone, FALSE, FALSE,
3894 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3897 Ybug_spring, FALSE, FALSE,
3898 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3901 Xtank_n, TRUE, FALSE,
3902 EL_SPACESHIP_UP, -1, -1
3905 Xtank_e, TRUE, FALSE,
3906 EL_SPACESHIP_RIGHT, -1, -1
3909 Xtank_s, TRUE, FALSE,
3910 EL_SPACESHIP_DOWN, -1, -1
3913 Xtank_w, TRUE, FALSE,
3914 EL_SPACESHIP_LEFT, -1, -1
3917 Xtank_gon, FALSE, FALSE,
3918 EL_SPACESHIP_UP, -1, -1
3921 Xtank_goe, FALSE, FALSE,
3922 EL_SPACESHIP_RIGHT, -1, -1
3925 Xtank_gos, FALSE, FALSE,
3926 EL_SPACESHIP_DOWN, -1, -1
3929 Xtank_gow, FALSE, FALSE,
3930 EL_SPACESHIP_LEFT, -1, -1
3933 Ytank_n, FALSE, FALSE,
3934 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3937 Ytank_nB, FALSE, TRUE,
3938 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3941 Ytank_e, FALSE, FALSE,
3942 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3945 Ytank_eB, FALSE, TRUE,
3946 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3949 Ytank_s, FALSE, FALSE,
3950 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3953 Ytank_sB, FALSE, TRUE,
3954 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3957 Ytank_w, FALSE, FALSE,
3958 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3961 Ytank_wB, FALSE, TRUE,
3962 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3965 Ytank_w_n, FALSE, FALSE,
3966 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3969 Ytank_n_e, FALSE, FALSE,
3970 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3973 Ytank_e_s, FALSE, FALSE,
3974 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3977 Ytank_s_w, FALSE, FALSE,
3978 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3981 Ytank_e_n, FALSE, FALSE,
3982 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3985 Ytank_s_e, FALSE, FALSE,
3986 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3989 Ytank_w_s, FALSE, FALSE,
3990 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3993 Ytank_n_w, FALSE, FALSE,
3994 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3997 Ytank_stone, FALSE, FALSE,
3998 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4001 Ytank_spring, FALSE, FALSE,
4002 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4005 Xandroid, TRUE, FALSE,
4006 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4009 Xandroid_1_n, FALSE, FALSE,
4010 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4013 Xandroid_2_n, FALSE, FALSE,
4014 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4017 Xandroid_1_e, FALSE, FALSE,
4018 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4021 Xandroid_2_e, FALSE, FALSE,
4022 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4025 Xandroid_1_w, FALSE, FALSE,
4026 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4029 Xandroid_2_w, FALSE, FALSE,
4030 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4033 Xandroid_1_s, FALSE, FALSE,
4034 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4037 Xandroid_2_s, FALSE, FALSE,
4038 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4041 Yandroid_n, FALSE, FALSE,
4042 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4045 Yandroid_nB, FALSE, TRUE,
4046 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4049 Yandroid_ne, FALSE, FALSE,
4050 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4053 Yandroid_neB, FALSE, TRUE,
4054 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4057 Yandroid_e, FALSE, FALSE,
4058 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4061 Yandroid_eB, FALSE, TRUE,
4062 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4065 Yandroid_se, FALSE, FALSE,
4066 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4069 Yandroid_seB, FALSE, TRUE,
4070 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4073 Yandroid_s, FALSE, FALSE,
4074 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4077 Yandroid_sB, FALSE, TRUE,
4078 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4081 Yandroid_sw, FALSE, FALSE,
4082 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4085 Yandroid_swB, FALSE, TRUE,
4086 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4089 Yandroid_w, FALSE, FALSE,
4090 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4093 Yandroid_wB, FALSE, TRUE,
4094 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4097 Yandroid_nw, FALSE, FALSE,
4098 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4101 Yandroid_nwB, FALSE, TRUE,
4102 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4105 Xspring, TRUE, FALSE,
4109 Xspring_pause, FALSE, FALSE,
4113 Xspring_e, FALSE, FALSE,
4117 Xspring_w, FALSE, FALSE,
4121 Xspring_fall, FALSE, FALSE,
4125 Yspring_s, FALSE, FALSE,
4126 EL_SPRING, ACTION_FALLING, -1
4129 Yspring_sB, FALSE, TRUE,
4130 EL_SPRING, ACTION_FALLING, -1
4133 Yspring_e, FALSE, FALSE,
4134 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4137 Yspring_eB, FALSE, TRUE,
4138 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4141 Yspring_w, FALSE, FALSE,
4142 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4145 Yspring_wB, FALSE, TRUE,
4146 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4149 Yspring_kill_e, FALSE, FALSE,
4150 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4153 Yspring_kill_eB, FALSE, TRUE,
4154 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4157 Yspring_kill_w, FALSE, FALSE,
4158 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4161 Yspring_kill_wB, FALSE, TRUE,
4162 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4165 Xeater_n, TRUE, FALSE,
4166 EL_YAMYAM_UP, -1, -1
4169 Xeater_e, TRUE, FALSE,
4170 EL_YAMYAM_RIGHT, -1, -1
4173 Xeater_w, TRUE, FALSE,
4174 EL_YAMYAM_LEFT, -1, -1
4177 Xeater_s, TRUE, FALSE,
4178 EL_YAMYAM_DOWN, -1, -1
4181 Yeater_n, FALSE, FALSE,
4182 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4185 Yeater_nB, FALSE, TRUE,
4186 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4189 Yeater_e, FALSE, FALSE,
4190 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4193 Yeater_eB, FALSE, TRUE,
4194 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4197 Yeater_s, FALSE, FALSE,
4198 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4201 Yeater_sB, FALSE, TRUE,
4202 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4205 Yeater_w, FALSE, FALSE,
4206 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4209 Yeater_wB, FALSE, TRUE,
4210 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4213 Yeater_stone, FALSE, FALSE,
4214 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4217 Yeater_spring, FALSE, FALSE,
4218 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4221 Xalien, TRUE, FALSE,
4225 Xalien_pause, FALSE, FALSE,
4229 Yalien_n, FALSE, FALSE,
4230 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4233 Yalien_nB, FALSE, TRUE,
4234 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4237 Yalien_e, FALSE, FALSE,
4238 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4241 Yalien_eB, FALSE, TRUE,
4242 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4245 Yalien_s, FALSE, FALSE,
4246 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4249 Yalien_sB, FALSE, TRUE,
4250 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4253 Yalien_w, FALSE, FALSE,
4254 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4257 Yalien_wB, FALSE, TRUE,
4258 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4261 Yalien_stone, FALSE, FALSE,
4262 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4265 Yalien_spring, FALSE, FALSE,
4266 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4269 Xemerald, TRUE, FALSE,
4273 Xemerald_pause, FALSE, FALSE,
4277 Xemerald_fall, FALSE, FALSE,
4281 Xemerald_shine, FALSE, FALSE,
4282 EL_EMERALD, ACTION_TWINKLING, -1
4285 Yemerald_s, FALSE, FALSE,
4286 EL_EMERALD, ACTION_FALLING, -1
4289 Yemerald_sB, FALSE, TRUE,
4290 EL_EMERALD, ACTION_FALLING, -1
4293 Yemerald_e, FALSE, FALSE,
4294 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4297 Yemerald_eB, FALSE, TRUE,
4298 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4301 Yemerald_w, FALSE, FALSE,
4302 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4305 Yemerald_wB, FALSE, TRUE,
4306 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4309 Yemerald_eat, FALSE, FALSE,
4310 EL_EMERALD, ACTION_COLLECTING, -1
4313 Yemerald_stone, FALSE, FALSE,
4314 EL_NUT, ACTION_BREAKING, -1
4317 Xdiamond, TRUE, FALSE,
4321 Xdiamond_pause, FALSE, FALSE,
4325 Xdiamond_fall, FALSE, FALSE,
4329 Xdiamond_shine, FALSE, FALSE,
4330 EL_DIAMOND, ACTION_TWINKLING, -1
4333 Ydiamond_s, FALSE, FALSE,
4334 EL_DIAMOND, ACTION_FALLING, -1
4337 Ydiamond_sB, FALSE, TRUE,
4338 EL_DIAMOND, ACTION_FALLING, -1
4341 Ydiamond_e, FALSE, FALSE,
4342 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4345 Ydiamond_eB, FALSE, TRUE,
4346 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4349 Ydiamond_w, FALSE, FALSE,
4350 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4353 Ydiamond_wB, FALSE, TRUE,
4354 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4357 Ydiamond_eat, FALSE, FALSE,
4358 EL_DIAMOND, ACTION_COLLECTING, -1
4361 Ydiamond_stone, FALSE, FALSE,
4362 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4365 Xdrip_fall, TRUE, FALSE,
4366 EL_AMOEBA_DROP, -1, -1
4369 Xdrip_stretch, FALSE, FALSE,
4370 EL_AMOEBA_DROP, ACTION_FALLING, -1
4373 Xdrip_stretchB, FALSE, TRUE,
4374 EL_AMOEBA_DROP, ACTION_FALLING, -1
4377 Xdrip_eat, FALSE, FALSE,
4378 EL_AMOEBA_DROP, ACTION_GROWING, -1
4381 Ydrip_s1, FALSE, FALSE,
4382 EL_AMOEBA_DROP, ACTION_FALLING, -1
4385 Ydrip_s1B, FALSE, TRUE,
4386 EL_AMOEBA_DROP, ACTION_FALLING, -1
4389 Ydrip_s2, FALSE, FALSE,
4390 EL_AMOEBA_DROP, ACTION_FALLING, -1
4393 Ydrip_s2B, FALSE, TRUE,
4394 EL_AMOEBA_DROP, ACTION_FALLING, -1
4401 Xbomb_pause, FALSE, FALSE,
4405 Xbomb_fall, FALSE, FALSE,
4409 Ybomb_s, FALSE, FALSE,
4410 EL_BOMB, ACTION_FALLING, -1
4413 Ybomb_sB, FALSE, TRUE,
4414 EL_BOMB, ACTION_FALLING, -1
4417 Ybomb_e, FALSE, FALSE,
4418 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4421 Ybomb_eB, FALSE, TRUE,
4422 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4425 Ybomb_w, FALSE, FALSE,
4426 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4429 Ybomb_wB, FALSE, TRUE,
4430 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4433 Ybomb_eat, FALSE, FALSE,
4434 EL_BOMB, ACTION_ACTIVATING, -1
4437 Xballoon, TRUE, FALSE,
4441 Yballoon_n, FALSE, FALSE,
4442 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4445 Yballoon_nB, FALSE, TRUE,
4446 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4449 Yballoon_e, FALSE, FALSE,
4450 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4453 Yballoon_eB, FALSE, TRUE,
4454 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4457 Yballoon_s, FALSE, FALSE,
4458 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4461 Yballoon_sB, FALSE, TRUE,
4462 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4465 Yballoon_w, FALSE, FALSE,
4466 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4469 Yballoon_wB, FALSE, TRUE,
4470 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4473 Xgrass, TRUE, FALSE,
4474 EL_EMC_GRASS, -1, -1
4477 Ygrass_nB, FALSE, FALSE,
4478 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4481 Ygrass_eB, FALSE, FALSE,
4482 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4485 Ygrass_sB, FALSE, FALSE,
4486 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4489 Ygrass_wB, FALSE, FALSE,
4490 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4497 Ydirt_nB, FALSE, FALSE,
4498 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4501 Ydirt_eB, FALSE, FALSE,
4502 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4505 Ydirt_sB, FALSE, FALSE,
4506 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4509 Ydirt_wB, FALSE, FALSE,
4510 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4513 Xacid_ne, TRUE, FALSE,
4514 EL_ACID_POOL_TOPRIGHT, -1, -1
4517 Xacid_se, TRUE, FALSE,
4518 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4521 Xacid_s, TRUE, FALSE,
4522 EL_ACID_POOL_BOTTOM, -1, -1
4525 Xacid_sw, TRUE, FALSE,
4526 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4529 Xacid_nw, TRUE, FALSE,
4530 EL_ACID_POOL_TOPLEFT, -1, -1
4533 Xacid_1, TRUE, FALSE,
4537 Xacid_2, FALSE, FALSE,
4541 Xacid_3, FALSE, FALSE,
4545 Xacid_4, FALSE, FALSE,
4549 Xacid_5, FALSE, FALSE,
4553 Xacid_6, FALSE, FALSE,
4557 Xacid_7, FALSE, FALSE,
4561 Xacid_8, FALSE, FALSE,
4565 Xball_1, TRUE, FALSE,
4566 EL_EMC_MAGIC_BALL, -1, -1
4569 Xball_1B, FALSE, FALSE,
4570 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4573 Xball_2, FALSE, FALSE,
4574 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4577 Xball_2B, FALSE, FALSE,
4578 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4581 Yball_eat, FALSE, FALSE,
4582 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4585 Ykey_1_eat, FALSE, FALSE,
4586 EL_EM_KEY_1, ACTION_COLLECTING, -1
4589 Ykey_2_eat, FALSE, FALSE,
4590 EL_EM_KEY_2, ACTION_COLLECTING, -1
4593 Ykey_3_eat, FALSE, FALSE,
4594 EL_EM_KEY_3, ACTION_COLLECTING, -1
4597 Ykey_4_eat, FALSE, FALSE,
4598 EL_EM_KEY_4, ACTION_COLLECTING, -1
4601 Ykey_5_eat, FALSE, FALSE,
4602 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4605 Ykey_6_eat, FALSE, FALSE,
4606 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4609 Ykey_7_eat, FALSE, FALSE,
4610 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4613 Ykey_8_eat, FALSE, FALSE,
4614 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4617 Ylenses_eat, FALSE, FALSE,
4618 EL_EMC_LENSES, ACTION_COLLECTING, -1
4621 Ymagnify_eat, FALSE, FALSE,
4622 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4625 Ygrass_eat, FALSE, FALSE,
4626 EL_EMC_GRASS, ACTION_SNAPPING, -1
4629 Ydirt_eat, FALSE, FALSE,
4630 EL_SAND, ACTION_SNAPPING, -1
4633 Xgrow_ns, TRUE, FALSE,
4634 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4637 Ygrow_ns_eat, FALSE, FALSE,
4638 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4641 Xgrow_ew, TRUE, FALSE,
4642 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4645 Ygrow_ew_eat, FALSE, FALSE,
4646 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4649 Xwonderwall, TRUE, FALSE,
4650 EL_MAGIC_WALL, -1, -1
4653 XwonderwallB, FALSE, FALSE,
4654 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4657 Xamoeba_1, TRUE, FALSE,
4658 EL_AMOEBA_DRY, ACTION_OTHER, -1
4661 Xamoeba_2, FALSE, FALSE,
4662 EL_AMOEBA_DRY, ACTION_OTHER, -1
4665 Xamoeba_3, FALSE, FALSE,
4666 EL_AMOEBA_DRY, ACTION_OTHER, -1
4669 Xamoeba_4, FALSE, FALSE,
4670 EL_AMOEBA_DRY, ACTION_OTHER, -1
4673 Xamoeba_5, TRUE, FALSE,
4674 EL_AMOEBA_WET, ACTION_OTHER, -1
4677 Xamoeba_6, FALSE, FALSE,
4678 EL_AMOEBA_WET, ACTION_OTHER, -1
4681 Xamoeba_7, FALSE, FALSE,
4682 EL_AMOEBA_WET, ACTION_OTHER, -1
4685 Xamoeba_8, FALSE, FALSE,
4686 EL_AMOEBA_WET, ACTION_OTHER, -1
4689 Xdoor_1, TRUE, FALSE,
4690 EL_EM_GATE_1, -1, -1
4693 Xdoor_2, TRUE, FALSE,
4694 EL_EM_GATE_2, -1, -1
4697 Xdoor_3, TRUE, FALSE,
4698 EL_EM_GATE_3, -1, -1
4701 Xdoor_4, TRUE, FALSE,
4702 EL_EM_GATE_4, -1, -1
4705 Xdoor_5, TRUE, FALSE,
4706 EL_EMC_GATE_5, -1, -1
4709 Xdoor_6, TRUE, FALSE,
4710 EL_EMC_GATE_6, -1, -1
4713 Xdoor_7, TRUE, FALSE,
4714 EL_EMC_GATE_7, -1, -1
4717 Xdoor_8, TRUE, FALSE,
4718 EL_EMC_GATE_8, -1, -1
4721 Xkey_1, TRUE, FALSE,
4725 Xkey_2, TRUE, FALSE,
4729 Xkey_3, TRUE, FALSE,
4733 Xkey_4, TRUE, FALSE,
4737 Xkey_5, TRUE, FALSE,
4738 EL_EMC_KEY_5, -1, -1
4741 Xkey_6, TRUE, FALSE,
4742 EL_EMC_KEY_6, -1, -1
4745 Xkey_7, TRUE, FALSE,
4746 EL_EMC_KEY_7, -1, -1
4749 Xkey_8, TRUE, FALSE,
4750 EL_EMC_KEY_8, -1, -1
4753 Xwind_n, TRUE, FALSE,
4754 EL_BALLOON_SWITCH_UP, -1, -1
4757 Xwind_e, TRUE, FALSE,
4758 EL_BALLOON_SWITCH_RIGHT, -1, -1
4761 Xwind_s, TRUE, FALSE,
4762 EL_BALLOON_SWITCH_DOWN, -1, -1
4765 Xwind_w, TRUE, FALSE,
4766 EL_BALLOON_SWITCH_LEFT, -1, -1
4769 Xwind_nesw, TRUE, FALSE,
4770 EL_BALLOON_SWITCH_ANY, -1, -1
4773 Xwind_stop, TRUE, FALSE,
4774 EL_BALLOON_SWITCH_NONE, -1, -1
4778 EL_EM_EXIT_CLOSED, -1, -1
4781 Xexit_1, TRUE, FALSE,
4782 EL_EM_EXIT_OPEN, -1, -1
4785 Xexit_2, FALSE, FALSE,
4786 EL_EM_EXIT_OPEN, -1, -1
4789 Xexit_3, FALSE, FALSE,
4790 EL_EM_EXIT_OPEN, -1, -1
4793 Xdynamite, TRUE, FALSE,
4794 EL_EM_DYNAMITE, -1, -1
4797 Ydynamite_eat, FALSE, FALSE,
4798 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4801 Xdynamite_1, TRUE, FALSE,
4802 EL_EM_DYNAMITE_ACTIVE, -1, -1
4805 Xdynamite_2, FALSE, FALSE,
4806 EL_EM_DYNAMITE_ACTIVE, -1, -1
4809 Xdynamite_3, FALSE, FALSE,
4810 EL_EM_DYNAMITE_ACTIVE, -1, -1
4813 Xdynamite_4, FALSE, FALSE,
4814 EL_EM_DYNAMITE_ACTIVE, -1, -1
4817 Xbumper, TRUE, FALSE,
4818 EL_EMC_SPRING_BUMPER, -1, -1
4821 XbumperB, FALSE, FALSE,
4822 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4825 Xwheel, TRUE, FALSE,
4826 EL_ROBOT_WHEEL, -1, -1
4829 XwheelB, FALSE, FALSE,
4830 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4833 Xswitch, TRUE, FALSE,
4834 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4837 XswitchB, FALSE, FALSE,
4838 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4842 EL_QUICKSAND_EMPTY, -1, -1
4845 Xsand_stone, TRUE, FALSE,
4846 EL_QUICKSAND_FULL, -1, -1
4849 Xsand_stonein_1, FALSE, TRUE,
4850 EL_ROCK, ACTION_FILLING, -1
4853 Xsand_stonein_2, FALSE, TRUE,
4854 EL_ROCK, ACTION_FILLING, -1
4857 Xsand_stonein_3, FALSE, TRUE,
4858 EL_ROCK, ACTION_FILLING, -1
4861 Xsand_stonein_4, FALSE, TRUE,
4862 EL_ROCK, ACTION_FILLING, -1
4866 Xsand_stonesand_1, FALSE, FALSE,
4867 EL_QUICKSAND_EMPTYING, -1, -1
4870 Xsand_stonesand_2, FALSE, FALSE,
4871 EL_QUICKSAND_EMPTYING, -1, -1
4874 Xsand_stonesand_3, FALSE, FALSE,
4875 EL_QUICKSAND_EMPTYING, -1, -1
4878 Xsand_stonesand_4, FALSE, FALSE,
4879 EL_QUICKSAND_EMPTYING, -1, -1
4882 Xsand_stonesand_quickout_1, FALSE, FALSE,
4883 EL_QUICKSAND_EMPTYING, -1, -1
4886 Xsand_stonesand_quickout_2, FALSE, FALSE,
4887 EL_QUICKSAND_EMPTYING, -1, -1
4891 Xsand_stonesand_1, FALSE, FALSE,
4892 EL_QUICKSAND_FULL, -1, -1
4895 Xsand_stonesand_2, FALSE, FALSE,
4896 EL_QUICKSAND_FULL, -1, -1
4899 Xsand_stonesand_3, FALSE, FALSE,
4900 EL_QUICKSAND_FULL, -1, -1
4903 Xsand_stonesand_4, FALSE, FALSE,
4904 EL_QUICKSAND_FULL, -1, -1
4908 Xsand_stoneout_1, FALSE, FALSE,
4909 EL_ROCK, ACTION_EMPTYING, -1
4912 Xsand_stoneout_2, FALSE, FALSE,
4913 EL_ROCK, ACTION_EMPTYING, -1
4917 Xsand_sandstone_1, FALSE, FALSE,
4918 EL_QUICKSAND_FILLING, -1, -1
4921 Xsand_sandstone_2, FALSE, FALSE,
4922 EL_QUICKSAND_FILLING, -1, -1
4925 Xsand_sandstone_3, FALSE, FALSE,
4926 EL_QUICKSAND_FILLING, -1, -1
4929 Xsand_sandstone_4, FALSE, FALSE,
4930 EL_QUICKSAND_FILLING, -1, -1
4934 Xsand_sandstone_1, FALSE, FALSE,
4935 EL_QUICKSAND_FULL, -1, -1
4938 Xsand_sandstone_2, FALSE, FALSE,
4939 EL_QUICKSAND_FULL, -1, -1
4942 Xsand_sandstone_3, FALSE, FALSE,
4943 EL_QUICKSAND_FULL, -1, -1
4946 Xsand_sandstone_4, FALSE, FALSE,
4947 EL_QUICKSAND_FULL, -1, -1
4951 Xplant, TRUE, FALSE,
4952 EL_EMC_PLANT, -1, -1
4955 Yplant, FALSE, FALSE,
4956 EL_EMC_PLANT, -1, -1
4959 Xlenses, TRUE, FALSE,
4960 EL_EMC_LENSES, -1, -1
4963 Xmagnify, TRUE, FALSE,
4964 EL_EMC_MAGNIFIER, -1, -1
4967 Xdripper, TRUE, FALSE,
4968 EL_EMC_DRIPPER, -1, -1
4971 XdripperB, FALSE, FALSE,
4972 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4975 Xfake_blank, TRUE, FALSE,
4976 EL_INVISIBLE_WALL, -1, -1
4979 Xfake_blankB, FALSE, FALSE,
4980 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4983 Xfake_grass, TRUE, FALSE,
4984 EL_EMC_FAKE_GRASS, -1, -1
4987 Xfake_grassB, FALSE, FALSE,
4988 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4991 Xfake_door_1, TRUE, FALSE,
4992 EL_EM_GATE_1_GRAY, -1, -1
4995 Xfake_door_2, TRUE, FALSE,
4996 EL_EM_GATE_2_GRAY, -1, -1
4999 Xfake_door_3, TRUE, FALSE,
5000 EL_EM_GATE_3_GRAY, -1, -1
5003 Xfake_door_4, TRUE, FALSE,
5004 EL_EM_GATE_4_GRAY, -1, -1
5007 Xfake_door_5, TRUE, FALSE,
5008 EL_EMC_GATE_5_GRAY, -1, -1
5011 Xfake_door_6, TRUE, FALSE,
5012 EL_EMC_GATE_6_GRAY, -1, -1
5015 Xfake_door_7, TRUE, FALSE,
5016 EL_EMC_GATE_7_GRAY, -1, -1
5019 Xfake_door_8, TRUE, FALSE,
5020 EL_EMC_GATE_8_GRAY, -1, -1
5023 Xfake_acid_1, TRUE, FALSE,
5024 EL_EMC_FAKE_ACID, -1, -1
5027 Xfake_acid_2, FALSE, FALSE,
5028 EL_EMC_FAKE_ACID, -1, -1
5031 Xfake_acid_3, FALSE, FALSE,
5032 EL_EMC_FAKE_ACID, -1, -1
5035 Xfake_acid_4, FALSE, FALSE,
5036 EL_EMC_FAKE_ACID, -1, -1
5039 Xfake_acid_5, FALSE, FALSE,
5040 EL_EMC_FAKE_ACID, -1, -1
5043 Xfake_acid_6, FALSE, FALSE,
5044 EL_EMC_FAKE_ACID, -1, -1
5047 Xfake_acid_7, FALSE, FALSE,
5048 EL_EMC_FAKE_ACID, -1, -1
5051 Xfake_acid_8, FALSE, FALSE,
5052 EL_EMC_FAKE_ACID, -1, -1
5055 Xsteel_1, TRUE, FALSE,
5056 EL_STEELWALL, -1, -1
5059 Xsteel_2, TRUE, FALSE,
5060 EL_EMC_STEELWALL_2, -1, -1
5063 Xsteel_3, TRUE, FALSE,
5064 EL_EMC_STEELWALL_3, -1, -1
5067 Xsteel_4, TRUE, FALSE,
5068 EL_EMC_STEELWALL_4, -1, -1
5071 Xwall_1, TRUE, FALSE,
5075 Xwall_2, TRUE, FALSE,
5076 EL_EMC_WALL_14, -1, -1
5079 Xwall_3, TRUE, FALSE,
5080 EL_EMC_WALL_15, -1, -1
5083 Xwall_4, TRUE, FALSE,
5084 EL_EMC_WALL_16, -1, -1
5087 Xround_wall_1, TRUE, FALSE,
5088 EL_WALL_SLIPPERY, -1, -1
5091 Xround_wall_2, TRUE, FALSE,
5092 EL_EMC_WALL_SLIPPERY_2, -1, -1
5095 Xround_wall_3, TRUE, FALSE,
5096 EL_EMC_WALL_SLIPPERY_3, -1, -1
5099 Xround_wall_4, TRUE, FALSE,
5100 EL_EMC_WALL_SLIPPERY_4, -1, -1
5103 Xdecor_1, TRUE, FALSE,
5104 EL_EMC_WALL_8, -1, -1
5107 Xdecor_2, TRUE, FALSE,
5108 EL_EMC_WALL_6, -1, -1
5111 Xdecor_3, TRUE, FALSE,
5112 EL_EMC_WALL_4, -1, -1
5115 Xdecor_4, TRUE, FALSE,
5116 EL_EMC_WALL_7, -1, -1
5119 Xdecor_5, TRUE, FALSE,
5120 EL_EMC_WALL_5, -1, -1
5123 Xdecor_6, TRUE, FALSE,
5124 EL_EMC_WALL_9, -1, -1
5127 Xdecor_7, TRUE, FALSE,
5128 EL_EMC_WALL_10, -1, -1
5131 Xdecor_8, TRUE, FALSE,
5132 EL_EMC_WALL_1, -1, -1
5135 Xdecor_9, TRUE, FALSE,
5136 EL_EMC_WALL_2, -1, -1
5139 Xdecor_10, TRUE, FALSE,
5140 EL_EMC_WALL_3, -1, -1
5143 Xdecor_11, TRUE, FALSE,
5144 EL_EMC_WALL_11, -1, -1
5147 Xdecor_12, TRUE, FALSE,
5148 EL_EMC_WALL_12, -1, -1
5151 Xalpha_0, TRUE, FALSE,
5152 EL_CHAR('0'), -1, -1
5155 Xalpha_1, TRUE, FALSE,
5156 EL_CHAR('1'), -1, -1
5159 Xalpha_2, TRUE, FALSE,
5160 EL_CHAR('2'), -1, -1
5163 Xalpha_3, TRUE, FALSE,
5164 EL_CHAR('3'), -1, -1
5167 Xalpha_4, TRUE, FALSE,
5168 EL_CHAR('4'), -1, -1
5171 Xalpha_5, TRUE, FALSE,
5172 EL_CHAR('5'), -1, -1
5175 Xalpha_6, TRUE, FALSE,
5176 EL_CHAR('6'), -1, -1
5179 Xalpha_7, TRUE, FALSE,
5180 EL_CHAR('7'), -1, -1
5183 Xalpha_8, TRUE, FALSE,
5184 EL_CHAR('8'), -1, -1
5187 Xalpha_9, TRUE, FALSE,
5188 EL_CHAR('9'), -1, -1
5191 Xalpha_excla, TRUE, FALSE,
5192 EL_CHAR('!'), -1, -1
5195 Xalpha_quote, TRUE, FALSE,
5196 EL_CHAR('"'), -1, -1
5199 Xalpha_comma, TRUE, FALSE,
5200 EL_CHAR(','), -1, -1
5203 Xalpha_minus, TRUE, FALSE,
5204 EL_CHAR('-'), -1, -1
5207 Xalpha_perio, TRUE, FALSE,
5208 EL_CHAR('.'), -1, -1
5211 Xalpha_colon, TRUE, FALSE,
5212 EL_CHAR(':'), -1, -1
5215 Xalpha_quest, TRUE, FALSE,
5216 EL_CHAR('?'), -1, -1
5219 Xalpha_a, TRUE, FALSE,
5220 EL_CHAR('A'), -1, -1
5223 Xalpha_b, TRUE, FALSE,
5224 EL_CHAR('B'), -1, -1
5227 Xalpha_c, TRUE, FALSE,
5228 EL_CHAR('C'), -1, -1
5231 Xalpha_d, TRUE, FALSE,
5232 EL_CHAR('D'), -1, -1
5235 Xalpha_e, TRUE, FALSE,
5236 EL_CHAR('E'), -1, -1
5239 Xalpha_f, TRUE, FALSE,
5240 EL_CHAR('F'), -1, -1
5243 Xalpha_g, TRUE, FALSE,
5244 EL_CHAR('G'), -1, -1
5247 Xalpha_h, TRUE, FALSE,
5248 EL_CHAR('H'), -1, -1
5251 Xalpha_i, TRUE, FALSE,
5252 EL_CHAR('I'), -1, -1
5255 Xalpha_j, TRUE, FALSE,
5256 EL_CHAR('J'), -1, -1
5259 Xalpha_k, TRUE, FALSE,
5260 EL_CHAR('K'), -1, -1
5263 Xalpha_l, TRUE, FALSE,
5264 EL_CHAR('L'), -1, -1
5267 Xalpha_m, TRUE, FALSE,
5268 EL_CHAR('M'), -1, -1
5271 Xalpha_n, TRUE, FALSE,
5272 EL_CHAR('N'), -1, -1
5275 Xalpha_o, TRUE, FALSE,
5276 EL_CHAR('O'), -1, -1
5279 Xalpha_p, TRUE, FALSE,
5280 EL_CHAR('P'), -1, -1
5283 Xalpha_q, TRUE, FALSE,
5284 EL_CHAR('Q'), -1, -1
5287 Xalpha_r, TRUE, FALSE,
5288 EL_CHAR('R'), -1, -1
5291 Xalpha_s, TRUE, FALSE,
5292 EL_CHAR('S'), -1, -1
5295 Xalpha_t, TRUE, FALSE,
5296 EL_CHAR('T'), -1, -1
5299 Xalpha_u, TRUE, FALSE,
5300 EL_CHAR('U'), -1, -1
5303 Xalpha_v, TRUE, FALSE,
5304 EL_CHAR('V'), -1, -1
5307 Xalpha_w, TRUE, FALSE,
5308 EL_CHAR('W'), -1, -1
5311 Xalpha_x, TRUE, FALSE,
5312 EL_CHAR('X'), -1, -1
5315 Xalpha_y, TRUE, FALSE,
5316 EL_CHAR('Y'), -1, -1
5319 Xalpha_z, TRUE, FALSE,
5320 EL_CHAR('Z'), -1, -1
5323 Xalpha_arrow_e, TRUE, FALSE,
5324 EL_CHAR('>'), -1, -1
5327 Xalpha_arrow_w, TRUE, FALSE,
5328 EL_CHAR('<'), -1, -1
5331 Xalpha_copyr, TRUE, FALSE,
5332 EL_CHAR('©'), -1, -1
5336 Xboom_bug, FALSE, FALSE,
5337 EL_BUG, ACTION_EXPLODING, -1
5340 Xboom_bomb, FALSE, FALSE,
5341 EL_BOMB, ACTION_EXPLODING, -1
5344 Xboom_android, FALSE, FALSE,
5345 EL_EMC_ANDROID, ACTION_OTHER, -1
5348 Xboom_1, FALSE, FALSE,
5349 EL_DEFAULT, ACTION_EXPLODING, -1
5352 Xboom_2, FALSE, FALSE,
5353 EL_DEFAULT, ACTION_EXPLODING, -1
5356 Znormal, FALSE, FALSE,
5360 Zdynamite, FALSE, FALSE,
5364 Zplayer, FALSE, FALSE,
5368 ZBORDER, FALSE, FALSE,
5378 static struct Mapping_EM_to_RND_player
5387 em_player_mapping_list[] =
5391 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5395 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5399 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5403 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5407 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5411 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5415 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5419 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5423 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5427 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5431 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5435 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5439 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5443 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5447 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5451 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5455 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5459 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5463 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5467 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5471 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5475 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5479 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5483 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5487 EL_PLAYER_1, ACTION_DEFAULT, -1,
5491 EL_PLAYER_2, ACTION_DEFAULT, -1,
5495 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5499 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5503 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5507 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5511 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5515 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5519 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5523 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5527 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5531 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5535 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5539 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5543 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5547 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5551 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5555 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5559 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5563 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5567 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5571 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5575 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5579 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5583 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5587 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5591 EL_PLAYER_3, ACTION_DEFAULT, -1,
5595 EL_PLAYER_4, ACTION_DEFAULT, -1,
5604 int map_element_RND_to_EM(int element_rnd)
5606 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5607 static boolean mapping_initialized = FALSE;
5609 if (!mapping_initialized)
5613 /* return "Xalpha_quest" for all undefined elements in mapping array */
5614 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5615 mapping_RND_to_EM[i] = Xalpha_quest;
5617 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5618 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5619 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5620 em_object_mapping_list[i].element_em;
5622 mapping_initialized = TRUE;
5625 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5626 return mapping_RND_to_EM[element_rnd];
5628 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5633 int map_element_EM_to_RND(int element_em)
5635 static unsigned short mapping_EM_to_RND[TILE_MAX];
5636 static boolean mapping_initialized = FALSE;
5638 if (!mapping_initialized)
5642 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5643 for (i = 0; i < TILE_MAX; i++)
5644 mapping_EM_to_RND[i] = EL_UNKNOWN;
5646 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5647 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5648 em_object_mapping_list[i].element_rnd;
5650 mapping_initialized = TRUE;
5653 if (element_em >= 0 && element_em < TILE_MAX)
5654 return mapping_EM_to_RND[element_em];
5656 Error(ERR_WARN, "invalid EM level element %d", element_em);
5661 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5663 struct LevelInfo_EM *level_em = level->native_em_level;
5664 struct LEVEL *lev = level_em->lev;
5667 for (i = 0; i < TILE_MAX; i++)
5668 lev->android_array[i] = Xblank;
5670 for (i = 0; i < level->num_android_clone_elements; i++)
5672 int element_rnd = level->android_clone_element[i];
5673 int element_em = map_element_RND_to_EM(element_rnd);
5675 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5676 if (em_object_mapping_list[j].element_rnd == element_rnd)
5677 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5681 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5683 struct LevelInfo_EM *level_em = level->native_em_level;
5684 struct LEVEL *lev = level_em->lev;
5687 level->num_android_clone_elements = 0;
5689 for (i = 0; i < TILE_MAX; i++)
5691 int element_em = lev->android_array[i];
5693 boolean element_found = FALSE;
5695 if (element_em == Xblank)
5698 element_rnd = map_element_EM_to_RND(element_em);
5700 for (j = 0; j < level->num_android_clone_elements; j++)
5701 if (level->android_clone_element[j] == element_rnd)
5702 element_found = TRUE;
5706 level->android_clone_element[level->num_android_clone_elements++] =
5709 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5714 if (level->num_android_clone_elements == 0)
5716 level->num_android_clone_elements = 1;
5717 level->android_clone_element[0] = EL_EMPTY;
5721 int map_direction_RND_to_EM(int direction)
5723 return (direction == MV_UP ? 0 :
5724 direction == MV_RIGHT ? 1 :
5725 direction == MV_DOWN ? 2 :
5726 direction == MV_LEFT ? 3 :
5730 int map_direction_EM_to_RND(int direction)
5732 return (direction == 0 ? MV_UP :
5733 direction == 1 ? MV_RIGHT :
5734 direction == 2 ? MV_DOWN :
5735 direction == 3 ? MV_LEFT :
5739 int get_next_element(int element)
5743 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5744 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5745 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5746 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5747 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5748 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5749 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5750 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5751 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5752 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5753 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5755 default: return element;
5760 int el_act_dir2img(int element, int action, int direction)
5762 element = GFX_ELEMENT(element);
5764 if (direction == MV_NONE)
5765 return element_info[element].graphic[action];
5767 direction = MV_DIR_TO_BIT(direction);
5769 return element_info[element].direction_graphic[action][direction];
5772 int el_act_dir2img(int element, int action, int direction)
5774 element = GFX_ELEMENT(element);
5775 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5777 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5778 return element_info[element].direction_graphic[action][direction];
5783 static int el_act_dir2crm(int element, int action, int direction)
5785 element = GFX_ELEMENT(element);
5787 if (direction == MV_NONE)
5788 return element_info[element].crumbled[action];
5790 direction = MV_DIR_TO_BIT(direction);
5792 return element_info[element].direction_crumbled[action][direction];
5795 static int el_act_dir2crm(int element, int action, int direction)
5797 element = GFX_ELEMENT(element);
5798 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5800 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5801 return element_info[element].direction_crumbled[action][direction];
5805 int el_act2img(int element, int action)
5807 element = GFX_ELEMENT(element);
5809 return element_info[element].graphic[action];
5812 int el_act2crm(int element, int action)
5814 element = GFX_ELEMENT(element);
5816 return element_info[element].crumbled[action];
5819 int el_dir2img(int element, int direction)
5821 element = GFX_ELEMENT(element);
5823 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5826 int el2baseimg(int element)
5828 return element_info[element].graphic[ACTION_DEFAULT];
5831 int el2img(int element)
5833 element = GFX_ELEMENT(element);
5835 return element_info[element].graphic[ACTION_DEFAULT];
5838 int el2edimg(int element)
5840 element = GFX_ELEMENT(element);
5842 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5845 int el2preimg(int element)
5847 element = GFX_ELEMENT(element);
5849 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5852 int el2panelimg(int element)
5854 element = GFX_ELEMENT(element);
5856 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5859 int font2baseimg(int font_nr)
5861 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5864 int getBeltNrFromBeltElement(int element)
5866 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5867 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5868 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5871 int getBeltNrFromBeltActiveElement(int element)
5873 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5874 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5875 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5878 int getBeltNrFromBeltSwitchElement(int element)
5880 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5881 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5882 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5885 int getBeltDirNrFromBeltElement(int element)
5887 static int belt_base_element[4] =
5889 EL_CONVEYOR_BELT_1_LEFT,
5890 EL_CONVEYOR_BELT_2_LEFT,
5891 EL_CONVEYOR_BELT_3_LEFT,
5892 EL_CONVEYOR_BELT_4_LEFT
5895 int belt_nr = getBeltNrFromBeltElement(element);
5896 int belt_dir_nr = element - belt_base_element[belt_nr];
5898 return (belt_dir_nr % 3);
5901 int getBeltDirNrFromBeltSwitchElement(int element)
5903 static int belt_base_element[4] =
5905 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5906 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5907 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5908 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5911 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5912 int belt_dir_nr = element - belt_base_element[belt_nr];
5914 return (belt_dir_nr % 3);
5917 int getBeltDirFromBeltElement(int element)
5919 static int belt_move_dir[3] =
5926 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5928 return belt_move_dir[belt_dir_nr];
5931 int getBeltDirFromBeltSwitchElement(int element)
5933 static int belt_move_dir[3] =
5940 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5942 return belt_move_dir[belt_dir_nr];
5945 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5947 static int belt_base_element[4] =
5949 EL_CONVEYOR_BELT_1_LEFT,
5950 EL_CONVEYOR_BELT_2_LEFT,
5951 EL_CONVEYOR_BELT_3_LEFT,
5952 EL_CONVEYOR_BELT_4_LEFT
5955 return belt_base_element[belt_nr] + belt_dir_nr;
5958 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5960 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5962 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5965 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5967 static int belt_base_element[4] =
5969 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5970 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5971 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5972 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5975 return belt_base_element[belt_nr] + belt_dir_nr;
5978 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5980 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5982 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5985 int getNumActivePlayers_EM()
5987 int num_players = 0;
5993 for (i = 0; i < MAX_PLAYERS; i++)
5994 if (tape.player_participates[i])
6000 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6002 int game_frame_delay_value;
6004 game_frame_delay_value =
6005 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6006 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6009 if (tape.playing && tape.warp_forward && !tape.pausing)
6010 game_frame_delay_value = 0;
6012 return game_frame_delay_value;
6015 unsigned int InitRND(long seed)
6017 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6018 return InitEngineRandom_EM(seed);
6020 return InitEngineRandom_RND(seed);
6024 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6025 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6028 inline static int get_effective_element_EM(int tile, int frame_em)
6030 int element = object_mapping[tile].element_rnd;
6031 int action = object_mapping[tile].action;
6032 boolean is_backside = object_mapping[tile].is_backside;
6033 boolean action_removing = (action == ACTION_DIGGING ||
6034 action == ACTION_SNAPPING ||
6035 action == ACTION_COLLECTING);
6041 case Yacid_splash_eB:
6042 case Yacid_splash_wB:
6043 return (frame_em > 5 ? EL_EMPTY : element);
6049 else /* frame_em == 7 */
6053 case Yacid_splash_eB:
6054 case Yacid_splash_wB:
6057 case Yemerald_stone:
6060 case Ydiamond_stone:
6064 case Xdrip_stretchB:
6083 case Xsand_stonein_1:
6084 case Xsand_stonein_2:
6085 case Xsand_stonein_3:
6086 case Xsand_stonein_4:
6090 return (is_backside || action_removing ? EL_EMPTY : element);
6095 inline static boolean check_linear_animation_EM(int tile)
6099 case Xsand_stonesand_1:
6100 case Xsand_stonesand_quickout_1:
6101 case Xsand_sandstone_1:
6102 case Xsand_stonein_1:
6103 case Xsand_stoneout_1:
6128 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6129 boolean has_crumbled_graphics,
6130 int crumbled, int sync_frame)
6132 /* if element can be crumbled, but certain action graphics are just empty
6133 space (like instantly snapping sand to empty space in 1 frame), do not
6134 treat these empty space graphics as crumbled graphics in EMC engine */
6135 if (crumbled == IMG_EMPTY_SPACE)
6136 has_crumbled_graphics = FALSE;
6138 if (has_crumbled_graphics)
6140 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6141 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6142 g_crumbled->anim_delay,
6143 g_crumbled->anim_mode,
6144 g_crumbled->anim_start_frame,
6147 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6148 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6150 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6152 g_em->has_crumbled_graphics = TRUE;
6156 g_em->crumbled_bitmap = NULL;
6157 g_em->crumbled_src_x = 0;
6158 g_em->crumbled_src_y = 0;
6159 g_em->crumbled_border_size = 0;
6161 g_em->has_crumbled_graphics = FALSE;
6165 void ResetGfxAnimation_EM(int x, int y, int tile)
6170 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6171 int tile, int frame_em, int x, int y)
6173 int action = object_mapping[tile].action;
6175 int direction = object_mapping[tile].direction;
6176 int effective_element = get_effective_element_EM(tile, frame_em);
6177 int graphic = (direction == MV_NONE ?
6178 el_act2img(effective_element, action) :
6179 el_act_dir2img(effective_element, action, direction));
6180 struct GraphicInfo *g = &graphic_info[graphic];
6183 boolean action_removing = (action == ACTION_DIGGING ||
6184 action == ACTION_SNAPPING ||
6185 action == ACTION_COLLECTING);
6186 boolean action_moving = (action == ACTION_FALLING ||
6187 action == ACTION_MOVING ||
6188 action == ACTION_PUSHING ||
6189 action == ACTION_EATING ||
6190 action == ACTION_FILLING ||
6191 action == ACTION_EMPTYING);
6192 boolean action_falling = (action == ACTION_FALLING ||
6193 action == ACTION_FILLING ||
6194 action == ACTION_EMPTYING);
6197 if (tile == Xsand_stonesand_1 ||
6198 tile == Xsand_stonesand_2 ||
6199 tile == Xsand_stonesand_3 ||
6200 tile == Xsand_stonesand_4)
6201 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6205 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6209 // printf("::: resetting... [%d]\n", tile);
6212 if (action_removing || check_linear_animation_EM(tile))
6214 GfxFrame[x][y] = frame_em;
6216 // printf("::: resetting... [%d]\n", tile);
6219 else if (action_moving)
6221 boolean is_backside = object_mapping[tile].is_backside;
6225 int direction = object_mapping[tile].direction;
6226 int move_dir = (action_falling ? MV_DOWN : direction);
6230 if (move_dir == MV_LEFT)
6231 GfxFrame[x - 1][y] = GfxFrame[x][y];
6232 else if (move_dir == MV_RIGHT)
6233 GfxFrame[x + 1][y] = GfxFrame[x][y];
6234 else if (move_dir == MV_UP)
6235 GfxFrame[x][y - 1] = GfxFrame[x][y];
6236 else if (move_dir == MV_DOWN)
6237 GfxFrame[x][y + 1] = GfxFrame[x][y];
6244 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6245 if (tile == Xsand_stonesand_quickout_1 ||
6246 tile == Xsand_stonesand_quickout_2)
6251 if (tile == Xsand_stonesand_1 ||
6252 tile == Xsand_stonesand_2 ||
6253 tile == Xsand_stonesand_3 ||
6254 tile == Xsand_stonesand_4)
6255 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6259 if (graphic_info[graphic].anim_global_sync)
6260 sync_frame = FrameCounter;
6261 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6262 sync_frame = GfxFrame[x][y];
6264 sync_frame = 0; /* playfield border (pseudo steel) */
6266 SetRandomAnimationValue(x, y);
6268 int frame = getAnimationFrame(g->anim_frames,
6271 g->anim_start_frame,
6274 g_em->unique_identifier =
6275 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6279 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6280 int tile, int frame_em, int x, int y)
6282 int action = object_mapping[tile].action;
6283 int direction = object_mapping[tile].direction;
6284 int effective_element = get_effective_element_EM(tile, frame_em);
6285 int graphic = (direction == MV_NONE ?
6286 el_act2img(effective_element, action) :
6287 el_act_dir2img(effective_element, action, direction));
6288 int crumbled = (direction == MV_NONE ?
6289 el_act2crm(effective_element, action) :
6290 el_act_dir2crm(effective_element, action, direction));
6291 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6292 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6293 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6294 struct GraphicInfo *g = &graphic_info[graphic];
6296 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6301 if (frame_em == 0) /* reset animation frame for certain elements */
6303 if (check_linear_animation_EM(tile))
6308 if (graphic_info[graphic].anim_global_sync)
6309 sync_frame = FrameCounter;
6310 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6311 sync_frame = GfxFrame[x][y];
6313 sync_frame = 0; /* playfield border (pseudo steel) */
6315 SetRandomAnimationValue(x, y);
6317 int frame = getAnimationFrame(g->anim_frames,
6320 g->anim_start_frame,
6323 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6324 &g_em->src_x, &g_em->src_y, FALSE);
6326 /* (updating the "crumbled" graphic definitions is probably not really needed,
6327 as animations for crumbled graphics can't be longer than one EMC cycle) */
6329 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6334 g_em->crumbled_bitmap = NULL;
6335 g_em->crumbled_src_x = 0;
6336 g_em->crumbled_src_y = 0;
6338 g_em->has_crumbled_graphics = FALSE;
6340 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6342 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6343 g_crumbled->anim_delay,
6344 g_crumbled->anim_mode,
6345 g_crumbled->anim_start_frame,
6348 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6349 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6351 g_em->has_crumbled_graphics = TRUE;
6356 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
6357 int player_nr, int anim, int frame_em)
6359 int element = player_mapping[player_nr][anim].element_rnd;
6360 int action = player_mapping[player_nr][anim].action;
6361 int direction = player_mapping[player_nr][anim].direction;
6362 int graphic = (direction == MV_NONE ?
6363 el_act2img(element, action) :
6364 el_act_dir2img(element, action, direction));
6365 struct GraphicInfo *g = &graphic_info[graphic];
6368 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6370 stored_player[player_nr].StepFrame = frame_em;
6372 sync_frame = stored_player[player_nr].Frame;
6374 int frame = getAnimationFrame(g->anim_frames,
6377 g->anim_start_frame,
6380 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6381 &g_em->src_x, &g_em->src_y, FALSE);
6384 printf("::: %d: %d, %d [%d]\n",
6386 stored_player[player_nr].Frame,
6387 stored_player[player_nr].StepFrame,
6392 void InitGraphicInfo_EM(void)
6395 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6396 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6401 int num_em_gfx_errors = 0;
6403 if (graphic_info_em_object[0][0].bitmap == NULL)
6405 /* EM graphics not yet initialized in em_open_all() */
6410 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6413 /* always start with reliable default values */
6414 for (i = 0; i < TILE_MAX; i++)
6416 object_mapping[i].element_rnd = EL_UNKNOWN;
6417 object_mapping[i].is_backside = FALSE;
6418 object_mapping[i].action = ACTION_DEFAULT;
6419 object_mapping[i].direction = MV_NONE;
6422 /* always start with reliable default values */
6423 for (p = 0; p < MAX_PLAYERS; p++)
6425 for (i = 0; i < SPR_MAX; i++)
6427 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6428 player_mapping[p][i].action = ACTION_DEFAULT;
6429 player_mapping[p][i].direction = MV_NONE;
6433 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6435 int e = em_object_mapping_list[i].element_em;
6437 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6438 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6440 if (em_object_mapping_list[i].action != -1)
6441 object_mapping[e].action = em_object_mapping_list[i].action;
6443 if (em_object_mapping_list[i].direction != -1)
6444 object_mapping[e].direction =
6445 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6448 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6450 int a = em_player_mapping_list[i].action_em;
6451 int p = em_player_mapping_list[i].player_nr;
6453 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6455 if (em_player_mapping_list[i].action != -1)
6456 player_mapping[p][a].action = em_player_mapping_list[i].action;
6458 if (em_player_mapping_list[i].direction != -1)
6459 player_mapping[p][a].direction =
6460 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6463 for (i = 0; i < TILE_MAX; i++)
6465 int element = object_mapping[i].element_rnd;
6466 int action = object_mapping[i].action;
6467 int direction = object_mapping[i].direction;
6468 boolean is_backside = object_mapping[i].is_backside;
6470 boolean action_removing = (action == ACTION_DIGGING ||
6471 action == ACTION_SNAPPING ||
6472 action == ACTION_COLLECTING);
6474 boolean action_exploding = ((action == ACTION_EXPLODING ||
6475 action == ACTION_SMASHED_BY_ROCK ||
6476 action == ACTION_SMASHED_BY_SPRING) &&
6477 element != EL_DIAMOND);
6478 boolean action_active = (action == ACTION_ACTIVE);
6479 boolean action_other = (action == ACTION_OTHER);
6481 for (j = 0; j < 8; j++)
6484 int effective_element = get_effective_element_EM(i, j);
6486 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6487 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6489 i == Xdrip_stretch ? element :
6490 i == Xdrip_stretchB ? element :
6491 i == Ydrip_s1 ? element :
6492 i == Ydrip_s1B ? element :
6493 i == Xball_1B ? element :
6494 i == Xball_2 ? element :
6495 i == Xball_2B ? element :
6496 i == Yball_eat ? element :
6497 i == Ykey_1_eat ? element :
6498 i == Ykey_2_eat ? element :
6499 i == Ykey_3_eat ? element :
6500 i == Ykey_4_eat ? element :
6501 i == Ykey_5_eat ? element :
6502 i == Ykey_6_eat ? element :
6503 i == Ykey_7_eat ? element :
6504 i == Ykey_8_eat ? element :
6505 i == Ylenses_eat ? element :
6506 i == Ymagnify_eat ? element :
6507 i == Ygrass_eat ? element :
6508 i == Ydirt_eat ? element :
6509 i == Yemerald_stone ? EL_EMERALD :
6510 i == Ydiamond_stone ? EL_ROCK :
6511 i == Xsand_stonein_1 ? element :
6512 i == Xsand_stonein_2 ? element :
6513 i == Xsand_stonein_3 ? element :
6514 i == Xsand_stonein_4 ? element :
6515 is_backside ? EL_EMPTY :
6516 action_removing ? EL_EMPTY :
6519 int effective_action = (j < 7 ? action :
6520 i == Xdrip_stretch ? action :
6521 i == Xdrip_stretchB ? action :
6522 i == Ydrip_s1 ? action :
6523 i == Ydrip_s1B ? action :
6524 i == Xball_1B ? action :
6525 i == Xball_2 ? action :
6526 i == Xball_2B ? action :
6527 i == Yball_eat ? action :
6528 i == Ykey_1_eat ? action :
6529 i == Ykey_2_eat ? action :
6530 i == Ykey_3_eat ? action :
6531 i == Ykey_4_eat ? action :
6532 i == Ykey_5_eat ? action :
6533 i == Ykey_6_eat ? action :
6534 i == Ykey_7_eat ? action :
6535 i == Ykey_8_eat ? action :
6536 i == Ylenses_eat ? action :
6537 i == Ymagnify_eat ? action :
6538 i == Ygrass_eat ? action :
6539 i == Ydirt_eat ? action :
6540 i == Xsand_stonein_1 ? action :
6541 i == Xsand_stonein_2 ? action :
6542 i == Xsand_stonein_3 ? action :
6543 i == Xsand_stonein_4 ? action :
6544 i == Xsand_stoneout_1 ? action :
6545 i == Xsand_stoneout_2 ? action :
6546 i == Xboom_android ? ACTION_EXPLODING :
6547 action_exploding ? ACTION_EXPLODING :
6548 action_active ? action :
6549 action_other ? action :
6551 int graphic = (el_act_dir2img(effective_element, effective_action,
6553 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6555 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6556 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6557 boolean has_action_graphics = (graphic != base_graphic);
6558 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6559 struct GraphicInfo *g = &graphic_info[graphic];
6561 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6563 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6566 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6567 boolean special_animation = (action != ACTION_DEFAULT &&
6568 g->anim_frames == 3 &&
6569 g->anim_delay == 2 &&
6570 g->anim_mode & ANIM_LINEAR);
6571 int sync_frame = (i == Xdrip_stretch ? 7 :
6572 i == Xdrip_stretchB ? 7 :
6573 i == Ydrip_s2 ? j + 8 :
6574 i == Ydrip_s2B ? j + 8 :
6583 i == Xfake_acid_1 ? 0 :
6584 i == Xfake_acid_2 ? 10 :
6585 i == Xfake_acid_3 ? 20 :
6586 i == Xfake_acid_4 ? 30 :
6587 i == Xfake_acid_5 ? 40 :
6588 i == Xfake_acid_6 ? 50 :
6589 i == Xfake_acid_7 ? 60 :
6590 i == Xfake_acid_8 ? 70 :
6592 i == Xball_2B ? j + 8 :
6593 i == Yball_eat ? j + 1 :
6594 i == Ykey_1_eat ? j + 1 :
6595 i == Ykey_2_eat ? j + 1 :
6596 i == Ykey_3_eat ? j + 1 :
6597 i == Ykey_4_eat ? j + 1 :
6598 i == Ykey_5_eat ? j + 1 :
6599 i == Ykey_6_eat ? j + 1 :
6600 i == Ykey_7_eat ? j + 1 :
6601 i == Ykey_8_eat ? j + 1 :
6602 i == Ylenses_eat ? j + 1 :
6603 i == Ymagnify_eat ? j + 1 :
6604 i == Ygrass_eat ? j + 1 :
6605 i == Ydirt_eat ? j + 1 :
6606 i == Xamoeba_1 ? 0 :
6607 i == Xamoeba_2 ? 1 :
6608 i == Xamoeba_3 ? 2 :
6609 i == Xamoeba_4 ? 3 :
6610 i == Xamoeba_5 ? 0 :
6611 i == Xamoeba_6 ? 1 :
6612 i == Xamoeba_7 ? 2 :
6613 i == Xamoeba_8 ? 3 :
6614 i == Xexit_2 ? j + 8 :
6615 i == Xexit_3 ? j + 16 :
6616 i == Xdynamite_1 ? 0 :
6617 i == Xdynamite_2 ? 8 :
6618 i == Xdynamite_3 ? 16 :
6619 i == Xdynamite_4 ? 24 :
6620 i == Xsand_stonein_1 ? j + 1 :
6621 i == Xsand_stonein_2 ? j + 9 :
6622 i == Xsand_stonein_3 ? j + 17 :
6623 i == Xsand_stonein_4 ? j + 25 :
6624 i == Xsand_stoneout_1 && j == 0 ? 0 :
6625 i == Xsand_stoneout_1 && j == 1 ? 0 :
6626 i == Xsand_stoneout_1 && j == 2 ? 1 :
6627 i == Xsand_stoneout_1 && j == 3 ? 2 :
6628 i == Xsand_stoneout_1 && j == 4 ? 2 :
6629 i == Xsand_stoneout_1 && j == 5 ? 3 :
6630 i == Xsand_stoneout_1 && j == 6 ? 4 :
6631 i == Xsand_stoneout_1 && j == 7 ? 4 :
6632 i == Xsand_stoneout_2 && j == 0 ? 5 :
6633 i == Xsand_stoneout_2 && j == 1 ? 6 :
6634 i == Xsand_stoneout_2 && j == 2 ? 7 :
6635 i == Xsand_stoneout_2 && j == 3 ? 8 :
6636 i == Xsand_stoneout_2 && j == 4 ? 9 :
6637 i == Xsand_stoneout_2 && j == 5 ? 11 :
6638 i == Xsand_stoneout_2 && j == 6 ? 13 :
6639 i == Xsand_stoneout_2 && j == 7 ? 15 :
6640 i == Xboom_bug && j == 1 ? 2 :
6641 i == Xboom_bug && j == 2 ? 2 :
6642 i == Xboom_bug && j == 3 ? 4 :
6643 i == Xboom_bug && j == 4 ? 4 :
6644 i == Xboom_bug && j == 5 ? 2 :
6645 i == Xboom_bug && j == 6 ? 2 :
6646 i == Xboom_bug && j == 7 ? 0 :
6647 i == Xboom_bomb && j == 1 ? 2 :
6648 i == Xboom_bomb && j == 2 ? 2 :
6649 i == Xboom_bomb && j == 3 ? 4 :
6650 i == Xboom_bomb && j == 4 ? 4 :
6651 i == Xboom_bomb && j == 5 ? 2 :
6652 i == Xboom_bomb && j == 6 ? 2 :
6653 i == Xboom_bomb && j == 7 ? 0 :
6654 i == Xboom_android && j == 7 ? 6 :
6655 i == Xboom_1 && j == 1 ? 2 :
6656 i == Xboom_1 && j == 2 ? 2 :
6657 i == Xboom_1 && j == 3 ? 4 :
6658 i == Xboom_1 && j == 4 ? 4 :
6659 i == Xboom_1 && j == 5 ? 6 :
6660 i == Xboom_1 && j == 6 ? 6 :
6661 i == Xboom_1 && j == 7 ? 8 :
6662 i == Xboom_2 && j == 0 ? 8 :
6663 i == Xboom_2 && j == 1 ? 8 :
6664 i == Xboom_2 && j == 2 ? 10 :
6665 i == Xboom_2 && j == 3 ? 10 :
6666 i == Xboom_2 && j == 4 ? 10 :
6667 i == Xboom_2 && j == 5 ? 12 :
6668 i == Xboom_2 && j == 6 ? 12 :
6669 i == Xboom_2 && j == 7 ? 12 :
6670 special_animation && j == 4 ? 3 :
6671 effective_action != action ? 0 :
6675 Bitmap *debug_bitmap = g_em->bitmap;
6676 int debug_src_x = g_em->src_x;
6677 int debug_src_y = g_em->src_y;
6680 int frame = getAnimationFrame(g->anim_frames,
6683 g->anim_start_frame,
6686 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6687 g->double_movement && is_backside);
6689 g_em->bitmap = src_bitmap;
6690 g_em->src_x = src_x;
6691 g_em->src_y = src_y;
6692 g_em->src_offset_x = 0;
6693 g_em->src_offset_y = 0;
6694 g_em->dst_offset_x = 0;
6695 g_em->dst_offset_y = 0;
6696 g_em->width = TILEX;
6697 g_em->height = TILEY;
6699 g_em->preserve_background = FALSE;
6702 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6707 g_em->crumbled_bitmap = NULL;
6708 g_em->crumbled_src_x = 0;
6709 g_em->crumbled_src_y = 0;
6710 g_em->crumbled_border_size = 0;
6712 g_em->has_crumbled_graphics = FALSE;
6715 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6716 printf("::: empty crumbled: %d [%s], %d, %d\n",
6717 effective_element, element_info[effective_element].token_name,
6718 effective_action, direction);
6721 /* if element can be crumbled, but certain action graphics are just empty
6722 space (like instantly snapping sand to empty space in 1 frame), do not
6723 treat these empty space graphics as crumbled graphics in EMC engine */
6724 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6726 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6727 g_crumbled->anim_delay,
6728 g_crumbled->anim_mode,
6729 g_crumbled->anim_start_frame,
6732 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
6734 g_em->has_crumbled_graphics = TRUE;
6735 g_em->crumbled_bitmap = src_bitmap;
6736 g_em->crumbled_src_x = src_x;
6737 g_em->crumbled_src_y = src_y;
6738 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6742 if (g_em == &graphic_info_em_object[207][0])
6743 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
6744 graphic_info_em_object[207][0].crumbled_src_x,
6745 graphic_info_em_object[207][0].crumbled_src_y,
6747 crumbled, frame, src_x, src_y,
6752 g->anim_start_frame,
6754 gfx.anim_random_frame,
6759 printf("::: EMC tile %d is crumbled\n", i);
6765 if (element == EL_ROCK &&
6766 effective_action == ACTION_FILLING)
6767 printf("::: has_action_graphics == %d\n", has_action_graphics);
6770 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6771 effective_action == ACTION_MOVING ||
6772 effective_action == ACTION_PUSHING ||
6773 effective_action == ACTION_EATING)) ||
6774 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6775 effective_action == ACTION_EMPTYING)))
6778 (effective_action == ACTION_FALLING ||
6779 effective_action == ACTION_FILLING ||
6780 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6781 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6782 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6783 int num_steps = (i == Ydrip_s1 ? 16 :
6784 i == Ydrip_s1B ? 16 :
6785 i == Ydrip_s2 ? 16 :
6786 i == Ydrip_s2B ? 16 :
6787 i == Xsand_stonein_1 ? 32 :
6788 i == Xsand_stonein_2 ? 32 :
6789 i == Xsand_stonein_3 ? 32 :
6790 i == Xsand_stonein_4 ? 32 :
6791 i == Xsand_stoneout_1 ? 16 :
6792 i == Xsand_stoneout_2 ? 16 : 8);
6793 int cx = ABS(dx) * (TILEX / num_steps);
6794 int cy = ABS(dy) * (TILEY / num_steps);
6795 int step_frame = (i == Ydrip_s2 ? j + 8 :
6796 i == Ydrip_s2B ? j + 8 :
6797 i == Xsand_stonein_2 ? j + 8 :
6798 i == Xsand_stonein_3 ? j + 16 :
6799 i == Xsand_stonein_4 ? j + 24 :
6800 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6801 int step = (is_backside ? step_frame : num_steps - step_frame);
6803 if (is_backside) /* tile where movement starts */
6805 if (dx < 0 || dy < 0)
6807 g_em->src_offset_x = cx * step;
6808 g_em->src_offset_y = cy * step;
6812 g_em->dst_offset_x = cx * step;
6813 g_em->dst_offset_y = cy * step;
6816 else /* tile where movement ends */
6818 if (dx < 0 || dy < 0)
6820 g_em->dst_offset_x = cx * step;
6821 g_em->dst_offset_y = cy * step;
6825 g_em->src_offset_x = cx * step;
6826 g_em->src_offset_y = cy * step;
6830 g_em->width = TILEX - cx * step;
6831 g_em->height = TILEY - cy * step;
6834 /* create unique graphic identifier to decide if tile must be redrawn */
6835 /* bit 31 - 16 (16 bit): EM style graphic
6836 bit 15 - 12 ( 4 bit): EM style frame
6837 bit 11 - 6 ( 6 bit): graphic width
6838 bit 5 - 0 ( 6 bit): graphic height */
6839 g_em->unique_identifier =
6840 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6844 /* skip check for EMC elements not contained in original EMC artwork */
6845 if (element == EL_EMC_FAKE_ACID)
6848 if (g_em->bitmap != debug_bitmap ||
6849 g_em->src_x != debug_src_x ||
6850 g_em->src_y != debug_src_y ||
6851 g_em->src_offset_x != 0 ||
6852 g_em->src_offset_y != 0 ||
6853 g_em->dst_offset_x != 0 ||
6854 g_em->dst_offset_y != 0 ||
6855 g_em->width != TILEX ||
6856 g_em->height != TILEY)
6858 static int last_i = -1;
6866 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6867 i, element, element_info[element].token_name,
6868 element_action_info[effective_action].suffix, direction);
6870 if (element != effective_element)
6871 printf(" [%d ('%s')]",
6873 element_info[effective_element].token_name);
6877 if (g_em->bitmap != debug_bitmap)
6878 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6879 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6881 if (g_em->src_x != debug_src_x ||
6882 g_em->src_y != debug_src_y)
6883 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6884 j, (is_backside ? 'B' : 'F'),
6885 g_em->src_x, g_em->src_y,
6886 g_em->src_x / 32, g_em->src_y / 32,
6887 debug_src_x, debug_src_y,
6888 debug_src_x / 32, debug_src_y / 32);
6890 if (g_em->src_offset_x != 0 ||
6891 g_em->src_offset_y != 0 ||
6892 g_em->dst_offset_x != 0 ||
6893 g_em->dst_offset_y != 0)
6894 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6896 g_em->src_offset_x, g_em->src_offset_y,
6897 g_em->dst_offset_x, g_em->dst_offset_y);
6899 if (g_em->width != TILEX ||
6900 g_em->height != TILEY)
6901 printf(" %d (%d): size %d,%d should be %d,%d\n",
6903 g_em->width, g_em->height, TILEX, TILEY);
6905 num_em_gfx_errors++;
6912 for (i = 0; i < TILE_MAX; i++)
6914 for (j = 0; j < 8; j++)
6916 int element = object_mapping[i].element_rnd;
6917 int action = object_mapping[i].action;
6918 int direction = object_mapping[i].direction;
6919 boolean is_backside = object_mapping[i].is_backside;
6920 int graphic_action = el_act_dir2img(element, action, direction);
6921 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6923 if ((action == ACTION_SMASHED_BY_ROCK ||
6924 action == ACTION_SMASHED_BY_SPRING ||
6925 action == ACTION_EATING) &&
6926 graphic_action == graphic_default)
6928 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6929 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6930 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6931 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6934 /* no separate animation for "smashed by rock" -- use rock instead */
6935 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6936 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6938 g_em->bitmap = g_xx->bitmap;
6939 g_em->src_x = g_xx->src_x;
6940 g_em->src_y = g_xx->src_y;
6941 g_em->src_offset_x = g_xx->src_offset_x;
6942 g_em->src_offset_y = g_xx->src_offset_y;
6943 g_em->dst_offset_x = g_xx->dst_offset_x;
6944 g_em->dst_offset_y = g_xx->dst_offset_y;
6945 g_em->width = g_xx->width;
6946 g_em->height = g_xx->height;
6947 g_em->unique_identifier = g_xx->unique_identifier;
6950 g_em->preserve_background = TRUE;
6955 for (p = 0; p < MAX_PLAYERS; p++)
6957 for (i = 0; i < SPR_MAX; i++)
6959 int element = player_mapping[p][i].element_rnd;
6960 int action = player_mapping[p][i].action;
6961 int direction = player_mapping[p][i].direction;
6963 for (j = 0; j < 8; j++)
6965 int effective_element = element;
6966 int effective_action = action;
6967 int graphic = (direction == MV_NONE ?
6968 el_act2img(effective_element, effective_action) :
6969 el_act_dir2img(effective_element, effective_action,
6971 struct GraphicInfo *g = &graphic_info[graphic];
6972 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6978 Bitmap *debug_bitmap = g_em->bitmap;
6979 int debug_src_x = g_em->src_x;
6980 int debug_src_y = g_em->src_y;
6983 int frame = getAnimationFrame(g->anim_frames,
6986 g->anim_start_frame,
6989 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6991 g_em->bitmap = src_bitmap;
6992 g_em->src_x = src_x;
6993 g_em->src_y = src_y;
6994 g_em->src_offset_x = 0;
6995 g_em->src_offset_y = 0;
6996 g_em->dst_offset_x = 0;
6997 g_em->dst_offset_y = 0;
6998 g_em->width = TILEX;
6999 g_em->height = TILEY;
7003 /* skip check for EMC elements not contained in original EMC artwork */
7004 if (element == EL_PLAYER_3 ||
7005 element == EL_PLAYER_4)
7008 if (g_em->bitmap != debug_bitmap ||
7009 g_em->src_x != debug_src_x ||
7010 g_em->src_y != debug_src_y)
7012 static int last_i = -1;
7020 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7021 p, i, element, element_info[element].token_name,
7022 element_action_info[effective_action].suffix, direction);
7024 if (element != effective_element)
7025 printf(" [%d ('%s')]",
7027 element_info[effective_element].token_name);
7031 if (g_em->bitmap != debug_bitmap)
7032 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7033 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7035 if (g_em->src_x != debug_src_x ||
7036 g_em->src_y != debug_src_y)
7037 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7039 g_em->src_x, g_em->src_y,
7040 g_em->src_x / 32, g_em->src_y / 32,
7041 debug_src_x, debug_src_y,
7042 debug_src_x / 32, debug_src_y / 32);
7044 num_em_gfx_errors++;
7054 printf("::: [%d errors found]\n", num_em_gfx_errors);
7060 void PlayMenuSoundExt(int sound)
7062 if (sound == SND_UNDEFINED)
7065 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7066 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7069 if (IS_LOOP_SOUND(sound))
7070 PlaySoundLoop(sound);
7075 void PlayMenuSound()
7077 PlayMenuSoundExt(menu.sound[game_status]);
7080 void PlayMenuSoundStereo(int sound, int stereo_position)
7082 if (sound == SND_UNDEFINED)
7085 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7086 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7089 if (IS_LOOP_SOUND(sound))
7090 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7092 PlaySoundStereo(sound, stereo_position);
7095 void PlayMenuSoundIfLoopExt(int sound)
7097 if (sound == SND_UNDEFINED)
7100 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7101 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7104 if (IS_LOOP_SOUND(sound))
7105 PlaySoundLoop(sound);
7108 void PlayMenuSoundIfLoop()
7110 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7113 void PlayMenuMusicExt(int music)
7115 if (music == MUS_UNDEFINED)
7118 if (!setup.sound_music)
7124 void PlayMenuMusic()
7126 PlayMenuMusicExt(menu.music[game_status]);
7129 void PlaySoundActivating()
7132 PlaySound(SND_MENU_ITEM_ACTIVATING);
7136 void PlaySoundSelecting()
7139 PlaySound(SND_MENU_ITEM_SELECTING);
7143 void ToggleFullscreenIfNeeded()
7145 boolean change_fullscreen = (setup.fullscreen !=
7146 video.fullscreen_enabled);
7147 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7148 !strEqual(setup.fullscreen_mode,
7149 video.fullscreen_mode_current));
7151 if (!video.fullscreen_available)
7155 if (change_fullscreen || change_fullscreen_mode)
7157 if (setup.fullscreen != video.fullscreen_enabled ||
7158 setup.fullscreen_mode != video.fullscreen_mode_current)
7161 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7163 /* save backbuffer content which gets lost when toggling fullscreen mode */
7164 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7167 if (change_fullscreen_mode)
7169 if (setup.fullscreen && video.fullscreen_enabled)
7172 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7174 /* (this is now set in sdl.c) */
7176 video.fullscreen_mode_current = setup.fullscreen_mode;
7178 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7181 /* toggle fullscreen */
7182 ChangeVideoModeIfNeeded(setup.fullscreen);
7184 setup.fullscreen = video.fullscreen_enabled;
7186 /* restore backbuffer content from temporary backbuffer backup bitmap */
7187 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7189 FreeBitmap(tmp_backbuffer);
7192 /* update visible window/screen */
7193 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7195 redraw_mask = REDRAW_ALL;