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_DIRECT, DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = (mode == DRAW_DIRECT ? window : 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;
157 if (force_redraw || setup.direct_draw)
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 if (setup.direct_draw)
164 SetDrawtoField(DRAW_BACKBUFFER);
166 for (xx = BX1; xx <= BX2; xx++)
167 for (yy = BY1; yy <= BY2; yy++)
168 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
169 DrawScreenField(xx, yy);
172 if (setup.direct_draw)
173 SetDrawtoField(DRAW_DIRECT);
176 if (setup.soft_scrolling)
178 int fx = FX, fy = FY;
180 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
181 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
183 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
195 BlitBitmap(drawto, window, x, y, width, height, x, y);
198 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
200 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
202 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
203 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
206 void DrawMaskedBorder_FIELD()
208 if (game_status >= GAME_MODE_TITLE &&
209 game_status <= GAME_MODE_PLAYING &&
210 border.draw_masked[game_status])
211 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
214 void DrawMaskedBorder_DOOR_1()
216 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
217 (game_status != GAME_MODE_EDITOR ||
218 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
219 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
222 void DrawMaskedBorder_DOOR_2()
224 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
225 game_status != GAME_MODE_EDITOR)
226 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
229 void DrawMaskedBorder_DOOR_3()
231 /* currently not available */
234 void DrawMaskedBorder_ALL()
236 DrawMaskedBorder_FIELD();
237 DrawMaskedBorder_DOOR_1();
238 DrawMaskedBorder_DOOR_2();
239 DrawMaskedBorder_DOOR_3();
242 void DrawMaskedBorder(int redraw_mask)
244 /* do not draw masked screen borders when displaying title screens */
245 if (effectiveGameStatus() == GAME_MODE_TITLE)
248 if (redraw_mask & REDRAW_ALL)
249 DrawMaskedBorder_ALL();
252 if (redraw_mask & REDRAW_FIELD)
253 DrawMaskedBorder_FIELD();
254 if (redraw_mask & REDRAW_DOOR_1)
255 DrawMaskedBorder_DOOR_1();
256 if (redraw_mask & REDRAW_DOOR_2)
257 DrawMaskedBorder_DOOR_2();
258 if (redraw_mask & REDRAW_DOOR_3)
259 DrawMaskedBorder_DOOR_3();
266 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
268 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
269 redraw_mask &= ~REDRAW_MAIN;
271 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
272 redraw_mask |= REDRAW_FIELD;
274 if (redraw_mask & REDRAW_FIELD)
275 redraw_mask &= ~REDRAW_TILES;
277 if (redraw_mask == REDRAW_NONE)
280 if (redraw_mask & REDRAW_TILES &&
281 game_status == GAME_MODE_PLAYING &&
282 border.draw_masked[GAME_MODE_PLAYING])
283 redraw_mask |= REDRAW_FIELD;
285 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
287 static boolean last_frame_skipped = FALSE;
288 boolean skip_even_when_not_scrolling = TRUE;
289 boolean just_scrolling = (ScreenMovDir != 0);
290 boolean verbose = FALSE;
292 if (global.fps_slowdown_factor > 1 &&
293 (FrameCounter % global.fps_slowdown_factor) &&
294 (just_scrolling || skip_even_when_not_scrolling))
296 redraw_mask &= ~REDRAW_MAIN;
298 last_frame_skipped = TRUE;
301 printf("FRAME SKIPPED\n");
305 if (last_frame_skipped)
306 redraw_mask |= REDRAW_FIELD;
308 last_frame_skipped = FALSE;
311 printf("frame not skipped\n");
315 /* synchronize X11 graphics at this point; if we would synchronize the
316 display immediately after the buffer switching (after the XFlush),
317 this could mean that we have to wait for the graphics to complete,
318 although we could go on doing calculations for the next frame */
322 /* prevent drawing masked border to backbuffer when using playfield buffer */
323 if (game_status != GAME_MODE_PLAYING ||
324 redraw_mask & REDRAW_FROM_BACKBUFFER ||
325 buffer == backbuffer)
326 DrawMaskedBorder(redraw_mask);
328 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
330 if (redraw_mask & REDRAW_ALL)
332 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
334 redraw_mask = REDRAW_NONE;
337 if (redraw_mask & REDRAW_FIELD)
339 if (game_status != GAME_MODE_PLAYING ||
340 redraw_mask & REDRAW_FROM_BACKBUFFER)
342 BlitBitmap(backbuffer, window,
343 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
347 int fx = FX, fy = FY;
349 if (setup.soft_scrolling)
351 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
352 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
355 if (setup.soft_scrolling ||
356 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
357 ABS(ScreenMovPos) == ScrollStepSize ||
358 redraw_tiles > REDRAWTILES_THRESHOLD)
360 if (border.draw_masked[GAME_MODE_PLAYING])
362 if (buffer != backbuffer)
364 /* copy playfield buffer to backbuffer to add masked border */
365 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
366 DrawMaskedBorder(REDRAW_FIELD);
369 BlitBitmap(backbuffer, window,
370 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
375 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
380 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
382 (setup.soft_scrolling ?
383 "setup.soft_scrolling" :
384 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
385 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
386 ABS(ScreenGfxPos) == ScrollStepSize ?
387 "ABS(ScreenGfxPos) == ScrollStepSize" :
388 "redraw_tiles > REDRAWTILES_THRESHOLD"));
394 redraw_mask &= ~REDRAW_MAIN;
397 if (redraw_mask & REDRAW_DOORS)
399 if (redraw_mask & REDRAW_DOOR_1)
400 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
402 if (redraw_mask & REDRAW_DOOR_2)
403 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
405 if (redraw_mask & REDRAW_DOOR_3)
406 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
408 redraw_mask &= ~REDRAW_DOORS;
411 if (redraw_mask & REDRAW_MICROLEVEL)
413 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
414 SX, SY + 10 * TILEY);
416 redraw_mask &= ~REDRAW_MICROLEVEL;
419 if (redraw_mask & REDRAW_TILES)
421 for (x = 0; x < SCR_FIELDX; x++)
422 for (y = 0 ; y < SCR_FIELDY; y++)
423 if (redraw[redraw_x1 + x][redraw_y1 + y])
424 BlitBitmap(buffer, window,
425 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
426 SX + x * TILEX, SY + y * TILEY);
429 if (redraw_mask & REDRAW_FPS) /* display frames per second */
434 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
435 if (!global.fps_slowdown)
438 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
439 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
444 for (x = 0; x < MAX_BUF_XSIZE; x++)
445 for (y = 0; y < MAX_BUF_YSIZE; y++)
448 redraw_mask = REDRAW_NONE;
454 long fading_delay = 300;
456 if (setup.fading && (redraw_mask & REDRAW_FIELD))
463 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
466 for (i = 0; i < 2 * FULL_SYSIZE; i++)
468 for (y = 0; y < FULL_SYSIZE; y++)
470 BlitBitmap(backbuffer, window,
471 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
479 for (i = 1; i < FULL_SYSIZE; i+=2)
480 BlitBitmap(backbuffer, window,
481 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
487 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
488 BlitBitmapMasked(backbuffer, window,
489 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
494 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
495 BlitBitmapMasked(backbuffer, window,
496 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
501 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
502 BlitBitmapMasked(backbuffer, window,
503 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
508 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
509 BlitBitmapMasked(backbuffer, window,
510 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
515 redraw_mask &= ~REDRAW_MAIN;
522 void FadeExt(int fade_mask, int fade_mode)
524 static int fade_mode_skip = FADE_MODE_NONE;
525 void (*draw_border_function)(void) = NULL;
527 Bitmap *bitmap = (fade_mode != FADE_MODE_FADE_IN ? bitmap_db_cross : NULL);
529 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
531 int x, y, width, height;
532 int fade_delay, post_delay;
534 redraw_mask |= fade_mask;
536 if (fade_mode & FADE_TYPE_SKIP)
539 printf("::: will skip %d ... [%d]\n", fade_mode, fade_mode_skip);
542 fade_mode_skip = fade_mode;
547 if (fade_mode_skip & FADE_TYPE_SKIP)
550 printf("::: skipping %d ... [%d]\n", fade_mode, fade_mode_skip);
553 /* skip all fade operations until specified fade operation */
554 if (fade_mode & fade_mode_skip)
555 fade_mode_skip = FADE_MODE_NONE;
561 if (global.autoplay_leveldir)
562 fading.fade_mode = FADE_MODE_NONE;
566 if (fading.fade_mode == FADE_MODE_NONE)
570 if (fade_mask & REDRAW_FIELD)
575 height = FULL_SYSIZE;
577 fade_delay = fading.fade_delay;
578 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
580 draw_border_function = DrawMaskedBorder_FIELD;
582 else /* REDRAW_ALL */
589 fade_delay = fading.fade_delay;
590 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
594 if (!setup.fade_screens || fade_delay == 0)
596 if (!setup.fade_screens || fade_delay == 0 || fading.anim_mode == ANIM_NONE)
599 if (fade_mode == FADE_MODE_FADE_OUT)
600 ClearRectangle(backbuffer, x, y, width, height);
607 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
608 draw_border_function);
610 redraw_mask &= ~fade_mask;
613 void FadeIn(int fade_mask)
616 // printf("::: now fading in...\n");
618 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
619 FadeExt(fade_mask, fading.fade_mode);
621 FadeExt(fade_mask, FADE_MODE_FADE_IN);
624 if (fading.fade_mode == FADE_MODE_CROSSFADE)
625 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
627 FadeExt(fade_mask, FADE_MODE_FADE_IN);
629 FadeExt(fade_mask, FADE_MODE_FADE_IN);
634 void FadeOut(int fade_mask)
637 // printf("::: fading.fade_mode == %d\n", fading.fade_mode);
639 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
640 FadeCrossSaveBackbuffer();
642 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
645 if (fading.fade_mode == FADE_MODE_CROSSFADE)
646 FadeCrossSaveBackbuffer();
648 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
650 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
655 void FadeCross(int fade_mask)
657 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
660 void FadeCrossSaveBackbuffer()
662 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
665 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
667 static struct TitleFadingInfo fading_leave_stored;
670 fading_leave_stored = fading_leave;
672 fading = fading_leave_stored;
675 void FadeSetEnterMenu()
677 fading = menu.enter_menu;
679 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
682 void FadeSetLeaveMenu()
684 fading = menu.leave_menu;
686 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
689 void FadeSetEnterScreen()
691 fading = menu.enter_screen[game_status];
693 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
696 void FadeSetLeaveScreen()
698 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
701 void FadeSetFromType(int type)
703 if (type & TYPE_ENTER_SCREEN)
704 FadeSetEnterScreen();
705 else if (type & TYPE_ENTER)
707 else if (type & TYPE_LEAVE)
711 void FadeSetDisabled()
713 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
715 fading = fading_none;
718 void FadeSkipNextFadeIn()
720 FadeExt(0, FADE_MODE_SKIP_FADE_IN);
723 void FadeSkipNextFadeOut()
725 FadeExt(0, FADE_MODE_SKIP_FADE_OUT);
728 void SetWindowBackgroundImageIfDefined(int graphic)
730 if (graphic_info[graphic].bitmap)
731 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
734 void SetMainBackgroundImageIfDefined(int graphic)
736 if (graphic_info[graphic].bitmap)
737 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
740 void SetDoorBackgroundImageIfDefined(int graphic)
742 if (graphic_info[graphic].bitmap)
743 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
746 void SetWindowBackgroundImage(int graphic)
748 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
749 graphic_info[graphic].bitmap ?
750 graphic_info[graphic].bitmap :
751 graphic_info[IMG_BACKGROUND].bitmap);
754 void SetMainBackgroundImage(int graphic)
756 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
757 graphic_info[graphic].bitmap ?
758 graphic_info[graphic].bitmap :
759 graphic_info[IMG_BACKGROUND].bitmap);
762 void SetDoorBackgroundImage(int graphic)
764 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
765 graphic_info[graphic].bitmap ?
766 graphic_info[graphic].bitmap :
767 graphic_info[IMG_BACKGROUND].bitmap);
770 void SetPanelBackground()
772 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
773 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
775 SetDoorBackgroundBitmap(bitmap_db_panel);
778 void DrawBackground(int x, int y, int width, int height)
780 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
781 /* (when entering hall of fame after playing) */
783 ClearRectangleOnBackground(drawto, x, y, width, height);
785 ClearRectangleOnBackground(backbuffer, x, y, width, height);
788 redraw_mask |= REDRAW_FIELD;
791 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
793 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
795 if (font->bitmap == NULL)
798 DrawBackground(x, y, width, height);
801 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
803 struct GraphicInfo *g = &graphic_info[graphic];
805 if (g->bitmap == NULL)
808 DrawBackground(x, y, width, height);
813 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
814 /* (when entering hall of fame after playing) */
815 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
817 /* !!! maybe this should be done before clearing the background !!! */
818 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
820 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
821 SetDrawtoField(DRAW_BUFFERED);
824 SetDrawtoField(DRAW_BACKBUFFER);
826 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
828 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
829 SetDrawtoField(DRAW_DIRECT);
833 void MarkTileDirty(int x, int y)
835 int xx = redraw_x1 + x;
836 int yy = redraw_y1 + y;
841 redraw[xx][yy] = TRUE;
842 redraw_mask |= REDRAW_TILES;
845 void SetBorderElement()
849 BorderElement = EL_EMPTY;
851 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
853 for (x = 0; x < lev_fieldx; x++)
855 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
856 BorderElement = EL_STEELWALL;
858 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
864 void FloodFillLevel(int from_x, int from_y, int fill_element,
865 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
866 int max_fieldx, int max_fieldy)
870 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
871 static int safety = 0;
873 /* check if starting field still has the desired content */
874 if (field[from_x][from_y] == fill_element)
879 if (safety > max_fieldx * max_fieldy)
880 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
882 old_element = field[from_x][from_y];
883 field[from_x][from_y] = fill_element;
885 for (i = 0; i < 4; i++)
887 x = from_x + check[i][0];
888 y = from_y + check[i][1];
890 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
891 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
897 void SetRandomAnimationValue(int x, int y)
899 gfx.anim_random_frame = GfxRandom[x][y];
902 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
904 /* animation synchronized with global frame counter, not move position */
905 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
906 sync_frame = FrameCounter;
908 return getAnimationFrame(graphic_info[graphic].anim_frames,
909 graphic_info[graphic].anim_delay,
910 graphic_info[graphic].anim_mode,
911 graphic_info[graphic].anim_start_frame,
915 void getSizedGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
920 int width_mult, width_div;
921 int height_mult, height_div;
925 { 15, 16, 2, 3 }, /* 1 x 1 */
926 { 7, 8, 2, 3 }, /* 2 x 2 */
927 { 3, 4, 2, 3 }, /* 4 x 4 */
928 { 1, 2, 2, 3 }, /* 8 x 8 */
929 { 0, 1, 2, 3 }, /* 16 x 16 */
930 { 0, 1, 0, 1 }, /* 32 x 32 */
932 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
933 int offset_calc_pos = log_2(tilesize);
934 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
935 int width_mult = offset_calc[offset_calc_pos].width_mult;
936 int width_div = offset_calc[offset_calc_pos].width_div;
937 int height_mult = offset_calc[offset_calc_pos].height_mult;
938 int height_div = offset_calc[offset_calc_pos].height_div;
939 int startx = src_bitmap->width * width_mult / width_div;
940 int starty = src_bitmap->height * height_mult / height_div;
941 int src_x = startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
942 int src_y = starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
944 *bitmap = src_bitmap;
949 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
952 getSizedGraphicSource(graphic, bitmap, x, y, MINI_TILESIZE);
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 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 tilesize)
1067 getSizedGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1068 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1071 void DrawMiniGraphic(int x, int y, int graphic)
1073 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1074 MarkTileDirty(x / 2, y / 2);
1077 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1082 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1083 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1086 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1087 int graphic, int frame,
1088 int cut_mode, int mask_mode)
1093 int width = TILEX, height = TILEY;
1096 if (dx || dy) /* shifted graphic */
1098 if (x < BX1) /* object enters playfield from the left */
1105 else if (x > BX2) /* object enters playfield from the right */
1111 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1117 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1119 else if (dx) /* general horizontal movement */
1120 MarkTileDirty(x + SIGN(dx), y);
1122 if (y < BY1) /* object enters playfield from the top */
1124 if (cut_mode==CUT_BELOW) /* object completely above top border */
1132 else if (y > BY2) /* object enters playfield from the bottom */
1138 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1144 else if (dy > 0 && cut_mode == CUT_ABOVE)
1146 if (y == BY2) /* object completely above bottom border */
1152 MarkTileDirty(x, y + 1);
1153 } /* object leaves playfield to the bottom */
1154 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1156 else if (dy) /* general vertical movement */
1157 MarkTileDirty(x, y + SIGN(dy));
1161 if (!IN_SCR_FIELD(x, y))
1163 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1164 printf("DrawGraphicShifted(): This should never happen!\n");
1169 if (width > 0 && height > 0)
1171 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1176 dst_x = FX + x * TILEX + dx;
1177 dst_y = FY + y * TILEY + dy;
1179 if (mask_mode == USE_MASKING)
1181 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1182 dst_x - src_x, dst_y - src_y);
1183 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1187 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1190 MarkTileDirty(x, y);
1194 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1195 int graphic, int frame,
1196 int cut_mode, int mask_mode)
1201 int width = TILEX, height = TILEY;
1204 int x2 = x + SIGN(dx);
1205 int y2 = y + SIGN(dy);
1206 int anim_frames = graphic_info[graphic].anim_frames;
1207 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1208 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1209 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1211 /* re-calculate animation frame for two-tile movement animation */
1212 frame = getGraphicAnimationFrame(graphic, sync_frame);
1214 /* check if movement start graphic inside screen area and should be drawn */
1215 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1217 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1219 dst_x = FX + x1 * TILEX;
1220 dst_y = FY + y1 * TILEY;
1222 if (mask_mode == USE_MASKING)
1224 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1225 dst_x - src_x, dst_y - src_y);
1226 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1230 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1233 MarkTileDirty(x1, y1);
1236 /* check if movement end graphic inside screen area and should be drawn */
1237 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1239 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1241 dst_x = FX + x2 * TILEX;
1242 dst_y = FY + y2 * TILEY;
1244 if (mask_mode == USE_MASKING)
1246 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1247 dst_x - src_x, dst_y - src_y);
1248 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1252 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1255 MarkTileDirty(x2, y2);
1259 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1260 int graphic, int frame,
1261 int cut_mode, int mask_mode)
1265 DrawGraphic(x, y, graphic, frame);
1270 if (graphic_info[graphic].double_movement) /* EM style movement images */
1271 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1273 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1276 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1277 int frame, int cut_mode)
1279 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1282 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1283 int cut_mode, int mask_mode)
1285 int lx = LEVELX(x), ly = LEVELY(y);
1289 if (IN_LEV_FIELD(lx, ly))
1291 SetRandomAnimationValue(lx, ly);
1293 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1294 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1296 /* do not use double (EM style) movement graphic when not moving */
1297 if (graphic_info[graphic].double_movement && !dx && !dy)
1299 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1300 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1303 else /* border element */
1305 graphic = el2img(element);
1306 frame = getGraphicAnimationFrame(graphic, -1);
1309 if (element == EL_EXPANDABLE_WALL)
1311 boolean left_stopped = FALSE, right_stopped = FALSE;
1313 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1314 left_stopped = TRUE;
1315 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1316 right_stopped = TRUE;
1318 if (left_stopped && right_stopped)
1320 else if (left_stopped)
1322 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1323 frame = graphic_info[graphic].anim_frames - 1;
1325 else if (right_stopped)
1327 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1328 frame = graphic_info[graphic].anim_frames - 1;
1333 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1334 else if (mask_mode == USE_MASKING)
1335 DrawGraphicThruMask(x, y, graphic, frame);
1337 DrawGraphic(x, y, graphic, frame);
1340 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1341 int cut_mode, int mask_mode)
1343 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1344 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1345 cut_mode, mask_mode);
1348 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1351 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1354 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1357 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1360 void DrawLevelElementThruMask(int x, int y, int element)
1362 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1365 void DrawLevelFieldThruMask(int x, int y)
1367 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1370 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1374 int sx = SCREENX(x), sy = SCREENY(y);
1376 int width, height, cx, cy, i;
1377 int crumbled_border_size = graphic_info[graphic].border_size;
1378 static int xy[4][2] =
1386 if (!IN_LEV_FIELD(x, y))
1389 element = TILE_GFX_ELEMENT(x, y);
1391 /* crumble field itself */
1392 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1394 if (!IN_SCR_FIELD(sx, sy))
1397 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1399 for (i = 0; i < 4; i++)
1401 int xx = x + xy[i][0];
1402 int yy = y + xy[i][1];
1404 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1407 /* check if neighbour field is of same type */
1408 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1411 if (i == 1 || i == 2)
1413 width = crumbled_border_size;
1415 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1421 height = crumbled_border_size;
1423 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1426 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1427 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1430 MarkTileDirty(sx, sy);
1432 else /* crumble neighbour fields */
1434 for (i = 0; i < 4; i++)
1436 int xx = x + xy[i][0];
1437 int yy = y + xy[i][1];
1438 int sxx = sx + xy[i][0];
1439 int syy = sy + xy[i][1];
1441 if (!IN_LEV_FIELD(xx, yy) ||
1442 !IN_SCR_FIELD(sxx, syy) ||
1446 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1449 element = TILE_GFX_ELEMENT(xx, yy);
1451 if (!GFX_CRUMBLED(element))
1454 graphic = el_act2crm(element, ACTION_DEFAULT);
1455 crumbled_border_size = graphic_info[graphic].border_size;
1457 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1459 if (i == 1 || i == 2)
1461 width = crumbled_border_size;
1463 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1469 height = crumbled_border_size;
1471 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1474 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1475 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1477 MarkTileDirty(sxx, syy);
1482 void DrawLevelFieldCrumbledSand(int x, int y)
1486 if (!IN_LEV_FIELD(x, y))
1490 /* !!! CHECK THIS !!! */
1493 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1494 GFX_CRUMBLED(GfxElement[x][y]))
1497 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1498 GfxElement[x][y] != EL_UNDEFINED &&
1499 GFX_CRUMBLED(GfxElement[x][y]))
1501 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1508 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1510 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1513 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1516 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1519 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1520 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1521 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1522 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1523 int sx = SCREENX(x), sy = SCREENY(y);
1525 DrawGraphic(sx, sy, graphic1, frame1);
1526 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1529 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1531 int sx = SCREENX(x), sy = SCREENY(y);
1532 static int xy[4][2] =
1541 for (i = 0; i < 4; i++)
1543 int xx = x + xy[i][0];
1544 int yy = y + xy[i][1];
1545 int sxx = sx + xy[i][0];
1546 int syy = sy + xy[i][1];
1548 if (!IN_LEV_FIELD(xx, yy) ||
1549 !IN_SCR_FIELD(sxx, syy) ||
1550 !GFX_CRUMBLED(Feld[xx][yy]) ||
1554 DrawLevelField(xx, yy);
1558 static int getBorderElement(int x, int y)
1562 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1563 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1564 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1565 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1566 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1567 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1568 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1570 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1571 int steel_position = (x == -1 && y == -1 ? 0 :
1572 x == lev_fieldx && y == -1 ? 1 :
1573 x == -1 && y == lev_fieldy ? 2 :
1574 x == lev_fieldx && y == lev_fieldy ? 3 :
1575 x == -1 || x == lev_fieldx ? 4 :
1576 y == -1 || y == lev_fieldy ? 5 : 6);
1578 return border[steel_position][steel_type];
1581 void DrawScreenElement(int x, int y, int element)
1583 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1584 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1587 void DrawLevelElement(int x, int y, int element)
1589 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1590 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1593 void DrawScreenField(int x, int y)
1595 int lx = LEVELX(x), ly = LEVELY(y);
1596 int element, content;
1598 if (!IN_LEV_FIELD(lx, ly))
1600 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1603 element = getBorderElement(lx, ly);
1605 DrawScreenElement(x, y, element);
1609 element = Feld[lx][ly];
1610 content = Store[lx][ly];
1612 if (IS_MOVING(lx, ly))
1614 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1615 boolean cut_mode = NO_CUTTING;
1617 if (element == EL_QUICKSAND_EMPTYING ||
1618 element == EL_QUICKSAND_FAST_EMPTYING ||
1619 element == EL_MAGIC_WALL_EMPTYING ||
1620 element == EL_BD_MAGIC_WALL_EMPTYING ||
1621 element == EL_DC_MAGIC_WALL_EMPTYING ||
1622 element == EL_AMOEBA_DROPPING)
1623 cut_mode = CUT_ABOVE;
1624 else if (element == EL_QUICKSAND_FILLING ||
1625 element == EL_QUICKSAND_FAST_FILLING ||
1626 element == EL_MAGIC_WALL_FILLING ||
1627 element == EL_BD_MAGIC_WALL_FILLING ||
1628 element == EL_DC_MAGIC_WALL_FILLING)
1629 cut_mode = CUT_BELOW;
1631 if (cut_mode == CUT_ABOVE)
1632 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1634 DrawScreenElement(x, y, EL_EMPTY);
1637 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1638 else if (cut_mode == NO_CUTTING)
1639 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1641 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1643 if (content == EL_ACID)
1645 int dir = MovDir[lx][ly];
1646 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1647 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1649 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1652 else if (IS_BLOCKED(lx, ly))
1657 boolean cut_mode = NO_CUTTING;
1658 int element_old, content_old;
1660 Blocked2Moving(lx, ly, &oldx, &oldy);
1663 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1664 MovDir[oldx][oldy] == MV_RIGHT);
1666 element_old = Feld[oldx][oldy];
1667 content_old = Store[oldx][oldy];
1669 if (element_old == EL_QUICKSAND_EMPTYING ||
1670 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1671 element_old == EL_MAGIC_WALL_EMPTYING ||
1672 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1673 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1674 element_old == EL_AMOEBA_DROPPING)
1675 cut_mode = CUT_ABOVE;
1677 DrawScreenElement(x, y, EL_EMPTY);
1680 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1682 else if (cut_mode == NO_CUTTING)
1683 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1686 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1689 else if (IS_DRAWABLE(element))
1690 DrawScreenElement(x, y, element);
1692 DrawScreenElement(x, y, EL_EMPTY);
1695 void DrawLevelField(int x, int y)
1697 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1698 DrawScreenField(SCREENX(x), SCREENY(y));
1699 else if (IS_MOVING(x, y))
1703 Moving2Blocked(x, y, &newx, &newy);
1704 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1705 DrawScreenField(SCREENX(newx), SCREENY(newy));
1707 else if (IS_BLOCKED(x, y))
1711 Blocked2Moving(x, y, &oldx, &oldy);
1712 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1713 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1717 void DrawMiniElement(int x, int y, int element)
1721 graphic = el2edimg(element);
1722 DrawMiniGraphic(x, y, graphic);
1725 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1727 int x = sx + scroll_x, y = sy + scroll_y;
1729 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1730 DrawMiniElement(sx, sy, EL_EMPTY);
1731 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1732 DrawMiniElement(sx, sy, Feld[x][y]);
1734 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1737 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1738 int x, int y, int xsize, int ysize, int font_nr)
1740 int font_width = getFontWidth(font_nr);
1741 int font_height = getFontHeight(font_nr);
1742 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1745 int dst_x = SX + startx + x * font_width;
1746 int dst_y = SY + starty + y * font_height;
1747 int width = graphic_info[graphic].width;
1748 int height = graphic_info[graphic].height;
1749 int inner_width = MAX(width - 2 * font_width, font_width);
1750 int inner_height = MAX(height - 2 * font_height, font_height);
1751 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1752 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1753 boolean draw_masked = graphic_info[graphic].draw_masked;
1755 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1757 if (src_bitmap == NULL || width < font_width || height < font_height)
1759 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1763 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1764 inner_sx + (x - 1) * font_width % inner_width);
1765 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1766 inner_sy + (y - 1) * font_height % inner_height);
1770 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1771 dst_x - src_x, dst_y - src_y);
1772 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1776 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1780 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1782 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1783 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1784 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1785 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1786 boolean no_delay = (tape.warp_forward);
1787 unsigned long anim_delay = 0;
1788 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1789 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1790 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1791 int font_width = getFontWidth(font_nr);
1792 int font_height = getFontHeight(font_nr);
1793 int max_xsize = level.envelope[envelope_nr].xsize;
1794 int max_ysize = level.envelope[envelope_nr].ysize;
1795 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1796 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1797 int xend = max_xsize;
1798 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1799 int xstep = (xstart < xend ? 1 : 0);
1800 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1803 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1805 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1806 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1807 int sx = (SXSIZE - xsize * font_width) / 2;
1808 int sy = (SYSIZE - ysize * font_height) / 2;
1811 SetDrawtoField(DRAW_BUFFERED);
1813 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1815 SetDrawtoField(DRAW_BACKBUFFER);
1817 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1818 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1821 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1822 level.envelope[envelope_nr].text, font_nr, max_xsize,
1823 xsize - 2, ysize - 2, mask_mode,
1824 level.envelope[envelope_nr].autowrap,
1825 level.envelope[envelope_nr].centered, FALSE);
1827 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1828 level.envelope[envelope_nr].text, font_nr, max_xsize,
1829 xsize - 2, ysize - 2, mask_mode);
1832 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1835 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1839 void ShowEnvelope(int envelope_nr)
1841 int element = EL_ENVELOPE_1 + envelope_nr;
1842 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1843 int sound_opening = element_info[element].sound[ACTION_OPENING];
1844 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1845 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1846 boolean no_delay = (tape.warp_forward);
1847 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1848 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1849 int anim_mode = graphic_info[graphic].anim_mode;
1850 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1851 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1853 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1855 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1857 if (anim_mode == ANIM_DEFAULT)
1858 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1860 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1863 Delay(wait_delay_value);
1865 WaitForEventToContinue();
1867 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1869 if (anim_mode != ANIM_NONE)
1870 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1872 if (anim_mode == ANIM_DEFAULT)
1873 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1875 game.envelope_active = FALSE;
1877 SetDrawtoField(DRAW_BUFFERED);
1879 redraw_mask |= REDRAW_FIELD;
1883 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1887 int graphic = el2preimg(element);
1889 getSizedGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1890 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1897 SetDrawBackgroundMask(REDRAW_NONE);
1900 for (x = BX1; x <= BX2; x++)
1901 for (y = BY1; y <= BY2; y++)
1902 DrawScreenField(x, y);
1904 redraw_mask |= REDRAW_FIELD;
1907 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1911 for (x = 0; x < size_x; x++)
1912 for (y = 0; y < size_y; y++)
1913 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1915 redraw_mask |= REDRAW_FIELD;
1918 static void DrawPreviewLevelExt(int from_x, int from_y)
1920 boolean show_level_border = (BorderElement != EL_EMPTY);
1921 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1922 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1923 int tile_size = preview.tile_size;
1924 int preview_width = preview.xsize * tile_size;
1925 int preview_height = preview.ysize * tile_size;
1926 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1927 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1928 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1929 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1932 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1934 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1935 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1937 for (x = 0; x < real_preview_xsize; x++)
1939 for (y = 0; y < real_preview_ysize; y++)
1941 int lx = from_x + x + (show_level_border ? -1 : 0);
1942 int ly = from_y + y + (show_level_border ? -1 : 0);
1943 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1944 getBorderElement(lx, ly));
1946 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1947 element, tile_size);
1951 redraw_mask |= REDRAW_MICROLEVEL;
1954 #define MICROLABEL_EMPTY 0
1955 #define MICROLABEL_LEVEL_NAME 1
1956 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1957 #define MICROLABEL_LEVEL_AUTHOR 3
1958 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1959 #define MICROLABEL_IMPORTED_FROM 5
1960 #define MICROLABEL_IMPORTED_BY_HEAD 6
1961 #define MICROLABEL_IMPORTED_BY 7
1963 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
1965 int max_text_width = SXSIZE;
1966 int font_width = getFontWidth(font_nr);
1968 if (pos->align == ALIGN_CENTER)
1969 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1970 else if (pos->align == ALIGN_RIGHT)
1971 max_text_width = pos->x;
1973 max_text_width = SXSIZE - pos->x;
1975 return max_text_width / font_width;
1978 static void DrawPreviewLevelLabelExt(int mode)
1980 struct TextPosInfo *pos = &menu.main.text.level_info_2;
1981 char label_text[MAX_OUTPUT_LINESIZE + 1];
1982 int max_len_label_text;
1984 int font_nr = pos->font;
1987 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1988 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1989 mode == MICROLABEL_IMPORTED_BY_HEAD)
1990 font_nr = pos->font_alt;
1992 int font_nr = FONT_TEXT_2;
1995 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1996 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1997 mode == MICROLABEL_IMPORTED_BY_HEAD)
1998 font_nr = FONT_TEXT_3;
2002 max_len_label_text = getMaxTextLength(pos, font_nr);
2004 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2008 if (pos->size != -1)
2009 max_len_label_text = pos->size;
2012 for (i = 0; i < max_len_label_text; i++)
2013 label_text[i] = ' ';
2014 label_text[max_len_label_text] = '\0';
2016 if (strlen(label_text) > 0)
2019 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2021 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2022 int lypos = MICROLABEL2_YPOS;
2024 DrawText(lxpos, lypos, label_text, font_nr);
2029 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2030 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2031 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2032 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2033 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2034 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2035 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2036 max_len_label_text);
2037 label_text[max_len_label_text] = '\0';
2039 if (strlen(label_text) > 0)
2042 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2044 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2045 int lypos = MICROLABEL2_YPOS;
2047 DrawText(lxpos, lypos, label_text, font_nr);
2051 redraw_mask |= REDRAW_MICROLEVEL;
2054 void DrawPreviewLevel(boolean restart)
2056 static unsigned long scroll_delay = 0;
2057 static unsigned long label_delay = 0;
2058 static int from_x, from_y, scroll_direction;
2059 static int label_state, label_counter;
2060 unsigned long scroll_delay_value = preview.step_delay;
2061 boolean show_level_border = (BorderElement != EL_EMPTY);
2062 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2063 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2064 int last_game_status = game_status; /* save current game status */
2067 /* force PREVIEW font on preview level */
2068 game_status = GAME_MODE_PSEUDO_PREVIEW;
2076 if (preview.anim_mode == ANIM_CENTERED)
2078 if (level_xsize > preview.xsize)
2079 from_x = (level_xsize - preview.xsize) / 2;
2080 if (level_ysize > preview.ysize)
2081 from_y = (level_ysize - preview.ysize) / 2;
2084 from_x += preview.xoffset;
2085 from_y += preview.yoffset;
2087 scroll_direction = MV_RIGHT;
2091 DrawPreviewLevelExt(from_x, from_y);
2092 DrawPreviewLevelLabelExt(label_state);
2094 /* initialize delay counters */
2095 DelayReached(&scroll_delay, 0);
2096 DelayReached(&label_delay, 0);
2098 if (leveldir_current->name)
2100 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2101 char label_text[MAX_OUTPUT_LINESIZE + 1];
2103 int font_nr = pos->font;
2105 int font_nr = FONT_TEXT_1;
2108 int max_len_label_text = getMaxTextLength(pos, font_nr);
2110 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2118 if (pos->size != -1)
2119 max_len_label_text = pos->size;
2122 strncpy(label_text, leveldir_current->name, max_len_label_text);
2123 label_text[max_len_label_text] = '\0';
2126 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2128 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2129 lypos = SY + MICROLABEL1_YPOS;
2131 DrawText(lxpos, lypos, label_text, font_nr);
2135 game_status = last_game_status; /* restore current game status */
2140 /* scroll preview level, if needed */
2141 if (preview.anim_mode != ANIM_NONE &&
2142 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2143 DelayReached(&scroll_delay, scroll_delay_value))
2145 switch (scroll_direction)
2150 from_x -= preview.step_offset;
2151 from_x = (from_x < 0 ? 0 : from_x);
2154 scroll_direction = MV_UP;
2158 if (from_x < level_xsize - preview.xsize)
2160 from_x += preview.step_offset;
2161 from_x = (from_x > level_xsize - preview.xsize ?
2162 level_xsize - preview.xsize : from_x);
2165 scroll_direction = MV_DOWN;
2171 from_y -= preview.step_offset;
2172 from_y = (from_y < 0 ? 0 : from_y);
2175 scroll_direction = MV_RIGHT;
2179 if (from_y < level_ysize - preview.ysize)
2181 from_y += preview.step_offset;
2182 from_y = (from_y > level_ysize - preview.ysize ?
2183 level_ysize - preview.ysize : from_y);
2186 scroll_direction = MV_LEFT;
2193 DrawPreviewLevelExt(from_x, from_y);
2196 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2197 /* redraw micro level label, if needed */
2198 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2199 !strEqual(level.author, ANONYMOUS_NAME) &&
2200 !strEqual(level.author, leveldir_current->name) &&
2201 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2203 int max_label_counter = 23;
2205 if (leveldir_current->imported_from != NULL &&
2206 strlen(leveldir_current->imported_from) > 0)
2207 max_label_counter += 14;
2208 if (leveldir_current->imported_by != NULL &&
2209 strlen(leveldir_current->imported_by) > 0)
2210 max_label_counter += 14;
2212 label_counter = (label_counter + 1) % max_label_counter;
2213 label_state = (label_counter >= 0 && label_counter <= 7 ?
2214 MICROLABEL_LEVEL_NAME :
2215 label_counter >= 9 && label_counter <= 12 ?
2216 MICROLABEL_LEVEL_AUTHOR_HEAD :
2217 label_counter >= 14 && label_counter <= 21 ?
2218 MICROLABEL_LEVEL_AUTHOR :
2219 label_counter >= 23 && label_counter <= 26 ?
2220 MICROLABEL_IMPORTED_FROM_HEAD :
2221 label_counter >= 28 && label_counter <= 35 ?
2222 MICROLABEL_IMPORTED_FROM :
2223 label_counter >= 37 && label_counter <= 40 ?
2224 MICROLABEL_IMPORTED_BY_HEAD :
2225 label_counter >= 42 && label_counter <= 49 ?
2226 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2228 if (leveldir_current->imported_from == NULL &&
2229 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2230 label_state == MICROLABEL_IMPORTED_FROM))
2231 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2232 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2234 DrawPreviewLevelLabelExt(label_state);
2237 game_status = last_game_status; /* restore current game status */
2240 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2241 int graphic, int sync_frame, int mask_mode)
2243 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2245 if (mask_mode == USE_MASKING)
2246 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2248 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2251 inline void DrawGraphicAnimation(int x, int y, int graphic)
2253 int lx = LEVELX(x), ly = LEVELY(y);
2255 if (!IN_SCR_FIELD(x, y))
2258 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2259 graphic, GfxFrame[lx][ly], NO_MASKING);
2260 MarkTileDirty(x, y);
2263 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2265 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2268 void DrawLevelElementAnimation(int x, int y, int element)
2270 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2272 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2275 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2277 int sx = SCREENX(x), sy = SCREENY(y);
2279 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2282 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2285 DrawGraphicAnimation(sx, sy, graphic);
2288 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2289 DrawLevelFieldCrumbledSand(x, y);
2291 if (GFX_CRUMBLED(Feld[x][y]))
2292 DrawLevelFieldCrumbledSand(x, y);
2296 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2298 int sx = SCREENX(x), sy = SCREENY(y);
2301 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2304 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2306 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2309 DrawGraphicAnimation(sx, sy, graphic);
2311 if (GFX_CRUMBLED(element))
2312 DrawLevelFieldCrumbledSand(x, y);
2315 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2317 if (player->use_murphy)
2319 /* this works only because currently only one player can be "murphy" ... */
2320 static int last_horizontal_dir = MV_LEFT;
2321 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2323 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2324 last_horizontal_dir = move_dir;
2326 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2328 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2330 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2336 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2339 static boolean equalGraphics(int graphic1, int graphic2)
2341 struct GraphicInfo *g1 = &graphic_info[graphic1];
2342 struct GraphicInfo *g2 = &graphic_info[graphic2];
2344 return (g1->bitmap == g2->bitmap &&
2345 g1->src_x == g2->src_x &&
2346 g1->src_y == g2->src_y &&
2347 g1->anim_frames == g2->anim_frames &&
2348 g1->anim_delay == g2->anim_delay &&
2349 g1->anim_mode == g2->anim_mode);
2352 void DrawAllPlayers()
2356 for (i = 0; i < MAX_PLAYERS; i++)
2357 if (stored_player[i].active)
2358 DrawPlayer(&stored_player[i]);
2361 void DrawPlayerField(int x, int y)
2363 if (!IS_PLAYER(x, y))
2366 DrawPlayer(PLAYERINFO(x, y));
2369 void DrawPlayer(struct PlayerInfo *player)
2371 int jx = player->jx;
2372 int jy = player->jy;
2373 int move_dir = player->MovDir;
2374 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2375 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2376 int last_jx = (player->is_moving ? jx - dx : jx);
2377 int last_jy = (player->is_moving ? jy - dy : jy);
2378 int next_jx = jx + dx;
2379 int next_jy = jy + dy;
2380 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2381 boolean player_is_opaque = FALSE;
2382 int sx = SCREENX(jx), sy = SCREENY(jy);
2383 int sxx = 0, syy = 0;
2384 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2386 int action = ACTION_DEFAULT;
2387 int last_player_graphic = getPlayerGraphic(player, move_dir);
2388 int last_player_frame = player->Frame;
2391 /* GfxElement[][] is set to the element the player is digging or collecting;
2392 remove also for off-screen player if the player is not moving anymore */
2393 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2394 GfxElement[jx][jy] = EL_UNDEFINED;
2396 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2400 if (!IN_LEV_FIELD(jx, jy))
2402 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2403 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2404 printf("DrawPlayerField(): This should never happen!\n");
2409 if (element == EL_EXPLOSION)
2412 action = (player->is_pushing ? ACTION_PUSHING :
2413 player->is_digging ? ACTION_DIGGING :
2414 player->is_collecting ? ACTION_COLLECTING :
2415 player->is_moving ? ACTION_MOVING :
2416 player->is_snapping ? ACTION_SNAPPING :
2417 player->is_dropping ? ACTION_DROPPING :
2418 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2420 if (player->is_waiting)
2421 move_dir = player->dir_waiting;
2423 InitPlayerGfxAnimation(player, action, move_dir);
2425 /* ----------------------------------------------------------------------- */
2426 /* draw things in the field the player is leaving, if needed */
2427 /* ----------------------------------------------------------------------- */
2429 if (player->is_moving)
2431 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2433 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2435 if (last_element == EL_DYNAMITE_ACTIVE ||
2436 last_element == EL_EM_DYNAMITE_ACTIVE ||
2437 last_element == EL_SP_DISK_RED_ACTIVE)
2438 DrawDynamite(last_jx, last_jy);
2440 DrawLevelFieldThruMask(last_jx, last_jy);
2442 else if (last_element == EL_DYNAMITE_ACTIVE ||
2443 last_element == EL_EM_DYNAMITE_ACTIVE ||
2444 last_element == EL_SP_DISK_RED_ACTIVE)
2445 DrawDynamite(last_jx, last_jy);
2447 /* !!! this is not enough to prevent flickering of players which are
2448 moving next to each others without a free tile between them -- this
2449 can only be solved by drawing all players layer by layer (first the
2450 background, then the foreground etc.) !!! => TODO */
2451 else if (!IS_PLAYER(last_jx, last_jy))
2452 DrawLevelField(last_jx, last_jy);
2455 DrawLevelField(last_jx, last_jy);
2458 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2459 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2462 if (!IN_SCR_FIELD(sx, sy))
2465 if (setup.direct_draw)
2466 SetDrawtoField(DRAW_BUFFERED);
2468 /* ----------------------------------------------------------------------- */
2469 /* draw things behind the player, if needed */
2470 /* ----------------------------------------------------------------------- */
2473 DrawLevelElement(jx, jy, Back[jx][jy]);
2474 else if (IS_ACTIVE_BOMB(element))
2475 DrawLevelElement(jx, jy, EL_EMPTY);
2478 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2480 int old_element = GfxElement[jx][jy];
2481 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2482 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2484 if (GFX_CRUMBLED(old_element))
2485 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2487 DrawGraphic(sx, sy, old_graphic, frame);
2489 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2490 player_is_opaque = TRUE;
2494 GfxElement[jx][jy] = EL_UNDEFINED;
2496 /* make sure that pushed elements are drawn with correct frame rate */
2498 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2500 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2501 GfxFrame[jx][jy] = player->StepFrame;
2503 if (player->is_pushing && player->is_moving)
2504 GfxFrame[jx][jy] = player->StepFrame;
2507 DrawLevelField(jx, jy);
2511 /* ----------------------------------------------------------------------- */
2512 /* draw player himself */
2513 /* ----------------------------------------------------------------------- */
2515 graphic = getPlayerGraphic(player, move_dir);
2517 /* in the case of changed player action or direction, prevent the current
2518 animation frame from being restarted for identical animations */
2519 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2520 player->Frame = last_player_frame;
2522 frame = getGraphicAnimationFrame(graphic, player->Frame);
2526 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2527 sxx = player->GfxPos;
2529 syy = player->GfxPos;
2532 if (!setup.soft_scrolling && ScreenMovPos)
2535 if (player_is_opaque)
2536 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2538 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2540 if (SHIELD_ON(player))
2542 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2543 IMG_SHIELD_NORMAL_ACTIVE);
2544 int frame = getGraphicAnimationFrame(graphic, -1);
2546 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2549 /* ----------------------------------------------------------------------- */
2550 /* draw things the player is pushing, if needed */
2551 /* ----------------------------------------------------------------------- */
2554 printf("::: %d, %d [%d, %d] [%d]\n",
2555 player->is_pushing, player_is_moving, player->GfxAction,
2556 player->is_moving, player_is_moving);
2560 if (player->is_pushing && player->is_moving)
2562 int px = SCREENX(jx), py = SCREENY(jy);
2563 int pxx = (TILEX - ABS(sxx)) * dx;
2564 int pyy = (TILEY - ABS(syy)) * dy;
2565 int gfx_frame = GfxFrame[jx][jy];
2571 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2573 element = Feld[next_jx][next_jy];
2574 gfx_frame = GfxFrame[next_jx][next_jy];
2577 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2580 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2581 frame = getGraphicAnimationFrame(graphic, sync_frame);
2583 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2586 /* draw background element under pushed element (like the Sokoban field) */
2587 if (Back[next_jx][next_jy])
2588 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2590 /* masked drawing is needed for EMC style (double) movement graphics */
2591 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2595 /* ----------------------------------------------------------------------- */
2596 /* draw things in front of player (active dynamite or dynabombs) */
2597 /* ----------------------------------------------------------------------- */
2599 if (IS_ACTIVE_BOMB(element))
2601 graphic = el2img(element);
2602 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2604 if (game.emulation == EMU_SUPAPLEX)
2605 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2607 DrawGraphicThruMask(sx, sy, graphic, frame);
2610 if (player_is_moving && last_element == EL_EXPLOSION)
2612 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2613 GfxElement[last_jx][last_jy] : EL_EMPTY);
2614 int graphic = el_act2img(element, ACTION_EXPLODING);
2615 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2616 int phase = ExplodePhase[last_jx][last_jy] - 1;
2617 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2620 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2623 /* ----------------------------------------------------------------------- */
2624 /* draw elements the player is just walking/passing through/under */
2625 /* ----------------------------------------------------------------------- */
2627 if (player_is_moving)
2629 /* handle the field the player is leaving ... */
2630 if (IS_ACCESSIBLE_INSIDE(last_element))
2631 DrawLevelField(last_jx, last_jy);
2632 else if (IS_ACCESSIBLE_UNDER(last_element))
2633 DrawLevelFieldThruMask(last_jx, last_jy);
2636 /* do not redraw accessible elements if the player is just pushing them */
2637 if (!player_is_moving || !player->is_pushing)
2639 /* ... and the field the player is entering */
2640 if (IS_ACCESSIBLE_INSIDE(element))
2641 DrawLevelField(jx, jy);
2642 else if (IS_ACCESSIBLE_UNDER(element))
2643 DrawLevelFieldThruMask(jx, jy);
2646 if (setup.direct_draw)
2648 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2649 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2650 int x_size = TILEX * (1 + ABS(jx - last_jx));
2651 int y_size = TILEY * (1 + ABS(jy - last_jy));
2653 BlitBitmap(drawto_field, window,
2654 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2655 SetDrawtoField(DRAW_DIRECT);
2658 MarkTileDirty(sx, sy);
2661 /* ------------------------------------------------------------------------- */
2663 void WaitForEventToContinue()
2665 boolean still_wait = TRUE;
2667 /* simulate releasing mouse button over last gadget, if still pressed */
2669 HandleGadgets(-1, -1, 0);
2671 button_status = MB_RELEASED;
2687 case EVENT_BUTTONPRESS:
2688 case EVENT_KEYPRESS:
2692 case EVENT_KEYRELEASE:
2693 ClearPlayerAction();
2697 HandleOtherEvents(&event);
2701 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2708 /* don't eat all CPU time */
2713 #define MAX_REQUEST_LINES 13
2714 #define MAX_REQUEST_LINE_FONT1_LEN 7
2715 #define MAX_REQUEST_LINE_FONT2_LEN 10
2717 boolean Request(char *text, unsigned int req_state)
2719 int mx, my, ty, result = -1;
2720 unsigned int old_door_state;
2721 int last_game_status = game_status; /* save current game status */
2722 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2723 int font_nr = FONT_TEXT_2;
2724 int max_word_len = 0;
2727 for (text_ptr = text; *text_ptr; text_ptr++)
2729 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2731 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2733 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2735 font_nr = FONT_TEXT_1;
2737 font_nr = FONT_LEVEL_NUMBER;
2744 if (game_status == GAME_MODE_PLAYING &&
2745 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2746 BlitScreenToBitmap_EM(backbuffer);
2748 /* disable deactivated drawing when quick-loading level tape recording */
2749 if (tape.playing && tape.deactivate_display)
2750 TapeDeactivateDisplayOff(TRUE);
2752 SetMouseCursor(CURSOR_DEFAULT);
2754 #if defined(NETWORK_AVALIABLE)
2755 /* pause network game while waiting for request to answer */
2756 if (options.network &&
2757 game_status == GAME_MODE_PLAYING &&
2758 req_state & REQUEST_WAIT_FOR_INPUT)
2759 SendToServer_PausePlaying();
2762 old_door_state = GetDoorState();
2764 /* simulate releasing mouse button over last gadget, if still pressed */
2766 HandleGadgets(-1, -1, 0);
2770 if (old_door_state & DOOR_OPEN_1)
2772 CloseDoor(DOOR_CLOSE_1);
2774 /* save old door content */
2775 BlitBitmap(bitmap_db_door, bitmap_db_door,
2776 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2777 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2781 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2784 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2786 /* clear door drawing field */
2787 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2789 /* force DOOR font inside door area */
2790 game_status = GAME_MODE_PSEUDO_DOOR;
2792 /* write text for request */
2793 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2795 char text_line[max_request_line_len + 1];
2801 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2804 if (!tc || tc == ' ')
2815 strncpy(text_line, text, tl);
2818 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2819 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2820 text_line, font_nr);
2822 text += tl + (tc == ' ' ? 1 : 0);
2825 game_status = last_game_status; /* restore current game status */
2827 if (req_state & REQ_ASK)
2829 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2830 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2832 else if (req_state & REQ_CONFIRM)
2834 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2836 else if (req_state & REQ_PLAYER)
2838 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2839 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2840 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2841 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2844 /* copy request gadgets to door backbuffer */
2845 BlitBitmap(drawto, bitmap_db_door,
2846 DX, DY, DXSIZE, DYSIZE,
2847 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2849 OpenDoor(DOOR_OPEN_1);
2851 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2853 if (game_status == GAME_MODE_PLAYING)
2855 SetPanelBackground();
2856 SetDrawBackgroundMask(REDRAW_DOOR_1);
2860 SetDrawBackgroundMask(REDRAW_FIELD);
2866 if (game_status != GAME_MODE_MAIN)
2869 button_status = MB_RELEASED;
2871 request_gadget_id = -1;
2873 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2885 case EVENT_BUTTONPRESS:
2886 case EVENT_BUTTONRELEASE:
2887 case EVENT_MOTIONNOTIFY:
2889 if (event.type == EVENT_MOTIONNOTIFY)
2891 if (!PointerInWindow(window))
2892 continue; /* window and pointer are on different screens */
2897 motion_status = TRUE;
2898 mx = ((MotionEvent *) &event)->x;
2899 my = ((MotionEvent *) &event)->y;
2903 motion_status = FALSE;
2904 mx = ((ButtonEvent *) &event)->x;
2905 my = ((ButtonEvent *) &event)->y;
2906 if (event.type == EVENT_BUTTONPRESS)
2907 button_status = ((ButtonEvent *) &event)->button;
2909 button_status = MB_RELEASED;
2912 /* this sets 'request_gadget_id' */
2913 HandleGadgets(mx, my, button_status);
2915 switch (request_gadget_id)
2917 case TOOL_CTRL_ID_YES:
2920 case TOOL_CTRL_ID_NO:
2923 case TOOL_CTRL_ID_CONFIRM:
2924 result = TRUE | FALSE;
2927 case TOOL_CTRL_ID_PLAYER_1:
2930 case TOOL_CTRL_ID_PLAYER_2:
2933 case TOOL_CTRL_ID_PLAYER_3:
2936 case TOOL_CTRL_ID_PLAYER_4:
2947 case EVENT_KEYPRESS:
2948 switch (GetEventKey((KeyEvent *)&event, TRUE))
2951 if (req_state & REQ_CONFIRM)
2967 if (req_state & REQ_PLAYER)
2971 case EVENT_KEYRELEASE:
2972 ClearPlayerAction();
2976 HandleOtherEvents(&event);
2980 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2982 int joy = AnyJoystick();
2984 if (joy & JOY_BUTTON_1)
2986 else if (joy & JOY_BUTTON_2)
2992 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2994 HandleGameActions();
3001 if (!PendingEvent()) /* delay only if no pending events */
3010 if (!PendingEvent()) /* delay only if no pending events */
3013 /* don't eat all CPU time */
3020 if (game_status != GAME_MODE_MAIN)
3025 if (!(req_state & REQ_STAY_OPEN))
3027 CloseDoor(DOOR_CLOSE_1);
3029 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3030 (req_state & REQ_REOPEN))
3031 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3036 if (game_status == GAME_MODE_PLAYING)
3038 SetPanelBackground();
3039 SetDrawBackgroundMask(REDRAW_DOOR_1);
3043 SetDrawBackgroundMask(REDRAW_FIELD);
3046 #if defined(NETWORK_AVALIABLE)
3047 /* continue network game after request */
3048 if (options.network &&
3049 game_status == GAME_MODE_PLAYING &&
3050 req_state & REQUEST_WAIT_FOR_INPUT)
3051 SendToServer_ContinuePlaying();
3054 /* restore deactivated drawing when quick-loading level tape recording */
3055 if (tape.playing && tape.deactivate_display)
3056 TapeDeactivateDisplayOn();
3061 unsigned int OpenDoor(unsigned int door_state)
3063 if (door_state & DOOR_COPY_BACK)
3065 if (door_state & DOOR_OPEN_1)
3066 BlitBitmap(bitmap_db_door, bitmap_db_door,
3067 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3068 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3070 if (door_state & DOOR_OPEN_2)
3071 BlitBitmap(bitmap_db_door, bitmap_db_door,
3072 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3073 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3075 door_state &= ~DOOR_COPY_BACK;
3078 return MoveDoor(door_state);
3081 unsigned int CloseDoor(unsigned int door_state)
3083 unsigned int old_door_state = GetDoorState();
3085 if (!(door_state & DOOR_NO_COPY_BACK))
3087 if (old_door_state & DOOR_OPEN_1)
3088 BlitBitmap(backbuffer, bitmap_db_door,
3089 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3091 if (old_door_state & DOOR_OPEN_2)
3092 BlitBitmap(backbuffer, bitmap_db_door,
3093 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3095 door_state &= ~DOOR_NO_COPY_BACK;
3098 return MoveDoor(door_state);
3101 unsigned int GetDoorState()
3103 return MoveDoor(DOOR_GET_STATE);
3106 unsigned int SetDoorState(unsigned int door_state)
3108 return MoveDoor(door_state | DOOR_SET_STATE);
3111 unsigned int MoveDoor(unsigned int door_state)
3113 static int door1 = DOOR_OPEN_1;
3114 static int door2 = DOOR_CLOSE_2;
3115 unsigned long door_delay = 0;
3116 unsigned long door_delay_value;
3119 if (door_1.width < 0 || door_1.width > DXSIZE)
3120 door_1.width = DXSIZE;
3121 if (door_1.height < 0 || door_1.height > DYSIZE)
3122 door_1.height = DYSIZE;
3123 if (door_2.width < 0 || door_2.width > VXSIZE)
3124 door_2.width = VXSIZE;
3125 if (door_2.height < 0 || door_2.height > VYSIZE)
3126 door_2.height = VYSIZE;
3128 if (door_state == DOOR_GET_STATE)
3129 return (door1 | door2);
3131 if (door_state & DOOR_SET_STATE)
3133 if (door_state & DOOR_ACTION_1)
3134 door1 = door_state & DOOR_ACTION_1;
3135 if (door_state & DOOR_ACTION_2)
3136 door2 = door_state & DOOR_ACTION_2;
3138 return (door1 | door2);
3141 if (!(door_state & DOOR_FORCE_REDRAW))
3143 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3144 door_state &= ~DOOR_OPEN_1;
3145 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3146 door_state &= ~DOOR_CLOSE_1;
3147 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3148 door_state &= ~DOOR_OPEN_2;
3149 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3150 door_state &= ~DOOR_CLOSE_2;
3153 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3156 if (setup.quick_doors)
3158 stepsize = 20; /* must be chosen to always draw last frame */
3159 door_delay_value = 0;
3162 if (global.autoplay_leveldir)
3164 door_state |= DOOR_NO_DELAY;
3165 door_state &= ~DOOR_CLOSE_ALL;
3168 if (door_state & DOOR_ACTION)
3170 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3171 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3172 boolean door_1_done = (!handle_door_1);
3173 boolean door_2_done = (!handle_door_2);
3174 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3175 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3176 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3177 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3178 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3179 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3180 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3181 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3182 int door_skip = max_door_size - door_size;
3183 int end = door_size;
3184 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3187 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3189 /* opening door sound has priority over simultaneously closing door */
3190 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3191 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3192 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3193 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3196 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3199 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3200 GC gc = bitmap->stored_clip_gc;
3202 if (door_state & DOOR_ACTION_1)
3204 int a = MIN(x * door_1.step_offset, end);
3205 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3206 int i = p + door_skip;
3208 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3210 BlitBitmap(bitmap_db_door, drawto,
3211 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3212 DXSIZE, DYSIZE, DX, DY);
3216 BlitBitmap(bitmap_db_door, drawto,
3217 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3218 DXSIZE, DYSIZE - p / 2, DX, DY);
3220 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3223 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3225 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3226 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3227 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3228 int dst2_x = DX, dst2_y = DY;
3229 int width = i, height = DYSIZE;
3231 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3232 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3235 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3236 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3239 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3241 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3242 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3243 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3244 int dst2_x = DX, dst2_y = DY;
3245 int width = DXSIZE, height = i;
3247 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3248 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3251 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3252 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3255 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3257 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3259 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3260 BlitBitmapMasked(bitmap, drawto,
3261 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3262 DX + DXSIZE - i, DY + j);
3263 BlitBitmapMasked(bitmap, drawto,
3264 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3265 DX + DXSIZE - i, DY + 140 + j);
3266 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3267 DY - (DOOR_GFX_PAGEY1 + j));
3268 BlitBitmapMasked(bitmap, drawto,
3269 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3271 BlitBitmapMasked(bitmap, drawto,
3272 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3275 BlitBitmapMasked(bitmap, drawto,
3276 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3278 BlitBitmapMasked(bitmap, drawto,
3279 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3281 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3282 BlitBitmapMasked(bitmap, drawto,
3283 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3284 DX + DXSIZE - i, DY + 77 + j);
3285 BlitBitmapMasked(bitmap, drawto,
3286 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3287 DX + DXSIZE - i, DY + 203 + j);
3290 redraw_mask |= REDRAW_DOOR_1;
3291 door_1_done = (a == end);
3294 if (door_state & DOOR_ACTION_2)
3296 int a = MIN(x * door_2.step_offset, door_size);
3297 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3298 int i = p + door_skip;
3300 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3302 BlitBitmap(bitmap_db_door, drawto,
3303 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3304 VXSIZE, VYSIZE, VX, VY);
3306 else if (x <= VYSIZE)
3308 BlitBitmap(bitmap_db_door, drawto,
3309 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3310 VXSIZE, VYSIZE - p / 2, VX, VY);
3312 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3315 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3317 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3318 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3319 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3320 int dst2_x = VX, dst2_y = VY;
3321 int width = i, height = VYSIZE;
3323 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3324 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3327 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3328 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3331 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3333 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3334 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3335 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3336 int dst2_x = VX, dst2_y = VY;
3337 int width = VXSIZE, height = i;
3339 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3340 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3343 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3344 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3347 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3349 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3351 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3352 BlitBitmapMasked(bitmap, drawto,
3353 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3354 VX + VXSIZE - i, VY + j);
3355 SetClipOrigin(bitmap, gc,
3356 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3357 BlitBitmapMasked(bitmap, drawto,
3358 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3361 BlitBitmapMasked(bitmap, drawto,
3362 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3363 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3364 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3365 BlitBitmapMasked(bitmap, drawto,
3366 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3368 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3371 redraw_mask |= REDRAW_DOOR_2;
3372 door_2_done = (a == VXSIZE);
3375 if (!(door_state & DOOR_NO_DELAY))
3379 if (game_status == GAME_MODE_MAIN)
3382 WaitUntilDelayReached(&door_delay, door_delay_value);
3387 if (door_state & DOOR_ACTION_1)
3388 door1 = door_state & DOOR_ACTION_1;
3389 if (door_state & DOOR_ACTION_2)
3390 door2 = door_state & DOOR_ACTION_2;
3392 return (door1 | door2);
3395 void DrawSpecialEditorDoor()
3397 /* draw bigger toolbox window */
3398 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3399 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3401 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3402 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3405 redraw_mask |= REDRAW_ALL;
3408 void UndrawSpecialEditorDoor()
3410 /* draw normal tape recorder window */
3411 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3412 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3415 redraw_mask |= REDRAW_ALL;
3419 /* ---------- new tool button stuff ---------------------------------------- */
3421 /* graphic position values for tool buttons */
3422 #define TOOL_BUTTON_YES_XPOS 2
3423 #define TOOL_BUTTON_YES_YPOS 250
3424 #define TOOL_BUTTON_YES_GFX_YPOS 0
3425 #define TOOL_BUTTON_YES_XSIZE 46
3426 #define TOOL_BUTTON_YES_YSIZE 28
3427 #define TOOL_BUTTON_NO_XPOS 52
3428 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3429 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3430 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3431 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3432 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3433 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3434 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3435 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3436 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3437 #define TOOL_BUTTON_PLAYER_XSIZE 30
3438 #define TOOL_BUTTON_PLAYER_YSIZE 30
3439 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3440 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3441 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3442 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3443 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3444 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3445 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3446 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3447 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3448 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3449 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3450 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3451 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3452 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3453 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3454 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3455 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3456 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3457 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3458 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3467 } toolbutton_info[NUM_TOOL_BUTTONS] =
3470 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3471 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3472 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3477 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3478 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3479 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3484 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3485 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3486 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3487 TOOL_CTRL_ID_CONFIRM,
3491 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3492 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3493 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3494 TOOL_CTRL_ID_PLAYER_1,
3498 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3499 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3500 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3501 TOOL_CTRL_ID_PLAYER_2,
3505 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3506 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3507 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3508 TOOL_CTRL_ID_PLAYER_3,
3512 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3513 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3514 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3515 TOOL_CTRL_ID_PLAYER_4,
3520 void CreateToolButtons()
3524 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3526 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3527 Bitmap *deco_bitmap = None;
3528 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3529 struct GadgetInfo *gi;
3530 unsigned long event_mask;
3531 int gd_xoffset, gd_yoffset;
3532 int gd_x1, gd_x2, gd_y;
3535 event_mask = GD_EVENT_RELEASED;
3537 gd_xoffset = toolbutton_info[i].xpos;
3538 gd_yoffset = toolbutton_info[i].ypos;
3539 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3540 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3541 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3543 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3545 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3547 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3548 &deco_bitmap, &deco_x, &deco_y);
3549 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3550 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3553 gi = CreateGadget(GDI_CUSTOM_ID, id,
3554 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3555 GDI_X, DX + toolbutton_info[i].x,
3556 GDI_Y, DY + toolbutton_info[i].y,
3557 GDI_WIDTH, toolbutton_info[i].width,
3558 GDI_HEIGHT, toolbutton_info[i].height,
3559 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3560 GDI_STATE, GD_BUTTON_UNPRESSED,
3561 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3562 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3563 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3564 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3565 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3566 GDI_DECORATION_SHIFTING, 1, 1,
3567 GDI_DIRECT_DRAW, FALSE,
3568 GDI_EVENT_MASK, event_mask,
3569 GDI_CALLBACK_ACTION, HandleToolButtons,
3573 Error(ERR_EXIT, "cannot create gadget");
3575 tool_gadget[id] = gi;
3579 void FreeToolButtons()
3583 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3584 FreeGadget(tool_gadget[i]);
3587 static void UnmapToolButtons()
3591 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3592 UnmapGadget(tool_gadget[i]);
3595 static void HandleToolButtons(struct GadgetInfo *gi)
3597 request_gadget_id = gi->custom_id;
3600 static struct Mapping_EM_to_RND_object
3603 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3604 boolean is_backside; /* backside of moving element */
3610 em_object_mapping_list[] =
3613 Xblank, TRUE, FALSE,
3617 Yacid_splash_eB, FALSE, FALSE,
3618 EL_ACID_SPLASH_RIGHT, -1, -1
3621 Yacid_splash_wB, FALSE, FALSE,
3622 EL_ACID_SPLASH_LEFT, -1, -1
3625 #ifdef EM_ENGINE_BAD_ROLL
3627 Xstone_force_e, FALSE, FALSE,
3628 EL_ROCK, -1, MV_BIT_RIGHT
3631 Xstone_force_w, FALSE, FALSE,
3632 EL_ROCK, -1, MV_BIT_LEFT
3635 Xnut_force_e, FALSE, FALSE,
3636 EL_NUT, -1, MV_BIT_RIGHT
3639 Xnut_force_w, FALSE, FALSE,
3640 EL_NUT, -1, MV_BIT_LEFT
3643 Xspring_force_e, FALSE, FALSE,
3644 EL_SPRING, -1, MV_BIT_RIGHT
3647 Xspring_force_w, FALSE, FALSE,
3648 EL_SPRING, -1, MV_BIT_LEFT
3651 Xemerald_force_e, FALSE, FALSE,
3652 EL_EMERALD, -1, MV_BIT_RIGHT
3655 Xemerald_force_w, FALSE, FALSE,
3656 EL_EMERALD, -1, MV_BIT_LEFT
3659 Xdiamond_force_e, FALSE, FALSE,
3660 EL_DIAMOND, -1, MV_BIT_RIGHT
3663 Xdiamond_force_w, FALSE, FALSE,
3664 EL_DIAMOND, -1, MV_BIT_LEFT
3667 Xbomb_force_e, FALSE, FALSE,
3668 EL_BOMB, -1, MV_BIT_RIGHT
3671 Xbomb_force_w, FALSE, FALSE,
3672 EL_BOMB, -1, MV_BIT_LEFT
3674 #endif /* EM_ENGINE_BAD_ROLL */
3677 Xstone, TRUE, FALSE,
3681 Xstone_pause, FALSE, FALSE,
3685 Xstone_fall, FALSE, FALSE,
3689 Ystone_s, FALSE, FALSE,
3690 EL_ROCK, ACTION_FALLING, -1
3693 Ystone_sB, FALSE, TRUE,
3694 EL_ROCK, ACTION_FALLING, -1
3697 Ystone_e, FALSE, FALSE,
3698 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3701 Ystone_eB, FALSE, TRUE,
3702 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3705 Ystone_w, FALSE, FALSE,
3706 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3709 Ystone_wB, FALSE, TRUE,
3710 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3717 Xnut_pause, FALSE, FALSE,
3721 Xnut_fall, FALSE, FALSE,
3725 Ynut_s, FALSE, FALSE,
3726 EL_NUT, ACTION_FALLING, -1
3729 Ynut_sB, FALSE, TRUE,
3730 EL_NUT, ACTION_FALLING, -1
3733 Ynut_e, FALSE, FALSE,
3734 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3737 Ynut_eB, FALSE, TRUE,
3738 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3741 Ynut_w, FALSE, FALSE,
3742 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3745 Ynut_wB, FALSE, TRUE,
3746 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3749 Xbug_n, TRUE, FALSE,
3753 Xbug_e, TRUE, FALSE,
3754 EL_BUG_RIGHT, -1, -1
3757 Xbug_s, TRUE, FALSE,
3761 Xbug_w, TRUE, FALSE,
3765 Xbug_gon, FALSE, FALSE,
3769 Xbug_goe, FALSE, FALSE,
3770 EL_BUG_RIGHT, -1, -1
3773 Xbug_gos, FALSE, FALSE,
3777 Xbug_gow, FALSE, FALSE,
3781 Ybug_n, FALSE, FALSE,
3782 EL_BUG, ACTION_MOVING, MV_BIT_UP
3785 Ybug_nB, FALSE, TRUE,
3786 EL_BUG, ACTION_MOVING, MV_BIT_UP
3789 Ybug_e, FALSE, FALSE,
3790 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3793 Ybug_eB, FALSE, TRUE,
3794 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3797 Ybug_s, FALSE, FALSE,
3798 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3801 Ybug_sB, FALSE, TRUE,
3802 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3805 Ybug_w, FALSE, FALSE,
3806 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3809 Ybug_wB, FALSE, TRUE,
3810 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3813 Ybug_w_n, FALSE, FALSE,
3814 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3817 Ybug_n_e, FALSE, FALSE,
3818 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3821 Ybug_e_s, FALSE, FALSE,
3822 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3825 Ybug_s_w, FALSE, FALSE,
3826 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3829 Ybug_e_n, FALSE, FALSE,
3830 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3833 Ybug_s_e, FALSE, FALSE,
3834 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3837 Ybug_w_s, FALSE, FALSE,
3838 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3841 Ybug_n_w, FALSE, FALSE,
3842 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3845 Ybug_stone, FALSE, FALSE,
3846 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3849 Ybug_spring, FALSE, FALSE,
3850 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3853 Xtank_n, TRUE, FALSE,
3854 EL_SPACESHIP_UP, -1, -1
3857 Xtank_e, TRUE, FALSE,
3858 EL_SPACESHIP_RIGHT, -1, -1
3861 Xtank_s, TRUE, FALSE,
3862 EL_SPACESHIP_DOWN, -1, -1
3865 Xtank_w, TRUE, FALSE,
3866 EL_SPACESHIP_LEFT, -1, -1
3869 Xtank_gon, FALSE, FALSE,
3870 EL_SPACESHIP_UP, -1, -1
3873 Xtank_goe, FALSE, FALSE,
3874 EL_SPACESHIP_RIGHT, -1, -1
3877 Xtank_gos, FALSE, FALSE,
3878 EL_SPACESHIP_DOWN, -1, -1
3881 Xtank_gow, FALSE, FALSE,
3882 EL_SPACESHIP_LEFT, -1, -1
3885 Ytank_n, FALSE, FALSE,
3886 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3889 Ytank_nB, FALSE, TRUE,
3890 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3893 Ytank_e, FALSE, FALSE,
3894 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3897 Ytank_eB, FALSE, TRUE,
3898 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3901 Ytank_s, FALSE, FALSE,
3902 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3905 Ytank_sB, FALSE, TRUE,
3906 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3909 Ytank_w, FALSE, FALSE,
3910 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3913 Ytank_wB, FALSE, TRUE,
3914 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3917 Ytank_w_n, FALSE, FALSE,
3918 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3921 Ytank_n_e, FALSE, FALSE,
3922 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3925 Ytank_e_s, FALSE, FALSE,
3926 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3929 Ytank_s_w, FALSE, FALSE,
3930 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3933 Ytank_e_n, FALSE, FALSE,
3934 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3937 Ytank_s_e, FALSE, FALSE,
3938 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3941 Ytank_w_s, FALSE, FALSE,
3942 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3945 Ytank_n_w, FALSE, FALSE,
3946 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3949 Ytank_stone, FALSE, FALSE,
3950 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3953 Ytank_spring, FALSE, FALSE,
3954 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3957 Xandroid, TRUE, FALSE,
3958 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3961 Xandroid_1_n, FALSE, FALSE,
3962 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3965 Xandroid_2_n, FALSE, FALSE,
3966 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3969 Xandroid_1_e, FALSE, FALSE,
3970 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3973 Xandroid_2_e, FALSE, FALSE,
3974 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3977 Xandroid_1_w, FALSE, FALSE,
3978 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3981 Xandroid_2_w, FALSE, FALSE,
3982 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3985 Xandroid_1_s, FALSE, FALSE,
3986 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3989 Xandroid_2_s, FALSE, FALSE,
3990 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3993 Yandroid_n, FALSE, FALSE,
3994 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3997 Yandroid_nB, FALSE, TRUE,
3998 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4001 Yandroid_ne, FALSE, FALSE,
4002 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4005 Yandroid_neB, FALSE, TRUE,
4006 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4009 Yandroid_e, FALSE, FALSE,
4010 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4013 Yandroid_eB, FALSE, TRUE,
4014 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4017 Yandroid_se, FALSE, FALSE,
4018 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4021 Yandroid_seB, FALSE, TRUE,
4022 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4025 Yandroid_s, FALSE, FALSE,
4026 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4029 Yandroid_sB, FALSE, TRUE,
4030 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4033 Yandroid_sw, FALSE, FALSE,
4034 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4037 Yandroid_swB, FALSE, TRUE,
4038 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4041 Yandroid_w, FALSE, FALSE,
4042 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4045 Yandroid_wB, FALSE, TRUE,
4046 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4049 Yandroid_nw, FALSE, FALSE,
4050 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4053 Yandroid_nwB, FALSE, TRUE,
4054 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4057 Xspring, TRUE, FALSE,
4061 Xspring_pause, FALSE, FALSE,
4065 Xspring_e, FALSE, FALSE,
4069 Xspring_w, FALSE, FALSE,
4073 Xspring_fall, FALSE, FALSE,
4077 Yspring_s, FALSE, FALSE,
4078 EL_SPRING, ACTION_FALLING, -1
4081 Yspring_sB, FALSE, TRUE,
4082 EL_SPRING, ACTION_FALLING, -1
4085 Yspring_e, FALSE, FALSE,
4086 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4089 Yspring_eB, FALSE, TRUE,
4090 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4093 Yspring_w, FALSE, FALSE,
4094 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4097 Yspring_wB, FALSE, TRUE,
4098 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4101 Yspring_kill_e, FALSE, FALSE,
4102 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4105 Yspring_kill_eB, FALSE, TRUE,
4106 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4109 Yspring_kill_w, FALSE, FALSE,
4110 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4113 Yspring_kill_wB, FALSE, TRUE,
4114 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4117 Xeater_n, TRUE, FALSE,
4118 EL_YAMYAM_UP, -1, -1
4121 Xeater_e, TRUE, FALSE,
4122 EL_YAMYAM_RIGHT, -1, -1
4125 Xeater_w, TRUE, FALSE,
4126 EL_YAMYAM_LEFT, -1, -1
4129 Xeater_s, TRUE, FALSE,
4130 EL_YAMYAM_DOWN, -1, -1
4133 Yeater_n, FALSE, FALSE,
4134 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4137 Yeater_nB, FALSE, TRUE,
4138 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4141 Yeater_e, FALSE, FALSE,
4142 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4145 Yeater_eB, FALSE, TRUE,
4146 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4149 Yeater_s, FALSE, FALSE,
4150 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4153 Yeater_sB, FALSE, TRUE,
4154 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4157 Yeater_w, FALSE, FALSE,
4158 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4161 Yeater_wB, FALSE, TRUE,
4162 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4165 Yeater_stone, FALSE, FALSE,
4166 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4169 Yeater_spring, FALSE, FALSE,
4170 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4173 Xalien, TRUE, FALSE,
4177 Xalien_pause, FALSE, FALSE,
4181 Yalien_n, FALSE, FALSE,
4182 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4185 Yalien_nB, FALSE, TRUE,
4186 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4189 Yalien_e, FALSE, FALSE,
4190 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4193 Yalien_eB, FALSE, TRUE,
4194 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4197 Yalien_s, FALSE, FALSE,
4198 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4201 Yalien_sB, FALSE, TRUE,
4202 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4205 Yalien_w, FALSE, FALSE,
4206 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4209 Yalien_wB, FALSE, TRUE,
4210 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4213 Yalien_stone, FALSE, FALSE,
4214 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4217 Yalien_spring, FALSE, FALSE,
4218 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4221 Xemerald, TRUE, FALSE,
4225 Xemerald_pause, FALSE, FALSE,
4229 Xemerald_fall, FALSE, FALSE,
4233 Xemerald_shine, FALSE, FALSE,
4234 EL_EMERALD, ACTION_TWINKLING, -1
4237 Yemerald_s, FALSE, FALSE,
4238 EL_EMERALD, ACTION_FALLING, -1
4241 Yemerald_sB, FALSE, TRUE,
4242 EL_EMERALD, ACTION_FALLING, -1
4245 Yemerald_e, FALSE, FALSE,
4246 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4249 Yemerald_eB, FALSE, TRUE,
4250 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4253 Yemerald_w, FALSE, FALSE,
4254 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4257 Yemerald_wB, FALSE, TRUE,
4258 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4261 Yemerald_eat, FALSE, FALSE,
4262 EL_EMERALD, ACTION_COLLECTING, -1
4265 Yemerald_stone, FALSE, FALSE,
4266 EL_NUT, ACTION_BREAKING, -1
4269 Xdiamond, TRUE, FALSE,
4273 Xdiamond_pause, FALSE, FALSE,
4277 Xdiamond_fall, FALSE, FALSE,
4281 Xdiamond_shine, FALSE, FALSE,
4282 EL_DIAMOND, ACTION_TWINKLING, -1
4285 Ydiamond_s, FALSE, FALSE,
4286 EL_DIAMOND, ACTION_FALLING, -1
4289 Ydiamond_sB, FALSE, TRUE,
4290 EL_DIAMOND, ACTION_FALLING, -1
4293 Ydiamond_e, FALSE, FALSE,
4294 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4297 Ydiamond_eB, FALSE, TRUE,
4298 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4301 Ydiamond_w, FALSE, FALSE,
4302 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4305 Ydiamond_wB, FALSE, TRUE,
4306 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4309 Ydiamond_eat, FALSE, FALSE,
4310 EL_DIAMOND, ACTION_COLLECTING, -1
4313 Ydiamond_stone, FALSE, FALSE,
4314 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4317 Xdrip_fall, TRUE, FALSE,
4318 EL_AMOEBA_DROP, -1, -1
4321 Xdrip_stretch, FALSE, FALSE,
4322 EL_AMOEBA_DROP, ACTION_FALLING, -1
4325 Xdrip_stretchB, FALSE, TRUE,
4326 EL_AMOEBA_DROP, ACTION_FALLING, -1
4329 Xdrip_eat, FALSE, FALSE,
4330 EL_AMOEBA_DROP, ACTION_GROWING, -1
4333 Ydrip_s1, FALSE, FALSE,
4334 EL_AMOEBA_DROP, ACTION_FALLING, -1
4337 Ydrip_s1B, FALSE, TRUE,
4338 EL_AMOEBA_DROP, ACTION_FALLING, -1
4341 Ydrip_s2, FALSE, FALSE,
4342 EL_AMOEBA_DROP, ACTION_FALLING, -1
4345 Ydrip_s2B, FALSE, TRUE,
4346 EL_AMOEBA_DROP, ACTION_FALLING, -1
4353 Xbomb_pause, FALSE, FALSE,
4357 Xbomb_fall, FALSE, FALSE,
4361 Ybomb_s, FALSE, FALSE,
4362 EL_BOMB, ACTION_FALLING, -1
4365 Ybomb_sB, FALSE, TRUE,
4366 EL_BOMB, ACTION_FALLING, -1
4369 Ybomb_e, FALSE, FALSE,
4370 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4373 Ybomb_eB, FALSE, TRUE,
4374 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4377 Ybomb_w, FALSE, FALSE,
4378 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4381 Ybomb_wB, FALSE, TRUE,
4382 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4385 Ybomb_eat, FALSE, FALSE,
4386 EL_BOMB, ACTION_ACTIVATING, -1
4389 Xballoon, TRUE, FALSE,
4393 Yballoon_n, FALSE, FALSE,
4394 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4397 Yballoon_nB, FALSE, TRUE,
4398 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4401 Yballoon_e, FALSE, FALSE,
4402 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4405 Yballoon_eB, FALSE, TRUE,
4406 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4409 Yballoon_s, FALSE, FALSE,
4410 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4413 Yballoon_sB, FALSE, TRUE,
4414 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4417 Yballoon_w, FALSE, FALSE,
4418 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4421 Yballoon_wB, FALSE, TRUE,
4422 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4425 Xgrass, TRUE, FALSE,
4426 EL_EMC_GRASS, -1, -1
4429 Ygrass_nB, FALSE, FALSE,
4430 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4433 Ygrass_eB, FALSE, FALSE,
4434 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4437 Ygrass_sB, FALSE, FALSE,
4438 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4441 Ygrass_wB, FALSE, FALSE,
4442 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4449 Ydirt_nB, FALSE, FALSE,
4450 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4453 Ydirt_eB, FALSE, FALSE,
4454 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4457 Ydirt_sB, FALSE, FALSE,
4458 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4461 Ydirt_wB, FALSE, FALSE,
4462 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4465 Xacid_ne, TRUE, FALSE,
4466 EL_ACID_POOL_TOPRIGHT, -1, -1
4469 Xacid_se, TRUE, FALSE,
4470 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4473 Xacid_s, TRUE, FALSE,
4474 EL_ACID_POOL_BOTTOM, -1, -1
4477 Xacid_sw, TRUE, FALSE,
4478 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4481 Xacid_nw, TRUE, FALSE,
4482 EL_ACID_POOL_TOPLEFT, -1, -1
4485 Xacid_1, TRUE, FALSE,
4489 Xacid_2, FALSE, FALSE,
4493 Xacid_3, FALSE, FALSE,
4497 Xacid_4, FALSE, FALSE,
4501 Xacid_5, FALSE, FALSE,
4505 Xacid_6, FALSE, FALSE,
4509 Xacid_7, FALSE, FALSE,
4513 Xacid_8, FALSE, FALSE,
4517 Xball_1, TRUE, FALSE,
4518 EL_EMC_MAGIC_BALL, -1, -1
4521 Xball_1B, FALSE, FALSE,
4522 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4525 Xball_2, FALSE, FALSE,
4526 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4529 Xball_2B, FALSE, FALSE,
4530 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4533 Yball_eat, FALSE, FALSE,
4534 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4537 Ykey_1_eat, FALSE, FALSE,
4538 EL_EM_KEY_1, ACTION_COLLECTING, -1
4541 Ykey_2_eat, FALSE, FALSE,
4542 EL_EM_KEY_2, ACTION_COLLECTING, -1
4545 Ykey_3_eat, FALSE, FALSE,
4546 EL_EM_KEY_3, ACTION_COLLECTING, -1
4549 Ykey_4_eat, FALSE, FALSE,
4550 EL_EM_KEY_4, ACTION_COLLECTING, -1
4553 Ykey_5_eat, FALSE, FALSE,
4554 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4557 Ykey_6_eat, FALSE, FALSE,
4558 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4561 Ykey_7_eat, FALSE, FALSE,
4562 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4565 Ykey_8_eat, FALSE, FALSE,
4566 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4569 Ylenses_eat, FALSE, FALSE,
4570 EL_EMC_LENSES, ACTION_COLLECTING, -1
4573 Ymagnify_eat, FALSE, FALSE,
4574 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4577 Ygrass_eat, FALSE, FALSE,
4578 EL_EMC_GRASS, ACTION_SNAPPING, -1
4581 Ydirt_eat, FALSE, FALSE,
4582 EL_SAND, ACTION_SNAPPING, -1
4585 Xgrow_ns, TRUE, FALSE,
4586 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4589 Ygrow_ns_eat, FALSE, FALSE,
4590 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4593 Xgrow_ew, TRUE, FALSE,
4594 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4597 Ygrow_ew_eat, FALSE, FALSE,
4598 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4601 Xwonderwall, TRUE, FALSE,
4602 EL_MAGIC_WALL, -1, -1
4605 XwonderwallB, FALSE, FALSE,
4606 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4609 Xamoeba_1, TRUE, FALSE,
4610 EL_AMOEBA_DRY, ACTION_OTHER, -1
4613 Xamoeba_2, FALSE, FALSE,
4614 EL_AMOEBA_DRY, ACTION_OTHER, -1
4617 Xamoeba_3, FALSE, FALSE,
4618 EL_AMOEBA_DRY, ACTION_OTHER, -1
4621 Xamoeba_4, FALSE, FALSE,
4622 EL_AMOEBA_DRY, ACTION_OTHER, -1
4625 Xamoeba_5, TRUE, FALSE,
4626 EL_AMOEBA_WET, ACTION_OTHER, -1
4629 Xamoeba_6, FALSE, FALSE,
4630 EL_AMOEBA_WET, ACTION_OTHER, -1
4633 Xamoeba_7, FALSE, FALSE,
4634 EL_AMOEBA_WET, ACTION_OTHER, -1
4637 Xamoeba_8, FALSE, FALSE,
4638 EL_AMOEBA_WET, ACTION_OTHER, -1
4641 Xdoor_1, TRUE, FALSE,
4642 EL_EM_GATE_1, -1, -1
4645 Xdoor_2, TRUE, FALSE,
4646 EL_EM_GATE_2, -1, -1
4649 Xdoor_3, TRUE, FALSE,
4650 EL_EM_GATE_3, -1, -1
4653 Xdoor_4, TRUE, FALSE,
4654 EL_EM_GATE_4, -1, -1
4657 Xdoor_5, TRUE, FALSE,
4658 EL_EMC_GATE_5, -1, -1
4661 Xdoor_6, TRUE, FALSE,
4662 EL_EMC_GATE_6, -1, -1
4665 Xdoor_7, TRUE, FALSE,
4666 EL_EMC_GATE_7, -1, -1
4669 Xdoor_8, TRUE, FALSE,
4670 EL_EMC_GATE_8, -1, -1
4673 Xkey_1, TRUE, FALSE,
4677 Xkey_2, TRUE, FALSE,
4681 Xkey_3, TRUE, FALSE,
4685 Xkey_4, TRUE, FALSE,
4689 Xkey_5, TRUE, FALSE,
4690 EL_EMC_KEY_5, -1, -1
4693 Xkey_6, TRUE, FALSE,
4694 EL_EMC_KEY_6, -1, -1
4697 Xkey_7, TRUE, FALSE,
4698 EL_EMC_KEY_7, -1, -1
4701 Xkey_8, TRUE, FALSE,
4702 EL_EMC_KEY_8, -1, -1
4705 Xwind_n, TRUE, FALSE,
4706 EL_BALLOON_SWITCH_UP, -1, -1
4709 Xwind_e, TRUE, FALSE,
4710 EL_BALLOON_SWITCH_RIGHT, -1, -1
4713 Xwind_s, TRUE, FALSE,
4714 EL_BALLOON_SWITCH_DOWN, -1, -1
4717 Xwind_w, TRUE, FALSE,
4718 EL_BALLOON_SWITCH_LEFT, -1, -1
4721 Xwind_nesw, TRUE, FALSE,
4722 EL_BALLOON_SWITCH_ANY, -1, -1
4725 Xwind_stop, TRUE, FALSE,
4726 EL_BALLOON_SWITCH_NONE, -1, -1
4730 EL_EM_EXIT_CLOSED, -1, -1
4733 Xexit_1, TRUE, FALSE,
4734 EL_EM_EXIT_OPEN, -1, -1
4737 Xexit_2, FALSE, FALSE,
4738 EL_EM_EXIT_OPEN, -1, -1
4741 Xexit_3, FALSE, FALSE,
4742 EL_EM_EXIT_OPEN, -1, -1
4745 Xdynamite, TRUE, FALSE,
4746 EL_EM_DYNAMITE, -1, -1
4749 Ydynamite_eat, FALSE, FALSE,
4750 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4753 Xdynamite_1, TRUE, FALSE,
4754 EL_EM_DYNAMITE_ACTIVE, -1, -1
4757 Xdynamite_2, FALSE, FALSE,
4758 EL_EM_DYNAMITE_ACTIVE, -1, -1
4761 Xdynamite_3, FALSE, FALSE,
4762 EL_EM_DYNAMITE_ACTIVE, -1, -1
4765 Xdynamite_4, FALSE, FALSE,
4766 EL_EM_DYNAMITE_ACTIVE, -1, -1
4769 Xbumper, TRUE, FALSE,
4770 EL_EMC_SPRING_BUMPER, -1, -1
4773 XbumperB, FALSE, FALSE,
4774 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4777 Xwheel, TRUE, FALSE,
4778 EL_ROBOT_WHEEL, -1, -1
4781 XwheelB, FALSE, FALSE,
4782 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4785 Xswitch, TRUE, FALSE,
4786 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4789 XswitchB, FALSE, FALSE,
4790 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4794 EL_QUICKSAND_EMPTY, -1, -1
4797 Xsand_stone, TRUE, FALSE,
4798 EL_QUICKSAND_FULL, -1, -1
4801 Xsand_stonein_1, FALSE, TRUE,
4802 EL_ROCK, ACTION_FILLING, -1
4805 Xsand_stonein_2, FALSE, TRUE,
4806 EL_ROCK, ACTION_FILLING, -1
4809 Xsand_stonein_3, FALSE, TRUE,
4810 EL_ROCK, ACTION_FILLING, -1
4813 Xsand_stonein_4, FALSE, TRUE,
4814 EL_ROCK, ACTION_FILLING, -1
4817 Xsand_stonesand_1, FALSE, FALSE,
4818 EL_QUICKSAND_FULL, -1, -1
4821 Xsand_stonesand_2, FALSE, FALSE,
4822 EL_QUICKSAND_FULL, -1, -1
4825 Xsand_stonesand_3, FALSE, FALSE,
4826 EL_QUICKSAND_FULL, -1, -1
4829 Xsand_stonesand_4, FALSE, FALSE,
4830 EL_QUICKSAND_FULL, -1, -1
4833 Xsand_stoneout_1, FALSE, FALSE,
4834 EL_ROCK, ACTION_EMPTYING, -1
4837 Xsand_stoneout_2, FALSE, FALSE,
4838 EL_ROCK, ACTION_EMPTYING, -1
4841 Xsand_sandstone_1, FALSE, FALSE,
4842 EL_QUICKSAND_FULL, -1, -1
4845 Xsand_sandstone_2, FALSE, FALSE,
4846 EL_QUICKSAND_FULL, -1, -1
4849 Xsand_sandstone_3, FALSE, FALSE,
4850 EL_QUICKSAND_FULL, -1, -1
4853 Xsand_sandstone_4, FALSE, FALSE,
4854 EL_QUICKSAND_FULL, -1, -1
4857 Xplant, TRUE, FALSE,
4858 EL_EMC_PLANT, -1, -1
4861 Yplant, FALSE, FALSE,
4862 EL_EMC_PLANT, -1, -1
4865 Xlenses, TRUE, FALSE,
4866 EL_EMC_LENSES, -1, -1
4869 Xmagnify, TRUE, FALSE,
4870 EL_EMC_MAGNIFIER, -1, -1
4873 Xdripper, TRUE, FALSE,
4874 EL_EMC_DRIPPER, -1, -1
4877 XdripperB, FALSE, FALSE,
4878 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4881 Xfake_blank, TRUE, FALSE,
4882 EL_INVISIBLE_WALL, -1, -1
4885 Xfake_blankB, FALSE, FALSE,
4886 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4889 Xfake_grass, TRUE, FALSE,
4890 EL_EMC_FAKE_GRASS, -1, -1
4893 Xfake_grassB, FALSE, FALSE,
4894 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4897 Xfake_door_1, TRUE, FALSE,
4898 EL_EM_GATE_1_GRAY, -1, -1
4901 Xfake_door_2, TRUE, FALSE,
4902 EL_EM_GATE_2_GRAY, -1, -1
4905 Xfake_door_3, TRUE, FALSE,
4906 EL_EM_GATE_3_GRAY, -1, -1
4909 Xfake_door_4, TRUE, FALSE,
4910 EL_EM_GATE_4_GRAY, -1, -1
4913 Xfake_door_5, TRUE, FALSE,
4914 EL_EMC_GATE_5_GRAY, -1, -1
4917 Xfake_door_6, TRUE, FALSE,
4918 EL_EMC_GATE_6_GRAY, -1, -1
4921 Xfake_door_7, TRUE, FALSE,
4922 EL_EMC_GATE_7_GRAY, -1, -1
4925 Xfake_door_8, TRUE, FALSE,
4926 EL_EMC_GATE_8_GRAY, -1, -1
4929 Xfake_acid_1, TRUE, FALSE,
4930 EL_EMC_FAKE_ACID, -1, -1
4933 Xfake_acid_2, FALSE, FALSE,
4934 EL_EMC_FAKE_ACID, -1, -1
4937 Xfake_acid_3, FALSE, FALSE,
4938 EL_EMC_FAKE_ACID, -1, -1
4941 Xfake_acid_4, FALSE, FALSE,
4942 EL_EMC_FAKE_ACID, -1, -1
4945 Xfake_acid_5, FALSE, FALSE,
4946 EL_EMC_FAKE_ACID, -1, -1
4949 Xfake_acid_6, FALSE, FALSE,
4950 EL_EMC_FAKE_ACID, -1, -1
4953 Xfake_acid_7, FALSE, FALSE,
4954 EL_EMC_FAKE_ACID, -1, -1
4957 Xfake_acid_8, FALSE, FALSE,
4958 EL_EMC_FAKE_ACID, -1, -1
4961 Xsteel_1, TRUE, FALSE,
4962 EL_STEELWALL, -1, -1
4965 Xsteel_2, TRUE, FALSE,
4966 EL_EMC_STEELWALL_2, -1, -1
4969 Xsteel_3, TRUE, FALSE,
4970 EL_EMC_STEELWALL_3, -1, -1
4973 Xsteel_4, TRUE, FALSE,
4974 EL_EMC_STEELWALL_4, -1, -1
4977 Xwall_1, TRUE, FALSE,
4981 Xwall_2, TRUE, FALSE,
4982 EL_EMC_WALL_14, -1, -1
4985 Xwall_3, TRUE, FALSE,
4986 EL_EMC_WALL_15, -1, -1
4989 Xwall_4, TRUE, FALSE,
4990 EL_EMC_WALL_16, -1, -1
4993 Xround_wall_1, TRUE, FALSE,
4994 EL_WALL_SLIPPERY, -1, -1
4997 Xround_wall_2, TRUE, FALSE,
4998 EL_EMC_WALL_SLIPPERY_2, -1, -1
5001 Xround_wall_3, TRUE, FALSE,
5002 EL_EMC_WALL_SLIPPERY_3, -1, -1
5005 Xround_wall_4, TRUE, FALSE,
5006 EL_EMC_WALL_SLIPPERY_4, -1, -1
5009 Xdecor_1, TRUE, FALSE,
5010 EL_EMC_WALL_8, -1, -1
5013 Xdecor_2, TRUE, FALSE,
5014 EL_EMC_WALL_6, -1, -1
5017 Xdecor_3, TRUE, FALSE,
5018 EL_EMC_WALL_4, -1, -1
5021 Xdecor_4, TRUE, FALSE,
5022 EL_EMC_WALL_7, -1, -1
5025 Xdecor_5, TRUE, FALSE,
5026 EL_EMC_WALL_5, -1, -1
5029 Xdecor_6, TRUE, FALSE,
5030 EL_EMC_WALL_9, -1, -1
5033 Xdecor_7, TRUE, FALSE,
5034 EL_EMC_WALL_10, -1, -1
5037 Xdecor_8, TRUE, FALSE,
5038 EL_EMC_WALL_1, -1, -1
5041 Xdecor_9, TRUE, FALSE,
5042 EL_EMC_WALL_2, -1, -1
5045 Xdecor_10, TRUE, FALSE,
5046 EL_EMC_WALL_3, -1, -1
5049 Xdecor_11, TRUE, FALSE,
5050 EL_EMC_WALL_11, -1, -1
5053 Xdecor_12, TRUE, FALSE,
5054 EL_EMC_WALL_12, -1, -1
5057 Xalpha_0, TRUE, FALSE,
5058 EL_CHAR('0'), -1, -1
5061 Xalpha_1, TRUE, FALSE,
5062 EL_CHAR('1'), -1, -1
5065 Xalpha_2, TRUE, FALSE,
5066 EL_CHAR('2'), -1, -1
5069 Xalpha_3, TRUE, FALSE,
5070 EL_CHAR('3'), -1, -1
5073 Xalpha_4, TRUE, FALSE,
5074 EL_CHAR('4'), -1, -1
5077 Xalpha_5, TRUE, FALSE,
5078 EL_CHAR('5'), -1, -1
5081 Xalpha_6, TRUE, FALSE,
5082 EL_CHAR('6'), -1, -1
5085 Xalpha_7, TRUE, FALSE,
5086 EL_CHAR('7'), -1, -1
5089 Xalpha_8, TRUE, FALSE,
5090 EL_CHAR('8'), -1, -1
5093 Xalpha_9, TRUE, FALSE,
5094 EL_CHAR('9'), -1, -1
5097 Xalpha_excla, TRUE, FALSE,
5098 EL_CHAR('!'), -1, -1
5101 Xalpha_quote, TRUE, FALSE,
5102 EL_CHAR('"'), -1, -1
5105 Xalpha_comma, TRUE, FALSE,
5106 EL_CHAR(','), -1, -1
5109 Xalpha_minus, TRUE, FALSE,
5110 EL_CHAR('-'), -1, -1
5113 Xalpha_perio, TRUE, FALSE,
5114 EL_CHAR('.'), -1, -1
5117 Xalpha_colon, TRUE, FALSE,
5118 EL_CHAR(':'), -1, -1
5121 Xalpha_quest, TRUE, FALSE,
5122 EL_CHAR('?'), -1, -1
5125 Xalpha_a, TRUE, FALSE,
5126 EL_CHAR('A'), -1, -1
5129 Xalpha_b, TRUE, FALSE,
5130 EL_CHAR('B'), -1, -1
5133 Xalpha_c, TRUE, FALSE,
5134 EL_CHAR('C'), -1, -1
5137 Xalpha_d, TRUE, FALSE,
5138 EL_CHAR('D'), -1, -1
5141 Xalpha_e, TRUE, FALSE,
5142 EL_CHAR('E'), -1, -1
5145 Xalpha_f, TRUE, FALSE,
5146 EL_CHAR('F'), -1, -1
5149 Xalpha_g, TRUE, FALSE,
5150 EL_CHAR('G'), -1, -1
5153 Xalpha_h, TRUE, FALSE,
5154 EL_CHAR('H'), -1, -1
5157 Xalpha_i, TRUE, FALSE,
5158 EL_CHAR('I'), -1, -1
5161 Xalpha_j, TRUE, FALSE,
5162 EL_CHAR('J'), -1, -1
5165 Xalpha_k, TRUE, FALSE,
5166 EL_CHAR('K'), -1, -1
5169 Xalpha_l, TRUE, FALSE,
5170 EL_CHAR('L'), -1, -1
5173 Xalpha_m, TRUE, FALSE,
5174 EL_CHAR('M'), -1, -1
5177 Xalpha_n, TRUE, FALSE,
5178 EL_CHAR('N'), -1, -1
5181 Xalpha_o, TRUE, FALSE,
5182 EL_CHAR('O'), -1, -1
5185 Xalpha_p, TRUE, FALSE,
5186 EL_CHAR('P'), -1, -1
5189 Xalpha_q, TRUE, FALSE,
5190 EL_CHAR('Q'), -1, -1
5193 Xalpha_r, TRUE, FALSE,
5194 EL_CHAR('R'), -1, -1
5197 Xalpha_s, TRUE, FALSE,
5198 EL_CHAR('S'), -1, -1
5201 Xalpha_t, TRUE, FALSE,
5202 EL_CHAR('T'), -1, -1
5205 Xalpha_u, TRUE, FALSE,
5206 EL_CHAR('U'), -1, -1
5209 Xalpha_v, TRUE, FALSE,
5210 EL_CHAR('V'), -1, -1
5213 Xalpha_w, TRUE, FALSE,
5214 EL_CHAR('W'), -1, -1
5217 Xalpha_x, TRUE, FALSE,
5218 EL_CHAR('X'), -1, -1
5221 Xalpha_y, TRUE, FALSE,
5222 EL_CHAR('Y'), -1, -1
5225 Xalpha_z, TRUE, FALSE,
5226 EL_CHAR('Z'), -1, -1
5229 Xalpha_arrow_e, TRUE, FALSE,
5230 EL_CHAR('>'), -1, -1
5233 Xalpha_arrow_w, TRUE, FALSE,
5234 EL_CHAR('<'), -1, -1
5237 Xalpha_copyr, TRUE, FALSE,
5238 EL_CHAR('©'), -1, -1
5242 Xboom_bug, FALSE, FALSE,
5243 EL_BUG, ACTION_EXPLODING, -1
5246 Xboom_bomb, FALSE, FALSE,
5247 EL_BOMB, ACTION_EXPLODING, -1
5250 Xboom_android, FALSE, FALSE,
5251 EL_EMC_ANDROID, ACTION_OTHER, -1
5254 Xboom_1, FALSE, FALSE,
5255 EL_DEFAULT, ACTION_EXPLODING, -1
5258 Xboom_2, FALSE, FALSE,
5259 EL_DEFAULT, ACTION_EXPLODING, -1
5262 Znormal, FALSE, FALSE,
5266 Zdynamite, FALSE, FALSE,
5270 Zplayer, FALSE, FALSE,
5274 ZBORDER, FALSE, FALSE,
5284 static struct Mapping_EM_to_RND_player
5293 em_player_mapping_list[] =
5297 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5301 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5305 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5309 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5313 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5317 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5321 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5325 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5329 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5333 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5337 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5341 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5345 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5349 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5353 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5357 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5361 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5365 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5369 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5373 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5377 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5381 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5385 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5389 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5393 EL_PLAYER_1, ACTION_DEFAULT, -1,
5397 EL_PLAYER_2, ACTION_DEFAULT, -1,
5401 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5405 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5409 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5413 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5417 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5421 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5425 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5429 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5433 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5437 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5441 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5445 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5449 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5453 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5457 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5461 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5465 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5469 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5473 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5477 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5481 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5485 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5489 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5493 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5497 EL_PLAYER_3, ACTION_DEFAULT, -1,
5501 EL_PLAYER_4, ACTION_DEFAULT, -1,
5510 int map_element_RND_to_EM(int element_rnd)
5512 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5513 static boolean mapping_initialized = FALSE;
5515 if (!mapping_initialized)
5519 /* return "Xalpha_quest" for all undefined elements in mapping array */
5520 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5521 mapping_RND_to_EM[i] = Xalpha_quest;
5523 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5524 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5525 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5526 em_object_mapping_list[i].element_em;
5528 mapping_initialized = TRUE;
5531 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5532 return mapping_RND_to_EM[element_rnd];
5534 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5539 int map_element_EM_to_RND(int element_em)
5541 static unsigned short mapping_EM_to_RND[TILE_MAX];
5542 static boolean mapping_initialized = FALSE;
5544 if (!mapping_initialized)
5548 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5549 for (i = 0; i < TILE_MAX; i++)
5550 mapping_EM_to_RND[i] = EL_UNKNOWN;
5552 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5553 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5554 em_object_mapping_list[i].element_rnd;
5556 mapping_initialized = TRUE;
5559 if (element_em >= 0 && element_em < TILE_MAX)
5560 return mapping_EM_to_RND[element_em];
5562 Error(ERR_WARN, "invalid EM level element %d", element_em);
5567 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5569 struct LevelInfo_EM *level_em = level->native_em_level;
5570 struct LEVEL *lev = level_em->lev;
5573 for (i = 0; i < TILE_MAX; i++)
5574 lev->android_array[i] = Xblank;
5576 for (i = 0; i < level->num_android_clone_elements; i++)
5578 int element_rnd = level->android_clone_element[i];
5579 int element_em = map_element_RND_to_EM(element_rnd);
5581 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5582 if (em_object_mapping_list[j].element_rnd == element_rnd)
5583 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5587 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5589 struct LevelInfo_EM *level_em = level->native_em_level;
5590 struct LEVEL *lev = level_em->lev;
5593 level->num_android_clone_elements = 0;
5595 for (i = 0; i < TILE_MAX; i++)
5597 int element_em = lev->android_array[i];
5599 boolean element_found = FALSE;
5601 if (element_em == Xblank)
5604 element_rnd = map_element_EM_to_RND(element_em);
5606 for (j = 0; j < level->num_android_clone_elements; j++)
5607 if (level->android_clone_element[j] == element_rnd)
5608 element_found = TRUE;
5612 level->android_clone_element[level->num_android_clone_elements++] =
5615 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5620 if (level->num_android_clone_elements == 0)
5622 level->num_android_clone_elements = 1;
5623 level->android_clone_element[0] = EL_EMPTY;
5627 int map_direction_RND_to_EM(int direction)
5629 return (direction == MV_UP ? 0 :
5630 direction == MV_RIGHT ? 1 :
5631 direction == MV_DOWN ? 2 :
5632 direction == MV_LEFT ? 3 :
5636 int map_direction_EM_to_RND(int direction)
5638 return (direction == 0 ? MV_UP :
5639 direction == 1 ? MV_RIGHT :
5640 direction == 2 ? MV_DOWN :
5641 direction == 3 ? MV_LEFT :
5645 int get_next_element(int element)
5649 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5650 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5651 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5652 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5653 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5654 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5655 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5656 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5657 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5658 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5659 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5661 default: return element;
5666 int el_act_dir2img(int element, int action, int direction)
5668 element = GFX_ELEMENT(element);
5670 if (direction == MV_NONE)
5671 return element_info[element].graphic[action];
5673 direction = MV_DIR_TO_BIT(direction);
5675 return element_info[element].direction_graphic[action][direction];
5678 int el_act_dir2img(int element, int action, int direction)
5680 element = GFX_ELEMENT(element);
5681 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5683 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5684 return element_info[element].direction_graphic[action][direction];
5689 static int el_act_dir2crm(int element, int action, int direction)
5691 element = GFX_ELEMENT(element);
5693 if (direction == MV_NONE)
5694 return element_info[element].crumbled[action];
5696 direction = MV_DIR_TO_BIT(direction);
5698 return element_info[element].direction_crumbled[action][direction];
5701 static int el_act_dir2crm(int element, int action, int direction)
5703 element = GFX_ELEMENT(element);
5704 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5706 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5707 return element_info[element].direction_crumbled[action][direction];
5711 int el_act2img(int element, int action)
5713 element = GFX_ELEMENT(element);
5715 return element_info[element].graphic[action];
5718 int el_act2crm(int element, int action)
5720 element = GFX_ELEMENT(element);
5722 return element_info[element].crumbled[action];
5725 int el_dir2img(int element, int direction)
5727 element = GFX_ELEMENT(element);
5729 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5732 int el2baseimg(int element)
5734 return element_info[element].graphic[ACTION_DEFAULT];
5737 int el2img(int element)
5739 element = GFX_ELEMENT(element);
5741 return element_info[element].graphic[ACTION_DEFAULT];
5744 int el2edimg(int element)
5746 element = GFX_ELEMENT(element);
5748 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5751 int el2preimg(int element)
5753 element = GFX_ELEMENT(element);
5755 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5758 int el2doorimg(int element)
5760 element = GFX_ELEMENT(element);
5762 return element_info[element].special_graphic[GFX_SPECIAL_ARG_DOOR];
5765 int font2baseimg(int font_nr)
5767 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5770 int getBeltNrFromBeltElement(int element)
5772 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5773 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5774 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5777 int getBeltNrFromBeltActiveElement(int element)
5779 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5780 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5781 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5784 int getBeltNrFromBeltSwitchElement(int element)
5786 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5787 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5788 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5791 int getBeltDirNrFromBeltElement(int element)
5793 static int belt_base_element[4] =
5795 EL_CONVEYOR_BELT_1_LEFT,
5796 EL_CONVEYOR_BELT_2_LEFT,
5797 EL_CONVEYOR_BELT_3_LEFT,
5798 EL_CONVEYOR_BELT_4_LEFT
5801 int belt_nr = getBeltNrFromBeltElement(element);
5802 int belt_dir_nr = element - belt_base_element[belt_nr];
5804 return (belt_dir_nr % 3);
5807 int getBeltDirNrFromBeltSwitchElement(int element)
5809 static int belt_base_element[4] =
5811 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5812 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5813 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5814 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5817 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5818 int belt_dir_nr = element - belt_base_element[belt_nr];
5820 return (belt_dir_nr % 3);
5823 int getBeltDirFromBeltElement(int element)
5825 static int belt_move_dir[3] =
5832 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5834 return belt_move_dir[belt_dir_nr];
5837 int getBeltDirFromBeltSwitchElement(int element)
5839 static int belt_move_dir[3] =
5846 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5848 return belt_move_dir[belt_dir_nr];
5851 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5853 static int belt_base_element[4] =
5855 EL_CONVEYOR_BELT_1_LEFT,
5856 EL_CONVEYOR_BELT_2_LEFT,
5857 EL_CONVEYOR_BELT_3_LEFT,
5858 EL_CONVEYOR_BELT_4_LEFT
5860 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5862 return belt_base_element[belt_nr] + belt_dir_nr;
5865 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5867 static int belt_base_element[4] =
5869 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5870 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5871 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5872 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5874 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5876 return belt_base_element[belt_nr] + belt_dir_nr;
5879 int getNumActivePlayers_EM()
5881 int num_players = 0;
5887 for (i = 0; i < MAX_PLAYERS; i++)
5888 if (tape.player_participates[i])
5894 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5896 int game_frame_delay_value;
5898 game_frame_delay_value =
5899 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5900 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5903 if (tape.playing && tape.warp_forward && !tape.pausing)
5904 game_frame_delay_value = 0;
5906 return game_frame_delay_value;
5909 unsigned int InitRND(long seed)
5911 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5912 return InitEngineRandom_EM(seed);
5914 return InitEngineRandom_RND(seed);
5918 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5919 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5922 void ResetGfxAnimation_EM(int x, int y, int tile)
5927 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5928 Bitmap **src_bitmap, int *src_x, int *src_y,
5931 int element = object_mapping[tile].element_rnd;
5932 int action = object_mapping[tile].action;
5933 int direction = object_mapping[tile].direction;
5934 boolean is_backside = object_mapping[tile].is_backside;
5935 boolean action_removing = (action == ACTION_DIGGING ||
5936 action == ACTION_SNAPPING ||
5937 action == ACTION_COLLECTING);
5938 int effective_element = (frame_em > 0 ? element :
5939 is_backside ? EL_EMPTY :
5940 action_removing ? EL_EMPTY :
5942 int graphic = (direction == MV_NONE ?
5943 el_act2img(effective_element, action) :
5944 el_act_dir2img(effective_element, action, direction));
5945 struct GraphicInfo *g = &graphic_info[graphic];
5948 if (graphic_info[graphic].anim_global_sync)
5949 sync_frame = FrameCounter;
5951 sync_frame = 7 - frame_em;
5953 SetRandomAnimationValue(x, y);
5955 int frame = getAnimationFrame(g->anim_frames,
5958 g->anim_start_frame,
5961 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5964 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
5965 Bitmap **src_bitmap, int *src_x, int *src_y)
5967 int element = player_mapping[player_nr][anim].element_rnd;
5968 int action = player_mapping[player_nr][anim].action;
5969 int direction = player_mapping[player_nr][anim].direction;
5970 int graphic = (direction == MV_NONE ?
5971 el_act2img(element, action) :
5972 el_act_dir2img(element, action, direction));
5973 struct GraphicInfo *g = &graphic_info[graphic];
5976 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
5978 stored_player[player_nr].StepFrame = 7 - frame_em;
5980 sync_frame = stored_player[player_nr].Frame;
5983 printf("::: %d: %d, %d [%d]\n",
5985 stored_player[player_nr].Frame,
5986 stored_player[player_nr].StepFrame,
5990 int frame = getAnimationFrame(g->anim_frames,
5993 g->anim_start_frame,
5996 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5999 void InitGraphicInfo_EM(void)
6002 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6003 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6008 int num_em_gfx_errors = 0;
6010 if (graphic_info_em_object[0][0].bitmap == NULL)
6012 /* EM graphics not yet initialized in em_open_all() */
6017 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6020 /* always start with reliable default values */
6021 for (i = 0; i < TILE_MAX; i++)
6023 object_mapping[i].element_rnd = EL_UNKNOWN;
6024 object_mapping[i].is_backside = FALSE;
6025 object_mapping[i].action = ACTION_DEFAULT;
6026 object_mapping[i].direction = MV_NONE;
6029 /* always start with reliable default values */
6030 for (p = 0; p < MAX_PLAYERS; p++)
6032 for (i = 0; i < SPR_MAX; i++)
6034 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6035 player_mapping[p][i].action = ACTION_DEFAULT;
6036 player_mapping[p][i].direction = MV_NONE;
6040 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6042 int e = em_object_mapping_list[i].element_em;
6044 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6045 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6047 if (em_object_mapping_list[i].action != -1)
6048 object_mapping[e].action = em_object_mapping_list[i].action;
6050 if (em_object_mapping_list[i].direction != -1)
6051 object_mapping[e].direction =
6052 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6055 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6057 int a = em_player_mapping_list[i].action_em;
6058 int p = em_player_mapping_list[i].player_nr;
6060 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6062 if (em_player_mapping_list[i].action != -1)
6063 player_mapping[p][a].action = em_player_mapping_list[i].action;
6065 if (em_player_mapping_list[i].direction != -1)
6066 player_mapping[p][a].direction =
6067 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6070 for (i = 0; i < TILE_MAX; i++)
6072 int element = object_mapping[i].element_rnd;
6073 int action = object_mapping[i].action;
6074 int direction = object_mapping[i].direction;
6075 boolean is_backside = object_mapping[i].is_backside;
6076 boolean action_removing = (action == ACTION_DIGGING ||
6077 action == ACTION_SNAPPING ||
6078 action == ACTION_COLLECTING);
6079 boolean action_exploding = ((action == ACTION_EXPLODING ||
6080 action == ACTION_SMASHED_BY_ROCK ||
6081 action == ACTION_SMASHED_BY_SPRING) &&
6082 element != EL_DIAMOND);
6083 boolean action_active = (action == ACTION_ACTIVE);
6084 boolean action_other = (action == ACTION_OTHER);
6086 for (j = 0; j < 8; j++)
6088 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6089 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6091 i == Xdrip_stretch ? element :
6092 i == Xdrip_stretchB ? element :
6093 i == Ydrip_s1 ? element :
6094 i == Ydrip_s1B ? element :
6095 i == Xball_1B ? element :
6096 i == Xball_2 ? element :
6097 i == Xball_2B ? element :
6098 i == Yball_eat ? element :
6099 i == Ykey_1_eat ? element :
6100 i == Ykey_2_eat ? element :
6101 i == Ykey_3_eat ? element :
6102 i == Ykey_4_eat ? element :
6103 i == Ykey_5_eat ? element :
6104 i == Ykey_6_eat ? element :
6105 i == Ykey_7_eat ? element :
6106 i == Ykey_8_eat ? element :
6107 i == Ylenses_eat ? element :
6108 i == Ymagnify_eat ? element :
6109 i == Ygrass_eat ? element :
6110 i == Ydirt_eat ? element :
6111 i == Yemerald_stone ? EL_EMERALD :
6112 i == Ydiamond_stone ? EL_ROCK :
6113 i == Xsand_stonein_1 ? element :
6114 i == Xsand_stonein_2 ? element :
6115 i == Xsand_stonein_3 ? element :
6116 i == Xsand_stonein_4 ? element :
6117 is_backside ? EL_EMPTY :
6118 action_removing ? EL_EMPTY :
6120 int effective_action = (j < 7 ? action :
6121 i == Xdrip_stretch ? action :
6122 i == Xdrip_stretchB ? action :
6123 i == Ydrip_s1 ? action :
6124 i == Ydrip_s1B ? action :
6125 i == Xball_1B ? action :
6126 i == Xball_2 ? action :
6127 i == Xball_2B ? action :
6128 i == Yball_eat ? action :
6129 i == Ykey_1_eat ? action :
6130 i == Ykey_2_eat ? action :
6131 i == Ykey_3_eat ? action :
6132 i == Ykey_4_eat ? action :
6133 i == Ykey_5_eat ? action :
6134 i == Ykey_6_eat ? action :
6135 i == Ykey_7_eat ? action :
6136 i == Ykey_8_eat ? action :
6137 i == Ylenses_eat ? action :
6138 i == Ymagnify_eat ? action :
6139 i == Ygrass_eat ? action :
6140 i == Ydirt_eat ? action :
6141 i == Xsand_stonein_1 ? action :
6142 i == Xsand_stonein_2 ? action :
6143 i == Xsand_stonein_3 ? action :
6144 i == Xsand_stonein_4 ? action :
6145 i == Xsand_stoneout_1 ? action :
6146 i == Xsand_stoneout_2 ? action :
6147 i == Xboom_android ? ACTION_EXPLODING :
6148 action_exploding ? ACTION_EXPLODING :
6149 action_active ? action :
6150 action_other ? action :
6152 int graphic = (el_act_dir2img(effective_element, effective_action,
6154 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6156 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6157 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6158 boolean has_action_graphics = (graphic != base_graphic);
6159 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6160 struct GraphicInfo *g = &graphic_info[graphic];
6161 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6164 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6165 boolean special_animation = (action != ACTION_DEFAULT &&
6166 g->anim_frames == 3 &&
6167 g->anim_delay == 2 &&
6168 g->anim_mode & ANIM_LINEAR);
6169 int sync_frame = (i == Xdrip_stretch ? 7 :
6170 i == Xdrip_stretchB ? 7 :
6171 i == Ydrip_s2 ? j + 8 :
6172 i == Ydrip_s2B ? j + 8 :
6181 i == Xfake_acid_1 ? 0 :
6182 i == Xfake_acid_2 ? 10 :
6183 i == Xfake_acid_3 ? 20 :
6184 i == Xfake_acid_4 ? 30 :
6185 i == Xfake_acid_5 ? 40 :
6186 i == Xfake_acid_6 ? 50 :
6187 i == Xfake_acid_7 ? 60 :
6188 i == Xfake_acid_8 ? 70 :
6190 i == Xball_2B ? j + 8 :
6191 i == Yball_eat ? j + 1 :
6192 i == Ykey_1_eat ? j + 1 :
6193 i == Ykey_2_eat ? j + 1 :
6194 i == Ykey_3_eat ? j + 1 :
6195 i == Ykey_4_eat ? j + 1 :
6196 i == Ykey_5_eat ? j + 1 :
6197 i == Ykey_6_eat ? j + 1 :
6198 i == Ykey_7_eat ? j + 1 :
6199 i == Ykey_8_eat ? j + 1 :
6200 i == Ylenses_eat ? j + 1 :
6201 i == Ymagnify_eat ? j + 1 :
6202 i == Ygrass_eat ? j + 1 :
6203 i == Ydirt_eat ? j + 1 :
6204 i == Xamoeba_1 ? 0 :
6205 i == Xamoeba_2 ? 1 :
6206 i == Xamoeba_3 ? 2 :
6207 i == Xamoeba_4 ? 3 :
6208 i == Xamoeba_5 ? 0 :
6209 i == Xamoeba_6 ? 1 :
6210 i == Xamoeba_7 ? 2 :
6211 i == Xamoeba_8 ? 3 :
6212 i == Xexit_2 ? j + 8 :
6213 i == Xexit_3 ? j + 16 :
6214 i == Xdynamite_1 ? 0 :
6215 i == Xdynamite_2 ? 8 :
6216 i == Xdynamite_3 ? 16 :
6217 i == Xdynamite_4 ? 24 :
6218 i == Xsand_stonein_1 ? j + 1 :
6219 i == Xsand_stonein_2 ? j + 9 :
6220 i == Xsand_stonein_3 ? j + 17 :
6221 i == Xsand_stonein_4 ? j + 25 :
6222 i == Xsand_stoneout_1 && j == 0 ? 0 :
6223 i == Xsand_stoneout_1 && j == 1 ? 0 :
6224 i == Xsand_stoneout_1 && j == 2 ? 1 :
6225 i == Xsand_stoneout_1 && j == 3 ? 2 :
6226 i == Xsand_stoneout_1 && j == 4 ? 2 :
6227 i == Xsand_stoneout_1 && j == 5 ? 3 :
6228 i == Xsand_stoneout_1 && j == 6 ? 4 :
6229 i == Xsand_stoneout_1 && j == 7 ? 4 :
6230 i == Xsand_stoneout_2 && j == 0 ? 5 :
6231 i == Xsand_stoneout_2 && j == 1 ? 6 :
6232 i == Xsand_stoneout_2 && j == 2 ? 7 :
6233 i == Xsand_stoneout_2 && j == 3 ? 8 :
6234 i == Xsand_stoneout_2 && j == 4 ? 9 :
6235 i == Xsand_stoneout_2 && j == 5 ? 11 :
6236 i == Xsand_stoneout_2 && j == 6 ? 13 :
6237 i == Xsand_stoneout_2 && j == 7 ? 15 :
6238 i == Xboom_bug && j == 1 ? 2 :
6239 i == Xboom_bug && j == 2 ? 2 :
6240 i == Xboom_bug && j == 3 ? 4 :
6241 i == Xboom_bug && j == 4 ? 4 :
6242 i == Xboom_bug && j == 5 ? 2 :
6243 i == Xboom_bug && j == 6 ? 2 :
6244 i == Xboom_bug && j == 7 ? 0 :
6245 i == Xboom_bomb && j == 1 ? 2 :
6246 i == Xboom_bomb && j == 2 ? 2 :
6247 i == Xboom_bomb && j == 3 ? 4 :
6248 i == Xboom_bomb && j == 4 ? 4 :
6249 i == Xboom_bomb && j == 5 ? 2 :
6250 i == Xboom_bomb && j == 6 ? 2 :
6251 i == Xboom_bomb && j == 7 ? 0 :
6252 i == Xboom_android && j == 7 ? 6 :
6253 i == Xboom_1 && j == 1 ? 2 :
6254 i == Xboom_1 && j == 2 ? 2 :
6255 i == Xboom_1 && j == 3 ? 4 :
6256 i == Xboom_1 && j == 4 ? 4 :
6257 i == Xboom_1 && j == 5 ? 6 :
6258 i == Xboom_1 && j == 6 ? 6 :
6259 i == Xboom_1 && j == 7 ? 8 :
6260 i == Xboom_2 && j == 0 ? 8 :
6261 i == Xboom_2 && j == 1 ? 8 :
6262 i == Xboom_2 && j == 2 ? 10 :
6263 i == Xboom_2 && j == 3 ? 10 :
6264 i == Xboom_2 && j == 4 ? 10 :
6265 i == Xboom_2 && j == 5 ? 12 :
6266 i == Xboom_2 && j == 6 ? 12 :
6267 i == Xboom_2 && j == 7 ? 12 :
6268 special_animation && j == 4 ? 3 :
6269 effective_action != action ? 0 :
6273 Bitmap *debug_bitmap = g_em->bitmap;
6274 int debug_src_x = g_em->src_x;
6275 int debug_src_y = g_em->src_y;
6278 int frame = getAnimationFrame(g->anim_frames,
6281 g->anim_start_frame,
6284 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6285 g->double_movement && is_backside);
6287 g_em->bitmap = src_bitmap;
6288 g_em->src_x = src_x;
6289 g_em->src_y = src_y;
6290 g_em->src_offset_x = 0;
6291 g_em->src_offset_y = 0;
6292 g_em->dst_offset_x = 0;
6293 g_em->dst_offset_y = 0;
6294 g_em->width = TILEX;
6295 g_em->height = TILEY;
6297 g_em->crumbled_bitmap = NULL;
6298 g_em->crumbled_src_x = 0;
6299 g_em->crumbled_src_y = 0;
6300 g_em->crumbled_border_size = 0;
6302 g_em->has_crumbled_graphics = FALSE;
6303 g_em->preserve_background = FALSE;
6306 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6307 printf("::: empty crumbled: %d [%s], %d, %d\n",
6308 effective_element, element_info[effective_element].token_name,
6309 effective_action, direction);
6312 /* if element can be crumbled, but certain action graphics are just empty
6313 space (like snapping sand with the original R'n'D graphics), do not
6314 treat these empty space graphics as crumbled graphics in EMC engine */
6315 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6317 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6319 g_em->has_crumbled_graphics = TRUE;
6320 g_em->crumbled_bitmap = src_bitmap;
6321 g_em->crumbled_src_x = src_x;
6322 g_em->crumbled_src_y = src_y;
6323 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6327 if (element == EL_ROCK &&
6328 effective_action == ACTION_FILLING)
6329 printf("::: has_action_graphics == %d\n", has_action_graphics);
6332 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6333 effective_action == ACTION_MOVING ||
6334 effective_action == ACTION_PUSHING ||
6335 effective_action == ACTION_EATING)) ||
6336 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6337 effective_action == ACTION_EMPTYING)))
6340 (effective_action == ACTION_FALLING ||
6341 effective_action == ACTION_FILLING ||
6342 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6343 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6344 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6345 int num_steps = (i == Ydrip_s1 ? 16 :
6346 i == Ydrip_s1B ? 16 :
6347 i == Ydrip_s2 ? 16 :
6348 i == Ydrip_s2B ? 16 :
6349 i == Xsand_stonein_1 ? 32 :
6350 i == Xsand_stonein_2 ? 32 :
6351 i == Xsand_stonein_3 ? 32 :
6352 i == Xsand_stonein_4 ? 32 :
6353 i == Xsand_stoneout_1 ? 16 :
6354 i == Xsand_stoneout_2 ? 16 : 8);
6355 int cx = ABS(dx) * (TILEX / num_steps);
6356 int cy = ABS(dy) * (TILEY / num_steps);
6357 int step_frame = (i == Ydrip_s2 ? j + 8 :
6358 i == Ydrip_s2B ? j + 8 :
6359 i == Xsand_stonein_2 ? j + 8 :
6360 i == Xsand_stonein_3 ? j + 16 :
6361 i == Xsand_stonein_4 ? j + 24 :
6362 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6363 int step = (is_backside ? step_frame : num_steps - step_frame);
6365 if (is_backside) /* tile where movement starts */
6367 if (dx < 0 || dy < 0)
6369 g_em->src_offset_x = cx * step;
6370 g_em->src_offset_y = cy * step;
6374 g_em->dst_offset_x = cx * step;
6375 g_em->dst_offset_y = cy * step;
6378 else /* tile where movement ends */
6380 if (dx < 0 || dy < 0)
6382 g_em->dst_offset_x = cx * step;
6383 g_em->dst_offset_y = cy * step;
6387 g_em->src_offset_x = cx * step;
6388 g_em->src_offset_y = cy * step;
6392 g_em->width = TILEX - cx * step;
6393 g_em->height = TILEY - cy * step;
6396 /* create unique graphic identifier to decide if tile must be redrawn */
6397 /* bit 31 - 16 (16 bit): EM style graphic
6398 bit 15 - 12 ( 4 bit): EM style frame
6399 bit 11 - 6 ( 6 bit): graphic width
6400 bit 5 - 0 ( 6 bit): graphic height */
6401 g_em->unique_identifier =
6402 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6406 /* skip check for EMC elements not contained in original EMC artwork */
6407 if (element == EL_EMC_FAKE_ACID)
6410 if (g_em->bitmap != debug_bitmap ||
6411 g_em->src_x != debug_src_x ||
6412 g_em->src_y != debug_src_y ||
6413 g_em->src_offset_x != 0 ||
6414 g_em->src_offset_y != 0 ||
6415 g_em->dst_offset_x != 0 ||
6416 g_em->dst_offset_y != 0 ||
6417 g_em->width != TILEX ||
6418 g_em->height != TILEY)
6420 static int last_i = -1;
6428 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6429 i, element, element_info[element].token_name,
6430 element_action_info[effective_action].suffix, direction);
6432 if (element != effective_element)
6433 printf(" [%d ('%s')]",
6435 element_info[effective_element].token_name);
6439 if (g_em->bitmap != debug_bitmap)
6440 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6441 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6443 if (g_em->src_x != debug_src_x ||
6444 g_em->src_y != debug_src_y)
6445 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6446 j, (is_backside ? 'B' : 'F'),
6447 g_em->src_x, g_em->src_y,
6448 g_em->src_x / 32, g_em->src_y / 32,
6449 debug_src_x, debug_src_y,
6450 debug_src_x / 32, debug_src_y / 32);
6452 if (g_em->src_offset_x != 0 ||
6453 g_em->src_offset_y != 0 ||
6454 g_em->dst_offset_x != 0 ||
6455 g_em->dst_offset_y != 0)
6456 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6458 g_em->src_offset_x, g_em->src_offset_y,
6459 g_em->dst_offset_x, g_em->dst_offset_y);
6461 if (g_em->width != TILEX ||
6462 g_em->height != TILEY)
6463 printf(" %d (%d): size %d,%d should be %d,%d\n",
6465 g_em->width, g_em->height, TILEX, TILEY);
6467 num_em_gfx_errors++;
6474 for (i = 0; i < TILE_MAX; i++)
6476 for (j = 0; j < 8; j++)
6478 int element = object_mapping[i].element_rnd;
6479 int action = object_mapping[i].action;
6480 int direction = object_mapping[i].direction;
6481 boolean is_backside = object_mapping[i].is_backside;
6482 int graphic_action = el_act_dir2img(element, action, direction);
6483 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6485 if ((action == ACTION_SMASHED_BY_ROCK ||
6486 action == ACTION_SMASHED_BY_SPRING ||
6487 action == ACTION_EATING) &&
6488 graphic_action == graphic_default)
6490 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6491 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6492 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6493 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6496 /* no separate animation for "smashed by rock" -- use rock instead */
6497 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6498 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6500 g_em->bitmap = g_xx->bitmap;
6501 g_em->src_x = g_xx->src_x;
6502 g_em->src_y = g_xx->src_y;
6503 g_em->src_offset_x = g_xx->src_offset_x;
6504 g_em->src_offset_y = g_xx->src_offset_y;
6505 g_em->dst_offset_x = g_xx->dst_offset_x;
6506 g_em->dst_offset_y = g_xx->dst_offset_y;
6507 g_em->width = g_xx->width;
6508 g_em->height = g_xx->height;
6509 g_em->unique_identifier = g_xx->unique_identifier;
6512 g_em->preserve_background = TRUE;
6517 for (p = 0; p < MAX_PLAYERS; p++)
6519 for (i = 0; i < SPR_MAX; i++)
6521 int element = player_mapping[p][i].element_rnd;
6522 int action = player_mapping[p][i].action;
6523 int direction = player_mapping[p][i].direction;
6525 for (j = 0; j < 8; j++)
6527 int effective_element = element;
6528 int effective_action = action;
6529 int graphic = (direction == MV_NONE ?
6530 el_act2img(effective_element, effective_action) :
6531 el_act_dir2img(effective_element, effective_action,
6533 struct GraphicInfo *g = &graphic_info[graphic];
6534 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6540 Bitmap *debug_bitmap = g_em->bitmap;
6541 int debug_src_x = g_em->src_x;
6542 int debug_src_y = g_em->src_y;
6545 int frame = getAnimationFrame(g->anim_frames,
6548 g->anim_start_frame,
6551 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6553 g_em->bitmap = src_bitmap;
6554 g_em->src_x = src_x;
6555 g_em->src_y = src_y;
6556 g_em->src_offset_x = 0;
6557 g_em->src_offset_y = 0;
6558 g_em->dst_offset_x = 0;
6559 g_em->dst_offset_y = 0;
6560 g_em->width = TILEX;
6561 g_em->height = TILEY;
6565 /* skip check for EMC elements not contained in original EMC artwork */
6566 if (element == EL_PLAYER_3 ||
6567 element == EL_PLAYER_4)
6570 if (g_em->bitmap != debug_bitmap ||
6571 g_em->src_x != debug_src_x ||
6572 g_em->src_y != debug_src_y)
6574 static int last_i = -1;
6582 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6583 p, i, element, element_info[element].token_name,
6584 element_action_info[effective_action].suffix, direction);
6586 if (element != effective_element)
6587 printf(" [%d ('%s')]",
6589 element_info[effective_element].token_name);
6593 if (g_em->bitmap != debug_bitmap)
6594 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6595 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6597 if (g_em->src_x != debug_src_x ||
6598 g_em->src_y != debug_src_y)
6599 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6601 g_em->src_x, g_em->src_y,
6602 g_em->src_x / 32, g_em->src_y / 32,
6603 debug_src_x, debug_src_y,
6604 debug_src_x / 32, debug_src_y / 32);
6606 num_em_gfx_errors++;
6616 printf("::: [%d errors found]\n", num_em_gfx_errors);
6622 void PlayMenuSoundExt(int sound)
6624 if (sound == SND_UNDEFINED)
6627 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6628 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6631 if (IS_LOOP_SOUND(sound))
6632 PlaySoundLoop(sound);
6637 void PlayMenuSound()
6639 PlayMenuSoundExt(menu.sound[game_status]);
6642 void PlayMenuSoundStereo(int sound, int stereo_position)
6644 if (sound == SND_UNDEFINED)
6647 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6648 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6651 if (IS_LOOP_SOUND(sound))
6652 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6654 PlaySoundStereo(sound, stereo_position);
6657 void PlayMenuSoundIfLoopExt(int sound)
6659 if (sound == SND_UNDEFINED)
6662 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6663 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6666 if (IS_LOOP_SOUND(sound))
6667 PlaySoundLoop(sound);
6670 void PlayMenuSoundIfLoop()
6672 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6675 void PlayMenuMusicExt(int music)
6677 if (music == MUS_UNDEFINED)
6680 if (!setup.sound_music)
6686 void PlayMenuMusic()
6688 PlayMenuMusicExt(menu.music[game_status]);
6691 void PlaySoundActivating()
6694 PlaySound(SND_MENU_ITEM_ACTIVATING);
6698 void PlaySoundSelecting()
6701 PlaySound(SND_MENU_ITEM_SELECTING);
6705 void ToggleFullscreenIfNeeded()
6707 boolean change_fullscreen = (setup.fullscreen !=
6708 video.fullscreen_enabled);
6709 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6710 !strEqual(setup.fullscreen_mode,
6711 video.fullscreen_mode_current));
6713 if (!video.fullscreen_available)
6717 if (change_fullscreen || change_fullscreen_mode)
6719 if (setup.fullscreen != video.fullscreen_enabled ||
6720 setup.fullscreen_mode != video.fullscreen_mode_current)
6723 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6725 /* save backbuffer content which gets lost when toggling fullscreen mode */
6726 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6729 if (change_fullscreen_mode)
6731 if (setup.fullscreen && video.fullscreen_enabled)
6734 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6736 /* (this is now set in sdl.c) */
6738 video.fullscreen_mode_current = setup.fullscreen_mode;
6740 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6743 /* toggle fullscreen */
6744 ChangeVideoModeIfNeeded(setup.fullscreen);
6746 setup.fullscreen = video.fullscreen_enabled;
6748 /* restore backbuffer content from temporary backbuffer backup bitmap */
6749 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6751 FreeBitmap(tmp_backbuffer);
6754 /* update visible window/screen */
6755 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6757 redraw_mask = REDRAW_ALL;