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 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
916 int *x, int *y, boolean get_backside)
918 struct GraphicInfo *g = &graphic_info[graphic];
919 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
920 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
924 if (g->offset_y == 0) /* frames are ordered horizontally */
926 int max_width = g->anim_frames_per_line * g->width;
927 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
929 *x = pos % max_width;
930 *y = src_y % g->height + pos / max_width * g->height;
932 else if (g->offset_x == 0) /* frames are ordered vertically */
934 int max_height = g->anim_frames_per_line * g->height;
935 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
937 *x = src_x % g->width + pos / max_height * g->width;
938 *y = pos % max_height;
940 else /* frames are ordered diagonally */
942 *x = src_x + frame * g->offset_x;
943 *y = src_y + frame * g->offset_y;
947 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
949 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
952 void DrawGraphic(int x, int y, int graphic, int frame)
955 if (!IN_SCR_FIELD(x, y))
957 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
958 printf("DrawGraphic(): This should never happen!\n");
963 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
967 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
973 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
974 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
977 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
980 if (!IN_SCR_FIELD(x, y))
982 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
983 printf("DrawGraphicThruMask(): This should never happen!\n");
988 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
993 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
999 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1001 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1002 dst_x - src_x, dst_y - src_y);
1003 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1006 void DrawMiniGraphic(int x, int y, int graphic)
1008 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1009 MarkTileDirty(x / 2, y / 2);
1012 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1014 struct GraphicInfo *g = &graphic_info[graphic];
1015 int mini_startx = 0;
1016 int mini_starty = g->bitmap->height * 2 / 3;
1018 *bitmap = g->bitmap;
1019 *x = mini_startx + g->src_x / 2;
1020 *y = mini_starty + g->src_y / 2;
1023 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1028 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1029 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1032 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1033 int graphic, int frame,
1034 int cut_mode, int mask_mode)
1039 int width = TILEX, height = TILEY;
1042 if (dx || dy) /* shifted graphic */
1044 if (x < BX1) /* object enters playfield from the left */
1051 else if (x > BX2) /* object enters playfield from the right */
1057 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1063 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1065 else if (dx) /* general horizontal movement */
1066 MarkTileDirty(x + SIGN(dx), y);
1068 if (y < BY1) /* object enters playfield from the top */
1070 if (cut_mode==CUT_BELOW) /* object completely above top border */
1078 else if (y > BY2) /* object enters playfield from the bottom */
1084 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1090 else if (dy > 0 && cut_mode == CUT_ABOVE)
1092 if (y == BY2) /* object completely above bottom border */
1098 MarkTileDirty(x, y + 1);
1099 } /* object leaves playfield to the bottom */
1100 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1102 else if (dy) /* general vertical movement */
1103 MarkTileDirty(x, y + SIGN(dy));
1107 if (!IN_SCR_FIELD(x, y))
1109 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1110 printf("DrawGraphicShifted(): This should never happen!\n");
1115 if (width > 0 && height > 0)
1117 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1122 dst_x = FX + x * TILEX + dx;
1123 dst_y = FY + y * TILEY + dy;
1125 if (mask_mode == USE_MASKING)
1127 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1128 dst_x - src_x, dst_y - src_y);
1129 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1133 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1136 MarkTileDirty(x, y);
1140 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1141 int graphic, int frame,
1142 int cut_mode, int mask_mode)
1147 int width = TILEX, height = TILEY;
1150 int x2 = x + SIGN(dx);
1151 int y2 = y + SIGN(dy);
1152 int anim_frames = graphic_info[graphic].anim_frames;
1153 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1154 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1155 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1157 /* re-calculate animation frame for two-tile movement animation */
1158 frame = getGraphicAnimationFrame(graphic, sync_frame);
1160 /* check if movement start graphic inside screen area and should be drawn */
1161 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1163 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1165 dst_x = FX + x1 * TILEX;
1166 dst_y = FY + y1 * TILEY;
1168 if (mask_mode == USE_MASKING)
1170 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1171 dst_x - src_x, dst_y - src_y);
1172 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1176 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1179 MarkTileDirty(x1, y1);
1182 /* check if movement end graphic inside screen area and should be drawn */
1183 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1185 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1187 dst_x = FX + x2 * TILEX;
1188 dst_y = FY + y2 * TILEY;
1190 if (mask_mode == USE_MASKING)
1192 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1193 dst_x - src_x, dst_y - src_y);
1194 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1198 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1201 MarkTileDirty(x2, y2);
1205 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1206 int graphic, int frame,
1207 int cut_mode, int mask_mode)
1211 DrawGraphic(x, y, graphic, frame);
1216 if (graphic_info[graphic].double_movement) /* EM style movement images */
1217 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1219 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1222 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1223 int frame, int cut_mode)
1225 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1228 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1229 int cut_mode, int mask_mode)
1231 int lx = LEVELX(x), ly = LEVELY(y);
1235 if (IN_LEV_FIELD(lx, ly))
1237 SetRandomAnimationValue(lx, ly);
1239 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1240 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1242 /* do not use double (EM style) movement graphic when not moving */
1243 if (graphic_info[graphic].double_movement && !dx && !dy)
1245 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1246 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1249 else /* border element */
1251 graphic = el2img(element);
1252 frame = getGraphicAnimationFrame(graphic, -1);
1255 if (element == EL_EXPANDABLE_WALL)
1257 boolean left_stopped = FALSE, right_stopped = FALSE;
1259 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1260 left_stopped = TRUE;
1261 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1262 right_stopped = TRUE;
1264 if (left_stopped && right_stopped)
1266 else if (left_stopped)
1268 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1269 frame = graphic_info[graphic].anim_frames - 1;
1271 else if (right_stopped)
1273 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1274 frame = graphic_info[graphic].anim_frames - 1;
1279 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1280 else if (mask_mode == USE_MASKING)
1281 DrawGraphicThruMask(x, y, graphic, frame);
1283 DrawGraphic(x, y, graphic, frame);
1286 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1287 int cut_mode, int mask_mode)
1289 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1290 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1291 cut_mode, mask_mode);
1294 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1297 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1300 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1303 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1306 void DrawLevelElementThruMask(int x, int y, int element)
1308 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1311 void DrawLevelFieldThruMask(int x, int y)
1313 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1316 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1320 int sx = SCREENX(x), sy = SCREENY(y);
1322 int width, height, cx, cy, i;
1323 int crumbled_border_size = graphic_info[graphic].border_size;
1324 static int xy[4][2] =
1332 if (!IN_LEV_FIELD(x, y))
1335 element = TILE_GFX_ELEMENT(x, y);
1337 /* crumble field itself */
1338 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1340 if (!IN_SCR_FIELD(sx, sy))
1343 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1345 for (i = 0; i < 4; i++)
1347 int xx = x + xy[i][0];
1348 int yy = y + xy[i][1];
1350 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1353 /* check if neighbour field is of same type */
1354 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1357 if (i == 1 || i == 2)
1359 width = crumbled_border_size;
1361 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1367 height = crumbled_border_size;
1369 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1372 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1373 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1376 MarkTileDirty(sx, sy);
1378 else /* crumble neighbour fields */
1380 for (i = 0; i < 4; i++)
1382 int xx = x + xy[i][0];
1383 int yy = y + xy[i][1];
1384 int sxx = sx + xy[i][0];
1385 int syy = sy + xy[i][1];
1387 if (!IN_LEV_FIELD(xx, yy) ||
1388 !IN_SCR_FIELD(sxx, syy) ||
1392 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1395 element = TILE_GFX_ELEMENT(xx, yy);
1397 if (!GFX_CRUMBLED(element))
1400 graphic = el_act2crm(element, ACTION_DEFAULT);
1401 crumbled_border_size = graphic_info[graphic].border_size;
1403 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1405 if (i == 1 || i == 2)
1407 width = crumbled_border_size;
1409 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1415 height = crumbled_border_size;
1417 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1420 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1421 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1423 MarkTileDirty(sxx, syy);
1428 void DrawLevelFieldCrumbledSand(int x, int y)
1432 if (!IN_LEV_FIELD(x, y))
1436 /* !!! CHECK THIS !!! */
1439 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1440 GFX_CRUMBLED(GfxElement[x][y]))
1443 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1444 GfxElement[x][y] != EL_UNDEFINED &&
1445 GFX_CRUMBLED(GfxElement[x][y]))
1447 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1454 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1456 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1459 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1462 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1465 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1466 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1467 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1468 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1469 int sx = SCREENX(x), sy = SCREENY(y);
1471 DrawGraphic(sx, sy, graphic1, frame1);
1472 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1475 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1477 int sx = SCREENX(x), sy = SCREENY(y);
1478 static int xy[4][2] =
1487 for (i = 0; i < 4; i++)
1489 int xx = x + xy[i][0];
1490 int yy = y + xy[i][1];
1491 int sxx = sx + xy[i][0];
1492 int syy = sy + xy[i][1];
1494 if (!IN_LEV_FIELD(xx, yy) ||
1495 !IN_SCR_FIELD(sxx, syy) ||
1496 !GFX_CRUMBLED(Feld[xx][yy]) ||
1500 DrawLevelField(xx, yy);
1504 static int getBorderElement(int x, int y)
1508 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1509 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1510 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1511 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1512 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1513 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1514 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1516 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1517 int steel_position = (x == -1 && y == -1 ? 0 :
1518 x == lev_fieldx && y == -1 ? 1 :
1519 x == -1 && y == lev_fieldy ? 2 :
1520 x == lev_fieldx && y == lev_fieldy ? 3 :
1521 x == -1 || x == lev_fieldx ? 4 :
1522 y == -1 || y == lev_fieldy ? 5 : 6);
1524 return border[steel_position][steel_type];
1527 void DrawScreenElement(int x, int y, int element)
1529 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1530 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1533 void DrawLevelElement(int x, int y, int element)
1535 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1536 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1539 void DrawScreenField(int x, int y)
1541 int lx = LEVELX(x), ly = LEVELY(y);
1542 int element, content;
1544 if (!IN_LEV_FIELD(lx, ly))
1546 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1549 element = getBorderElement(lx, ly);
1551 DrawScreenElement(x, y, element);
1555 element = Feld[lx][ly];
1556 content = Store[lx][ly];
1558 if (IS_MOVING(lx, ly))
1560 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1561 boolean cut_mode = NO_CUTTING;
1563 if (element == EL_QUICKSAND_EMPTYING ||
1564 element == EL_QUICKSAND_FAST_EMPTYING ||
1565 element == EL_MAGIC_WALL_EMPTYING ||
1566 element == EL_BD_MAGIC_WALL_EMPTYING ||
1567 element == EL_DC_MAGIC_WALL_EMPTYING ||
1568 element == EL_AMOEBA_DROPPING)
1569 cut_mode = CUT_ABOVE;
1570 else if (element == EL_QUICKSAND_FILLING ||
1571 element == EL_QUICKSAND_FAST_FILLING ||
1572 element == EL_MAGIC_WALL_FILLING ||
1573 element == EL_BD_MAGIC_WALL_FILLING ||
1574 element == EL_DC_MAGIC_WALL_FILLING)
1575 cut_mode = CUT_BELOW;
1577 if (cut_mode == CUT_ABOVE)
1578 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1580 DrawScreenElement(x, y, EL_EMPTY);
1583 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1584 else if (cut_mode == NO_CUTTING)
1585 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1587 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1589 if (content == EL_ACID)
1591 int dir = MovDir[lx][ly];
1592 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1593 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1595 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1598 else if (IS_BLOCKED(lx, ly))
1603 boolean cut_mode = NO_CUTTING;
1604 int element_old, content_old;
1606 Blocked2Moving(lx, ly, &oldx, &oldy);
1609 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1610 MovDir[oldx][oldy] == MV_RIGHT);
1612 element_old = Feld[oldx][oldy];
1613 content_old = Store[oldx][oldy];
1615 if (element_old == EL_QUICKSAND_EMPTYING ||
1616 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1617 element_old == EL_MAGIC_WALL_EMPTYING ||
1618 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1619 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1620 element_old == EL_AMOEBA_DROPPING)
1621 cut_mode = CUT_ABOVE;
1623 DrawScreenElement(x, y, EL_EMPTY);
1626 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1628 else if (cut_mode == NO_CUTTING)
1629 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1632 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1635 else if (IS_DRAWABLE(element))
1636 DrawScreenElement(x, y, element);
1638 DrawScreenElement(x, y, EL_EMPTY);
1641 void DrawLevelField(int x, int y)
1643 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1644 DrawScreenField(SCREENX(x), SCREENY(y));
1645 else if (IS_MOVING(x, y))
1649 Moving2Blocked(x, y, &newx, &newy);
1650 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1651 DrawScreenField(SCREENX(newx), SCREENY(newy));
1653 else if (IS_BLOCKED(x, y))
1657 Blocked2Moving(x, y, &oldx, &oldy);
1658 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1659 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1663 void DrawMiniElement(int x, int y, int element)
1667 graphic = el2edimg(element);
1668 DrawMiniGraphic(x, y, graphic);
1671 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1673 int x = sx + scroll_x, y = sy + scroll_y;
1675 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1676 DrawMiniElement(sx, sy, EL_EMPTY);
1677 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1678 DrawMiniElement(sx, sy, Feld[x][y]);
1680 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1683 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1684 int x, int y, int xsize, int ysize, int font_nr)
1686 int font_width = getFontWidth(font_nr);
1687 int font_height = getFontHeight(font_nr);
1688 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1691 int dst_x = SX + startx + x * font_width;
1692 int dst_y = SY + starty + y * font_height;
1693 int width = graphic_info[graphic].width;
1694 int height = graphic_info[graphic].height;
1695 int inner_width = MAX(width - 2 * font_width, font_width);
1696 int inner_height = MAX(height - 2 * font_height, font_height);
1697 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1698 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1699 boolean draw_masked = graphic_info[graphic].draw_masked;
1701 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1703 if (src_bitmap == NULL || width < font_width || height < font_height)
1705 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1709 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1710 inner_sx + (x - 1) * font_width % inner_width);
1711 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1712 inner_sy + (y - 1) * font_height % inner_height);
1716 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1717 dst_x - src_x, dst_y - src_y);
1718 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1722 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1726 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1728 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1729 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1730 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1731 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1732 boolean no_delay = (tape.warp_forward);
1733 unsigned long anim_delay = 0;
1734 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1735 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1736 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1737 int font_width = getFontWidth(font_nr);
1738 int font_height = getFontHeight(font_nr);
1739 int max_xsize = level.envelope[envelope_nr].xsize;
1740 int max_ysize = level.envelope[envelope_nr].ysize;
1741 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1742 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1743 int xend = max_xsize;
1744 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1745 int xstep = (xstart < xend ? 1 : 0);
1746 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1749 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1751 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1752 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1753 int sx = (SXSIZE - xsize * font_width) / 2;
1754 int sy = (SYSIZE - ysize * font_height) / 2;
1757 SetDrawtoField(DRAW_BUFFERED);
1759 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1761 SetDrawtoField(DRAW_BACKBUFFER);
1763 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1764 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1767 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1768 level.envelope[envelope_nr].text, font_nr, max_xsize,
1769 xsize - 2, ysize - 2, mask_mode,
1770 level.envelope[envelope_nr].autowrap,
1771 level.envelope[envelope_nr].centered, FALSE);
1773 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1774 level.envelope[envelope_nr].text, font_nr, max_xsize,
1775 xsize - 2, ysize - 2, mask_mode);
1778 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1781 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1785 void ShowEnvelope(int envelope_nr)
1787 int element = EL_ENVELOPE_1 + envelope_nr;
1788 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1789 int sound_opening = element_info[element].sound[ACTION_OPENING];
1790 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1791 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1792 boolean no_delay = (tape.warp_forward);
1793 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1794 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1795 int anim_mode = graphic_info[graphic].anim_mode;
1796 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1797 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1799 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1801 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1803 if (anim_mode == ANIM_DEFAULT)
1804 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1806 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1809 Delay(wait_delay_value);
1811 WaitForEventToContinue();
1813 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1815 if (anim_mode != ANIM_NONE)
1816 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1818 if (anim_mode == ANIM_DEFAULT)
1819 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1821 game.envelope_active = FALSE;
1823 SetDrawtoField(DRAW_BUFFERED);
1825 redraw_mask |= REDRAW_FIELD;
1829 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1834 int width_mult, width_div;
1835 int height_mult, height_div;
1853 int offset_calc_pos = (tilesize < MICRO_TILESIZE / 4 ||
1854 tilesize > TILESIZE ? 5 : 5 - log_2(tilesize));
1856 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1857 5 - log_2(tilesize));
1859 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1860 int width_mult = offset_calc[offset_calc_pos].width_mult;
1861 int width_div = offset_calc[offset_calc_pos].width_div;
1862 int height_mult = offset_calc[offset_calc_pos].height_mult;
1863 int height_div = offset_calc[offset_calc_pos].height_div;
1864 int mini_startx = src_bitmap->width * width_mult / width_div;
1865 int mini_starty = src_bitmap->height * height_mult / height_div;
1866 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1867 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1869 *bitmap = src_bitmap;
1874 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1878 int graphic = el2preimg(element);
1880 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1881 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1888 SetDrawBackgroundMask(REDRAW_NONE);
1891 for (x = BX1; x <= BX2; x++)
1892 for (y = BY1; y <= BY2; y++)
1893 DrawScreenField(x, y);
1895 redraw_mask |= REDRAW_FIELD;
1898 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1902 for (x = 0; x < size_x; x++)
1903 for (y = 0; y < size_y; y++)
1904 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1906 redraw_mask |= REDRAW_FIELD;
1909 static void DrawPreviewLevelExt(int from_x, int from_y)
1911 boolean show_level_border = (BorderElement != EL_EMPTY);
1912 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1913 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1914 int tile_size = preview.tile_size;
1915 int preview_width = preview.xsize * tile_size;
1916 int preview_height = preview.ysize * tile_size;
1917 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1918 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1919 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1920 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1923 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1925 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1926 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1928 for (x = 0; x < real_preview_xsize; x++)
1930 for (y = 0; y < real_preview_ysize; y++)
1932 int lx = from_x + x + (show_level_border ? -1 : 0);
1933 int ly = from_y + y + (show_level_border ? -1 : 0);
1934 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1935 getBorderElement(lx, ly));
1937 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1938 element, tile_size);
1942 redraw_mask |= REDRAW_MICROLEVEL;
1945 #define MICROLABEL_EMPTY 0
1946 #define MICROLABEL_LEVEL_NAME 1
1947 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1948 #define MICROLABEL_LEVEL_AUTHOR 3
1949 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1950 #define MICROLABEL_IMPORTED_FROM 5
1951 #define MICROLABEL_IMPORTED_BY_HEAD 6
1952 #define MICROLABEL_IMPORTED_BY 7
1954 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
1956 int max_text_width = SXSIZE;
1957 int font_width = getFontWidth(font_nr);
1959 if (pos->align == ALIGN_CENTER)
1960 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1961 else if (pos->align == ALIGN_RIGHT)
1962 max_text_width = pos->x;
1964 max_text_width = SXSIZE - pos->x;
1966 return max_text_width / font_width;
1969 static void DrawPreviewLevelLabelExt(int mode)
1971 struct TextPosInfo *pos = &menu.main.text.level_info_2;
1972 char label_text[MAX_OUTPUT_LINESIZE + 1];
1973 int max_len_label_text;
1975 int font_nr = pos->font;
1978 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1979 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1980 mode == MICROLABEL_IMPORTED_BY_HEAD)
1981 font_nr = pos->font_alt;
1983 int font_nr = FONT_TEXT_2;
1986 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1987 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1988 mode == MICROLABEL_IMPORTED_BY_HEAD)
1989 font_nr = FONT_TEXT_3;
1993 max_len_label_text = getMaxTextLength(pos, font_nr);
1995 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1999 if (pos->chars != -1)
2000 max_len_label_text = pos->chars;
2003 for (i = 0; i < max_len_label_text; i++)
2004 label_text[i] = ' ';
2005 label_text[max_len_label_text] = '\0';
2007 if (strlen(label_text) > 0)
2010 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2012 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2013 int lypos = MICROLABEL2_YPOS;
2015 DrawText(lxpos, lypos, label_text, font_nr);
2020 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2021 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2022 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2023 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2024 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2025 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2026 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2027 max_len_label_text);
2028 label_text[max_len_label_text] = '\0';
2030 if (strlen(label_text) > 0)
2033 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2035 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2036 int lypos = MICROLABEL2_YPOS;
2038 DrawText(lxpos, lypos, label_text, font_nr);
2042 redraw_mask |= REDRAW_MICROLEVEL;
2045 void DrawPreviewLevel(boolean restart)
2047 static unsigned long scroll_delay = 0;
2048 static unsigned long label_delay = 0;
2049 static int from_x, from_y, scroll_direction;
2050 static int label_state, label_counter;
2051 unsigned long scroll_delay_value = preview.step_delay;
2052 boolean show_level_border = (BorderElement != EL_EMPTY);
2053 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2054 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2055 int last_game_status = game_status; /* save current game status */
2058 /* force PREVIEW font on preview level */
2059 game_status = GAME_MODE_PSEUDO_PREVIEW;
2067 if (preview.anim_mode == ANIM_CENTERED)
2069 if (level_xsize > preview.xsize)
2070 from_x = (level_xsize - preview.xsize) / 2;
2071 if (level_ysize > preview.ysize)
2072 from_y = (level_ysize - preview.ysize) / 2;
2075 from_x += preview.xoffset;
2076 from_y += preview.yoffset;
2078 scroll_direction = MV_RIGHT;
2082 DrawPreviewLevelExt(from_x, from_y);
2083 DrawPreviewLevelLabelExt(label_state);
2085 /* initialize delay counters */
2086 DelayReached(&scroll_delay, 0);
2087 DelayReached(&label_delay, 0);
2089 if (leveldir_current->name)
2091 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2092 char label_text[MAX_OUTPUT_LINESIZE + 1];
2094 int font_nr = pos->font;
2096 int font_nr = FONT_TEXT_1;
2099 int max_len_label_text = getMaxTextLength(pos, font_nr);
2101 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2109 if (pos->chars != -1)
2110 max_len_label_text = pos->chars;
2113 strncpy(label_text, leveldir_current->name, max_len_label_text);
2114 label_text[max_len_label_text] = '\0';
2117 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2119 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2120 lypos = SY + MICROLABEL1_YPOS;
2122 DrawText(lxpos, lypos, label_text, font_nr);
2126 game_status = last_game_status; /* restore current game status */
2131 /* scroll preview level, if needed */
2132 if (preview.anim_mode != ANIM_NONE &&
2133 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2134 DelayReached(&scroll_delay, scroll_delay_value))
2136 switch (scroll_direction)
2141 from_x -= preview.step_offset;
2142 from_x = (from_x < 0 ? 0 : from_x);
2145 scroll_direction = MV_UP;
2149 if (from_x < level_xsize - preview.xsize)
2151 from_x += preview.step_offset;
2152 from_x = (from_x > level_xsize - preview.xsize ?
2153 level_xsize - preview.xsize : from_x);
2156 scroll_direction = MV_DOWN;
2162 from_y -= preview.step_offset;
2163 from_y = (from_y < 0 ? 0 : from_y);
2166 scroll_direction = MV_RIGHT;
2170 if (from_y < level_ysize - preview.ysize)
2172 from_y += preview.step_offset;
2173 from_y = (from_y > level_ysize - preview.ysize ?
2174 level_ysize - preview.ysize : from_y);
2177 scroll_direction = MV_LEFT;
2184 DrawPreviewLevelExt(from_x, from_y);
2187 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2188 /* redraw micro level label, if needed */
2189 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2190 !strEqual(level.author, ANONYMOUS_NAME) &&
2191 !strEqual(level.author, leveldir_current->name) &&
2192 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2194 int max_label_counter = 23;
2196 if (leveldir_current->imported_from != NULL &&
2197 strlen(leveldir_current->imported_from) > 0)
2198 max_label_counter += 14;
2199 if (leveldir_current->imported_by != NULL &&
2200 strlen(leveldir_current->imported_by) > 0)
2201 max_label_counter += 14;
2203 label_counter = (label_counter + 1) % max_label_counter;
2204 label_state = (label_counter >= 0 && label_counter <= 7 ?
2205 MICROLABEL_LEVEL_NAME :
2206 label_counter >= 9 && label_counter <= 12 ?
2207 MICROLABEL_LEVEL_AUTHOR_HEAD :
2208 label_counter >= 14 && label_counter <= 21 ?
2209 MICROLABEL_LEVEL_AUTHOR :
2210 label_counter >= 23 && label_counter <= 26 ?
2211 MICROLABEL_IMPORTED_FROM_HEAD :
2212 label_counter >= 28 && label_counter <= 35 ?
2213 MICROLABEL_IMPORTED_FROM :
2214 label_counter >= 37 && label_counter <= 40 ?
2215 MICROLABEL_IMPORTED_BY_HEAD :
2216 label_counter >= 42 && label_counter <= 49 ?
2217 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2219 if (leveldir_current->imported_from == NULL &&
2220 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2221 label_state == MICROLABEL_IMPORTED_FROM))
2222 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2223 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2225 DrawPreviewLevelLabelExt(label_state);
2228 game_status = last_game_status; /* restore current game status */
2231 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2232 int graphic, int sync_frame, int mask_mode)
2234 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2236 if (mask_mode == USE_MASKING)
2237 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2239 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2242 inline void DrawGraphicAnimation(int x, int y, int graphic)
2244 int lx = LEVELX(x), ly = LEVELY(y);
2246 if (!IN_SCR_FIELD(x, y))
2249 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2250 graphic, GfxFrame[lx][ly], NO_MASKING);
2251 MarkTileDirty(x, y);
2254 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2256 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2259 void DrawLevelElementAnimation(int x, int y, int element)
2261 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2263 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2266 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2268 int sx = SCREENX(x), sy = SCREENY(y);
2270 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2273 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2276 DrawGraphicAnimation(sx, sy, graphic);
2279 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2280 DrawLevelFieldCrumbledSand(x, y);
2282 if (GFX_CRUMBLED(Feld[x][y]))
2283 DrawLevelFieldCrumbledSand(x, y);
2287 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2289 int sx = SCREENX(x), sy = SCREENY(y);
2292 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2295 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2297 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2300 DrawGraphicAnimation(sx, sy, graphic);
2302 if (GFX_CRUMBLED(element))
2303 DrawLevelFieldCrumbledSand(x, y);
2306 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2308 if (player->use_murphy)
2310 /* this works only because currently only one player can be "murphy" ... */
2311 static int last_horizontal_dir = MV_LEFT;
2312 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2314 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2315 last_horizontal_dir = move_dir;
2317 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2319 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2321 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2327 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2330 static boolean equalGraphics(int graphic1, int graphic2)
2332 struct GraphicInfo *g1 = &graphic_info[graphic1];
2333 struct GraphicInfo *g2 = &graphic_info[graphic2];
2335 return (g1->bitmap == g2->bitmap &&
2336 g1->src_x == g2->src_x &&
2337 g1->src_y == g2->src_y &&
2338 g1->anim_frames == g2->anim_frames &&
2339 g1->anim_delay == g2->anim_delay &&
2340 g1->anim_mode == g2->anim_mode);
2343 void DrawAllPlayers()
2347 for (i = 0; i < MAX_PLAYERS; i++)
2348 if (stored_player[i].active)
2349 DrawPlayer(&stored_player[i]);
2352 void DrawPlayerField(int x, int y)
2354 if (!IS_PLAYER(x, y))
2357 DrawPlayer(PLAYERINFO(x, y));
2360 void DrawPlayer(struct PlayerInfo *player)
2362 int jx = player->jx;
2363 int jy = player->jy;
2364 int move_dir = player->MovDir;
2365 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2366 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2367 int last_jx = (player->is_moving ? jx - dx : jx);
2368 int last_jy = (player->is_moving ? jy - dy : jy);
2369 int next_jx = jx + dx;
2370 int next_jy = jy + dy;
2371 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2372 boolean player_is_opaque = FALSE;
2373 int sx = SCREENX(jx), sy = SCREENY(jy);
2374 int sxx = 0, syy = 0;
2375 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2377 int action = ACTION_DEFAULT;
2378 int last_player_graphic = getPlayerGraphic(player, move_dir);
2379 int last_player_frame = player->Frame;
2382 /* GfxElement[][] is set to the element the player is digging or collecting;
2383 remove also for off-screen player if the player is not moving anymore */
2384 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2385 GfxElement[jx][jy] = EL_UNDEFINED;
2387 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2391 if (!IN_LEV_FIELD(jx, jy))
2393 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2394 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2395 printf("DrawPlayerField(): This should never happen!\n");
2400 if (element == EL_EXPLOSION)
2403 action = (player->is_pushing ? ACTION_PUSHING :
2404 player->is_digging ? ACTION_DIGGING :
2405 player->is_collecting ? ACTION_COLLECTING :
2406 player->is_moving ? ACTION_MOVING :
2407 player->is_snapping ? ACTION_SNAPPING :
2408 player->is_dropping ? ACTION_DROPPING :
2409 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2411 if (player->is_waiting)
2412 move_dir = player->dir_waiting;
2414 InitPlayerGfxAnimation(player, action, move_dir);
2416 /* ----------------------------------------------------------------------- */
2417 /* draw things in the field the player is leaving, if needed */
2418 /* ----------------------------------------------------------------------- */
2420 if (player->is_moving)
2422 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2424 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2426 if (last_element == EL_DYNAMITE_ACTIVE ||
2427 last_element == EL_EM_DYNAMITE_ACTIVE ||
2428 last_element == EL_SP_DISK_RED_ACTIVE)
2429 DrawDynamite(last_jx, last_jy);
2431 DrawLevelFieldThruMask(last_jx, last_jy);
2433 else if (last_element == EL_DYNAMITE_ACTIVE ||
2434 last_element == EL_EM_DYNAMITE_ACTIVE ||
2435 last_element == EL_SP_DISK_RED_ACTIVE)
2436 DrawDynamite(last_jx, last_jy);
2438 /* !!! this is not enough to prevent flickering of players which are
2439 moving next to each others without a free tile between them -- this
2440 can only be solved by drawing all players layer by layer (first the
2441 background, then the foreground etc.) !!! => TODO */
2442 else if (!IS_PLAYER(last_jx, last_jy))
2443 DrawLevelField(last_jx, last_jy);
2446 DrawLevelField(last_jx, last_jy);
2449 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2450 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2453 if (!IN_SCR_FIELD(sx, sy))
2456 if (setup.direct_draw)
2457 SetDrawtoField(DRAW_BUFFERED);
2459 /* ----------------------------------------------------------------------- */
2460 /* draw things behind the player, if needed */
2461 /* ----------------------------------------------------------------------- */
2464 DrawLevelElement(jx, jy, Back[jx][jy]);
2465 else if (IS_ACTIVE_BOMB(element))
2466 DrawLevelElement(jx, jy, EL_EMPTY);
2469 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2471 int old_element = GfxElement[jx][jy];
2472 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2473 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2475 if (GFX_CRUMBLED(old_element))
2476 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2478 DrawGraphic(sx, sy, old_graphic, frame);
2480 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2481 player_is_opaque = TRUE;
2485 GfxElement[jx][jy] = EL_UNDEFINED;
2487 /* make sure that pushed elements are drawn with correct frame rate */
2489 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2491 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2492 GfxFrame[jx][jy] = player->StepFrame;
2494 if (player->is_pushing && player->is_moving)
2495 GfxFrame[jx][jy] = player->StepFrame;
2498 DrawLevelField(jx, jy);
2502 /* ----------------------------------------------------------------------- */
2503 /* draw player himself */
2504 /* ----------------------------------------------------------------------- */
2506 graphic = getPlayerGraphic(player, move_dir);
2508 /* in the case of changed player action or direction, prevent the current
2509 animation frame from being restarted for identical animations */
2510 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2511 player->Frame = last_player_frame;
2513 frame = getGraphicAnimationFrame(graphic, player->Frame);
2517 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2518 sxx = player->GfxPos;
2520 syy = player->GfxPos;
2523 if (!setup.soft_scrolling && ScreenMovPos)
2526 if (player_is_opaque)
2527 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2529 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2531 if (SHIELD_ON(player))
2533 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2534 IMG_SHIELD_NORMAL_ACTIVE);
2535 int frame = getGraphicAnimationFrame(graphic, -1);
2537 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2540 /* ----------------------------------------------------------------------- */
2541 /* draw things the player is pushing, if needed */
2542 /* ----------------------------------------------------------------------- */
2545 printf("::: %d, %d [%d, %d] [%d]\n",
2546 player->is_pushing, player_is_moving, player->GfxAction,
2547 player->is_moving, player_is_moving);
2551 if (player->is_pushing && player->is_moving)
2553 int px = SCREENX(jx), py = SCREENY(jy);
2554 int pxx = (TILEX - ABS(sxx)) * dx;
2555 int pyy = (TILEY - ABS(syy)) * dy;
2556 int gfx_frame = GfxFrame[jx][jy];
2562 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2564 element = Feld[next_jx][next_jy];
2565 gfx_frame = GfxFrame[next_jx][next_jy];
2568 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2571 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2572 frame = getGraphicAnimationFrame(graphic, sync_frame);
2574 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2577 /* draw background element under pushed element (like the Sokoban field) */
2578 if (Back[next_jx][next_jy])
2579 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2581 /* masked drawing is needed for EMC style (double) movement graphics */
2582 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2586 /* ----------------------------------------------------------------------- */
2587 /* draw things in front of player (active dynamite or dynabombs) */
2588 /* ----------------------------------------------------------------------- */
2590 if (IS_ACTIVE_BOMB(element))
2592 graphic = el2img(element);
2593 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2595 if (game.emulation == EMU_SUPAPLEX)
2596 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2598 DrawGraphicThruMask(sx, sy, graphic, frame);
2601 if (player_is_moving && last_element == EL_EXPLOSION)
2603 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2604 GfxElement[last_jx][last_jy] : EL_EMPTY);
2605 int graphic = el_act2img(element, ACTION_EXPLODING);
2606 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2607 int phase = ExplodePhase[last_jx][last_jy] - 1;
2608 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2611 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2614 /* ----------------------------------------------------------------------- */
2615 /* draw elements the player is just walking/passing through/under */
2616 /* ----------------------------------------------------------------------- */
2618 if (player_is_moving)
2620 /* handle the field the player is leaving ... */
2621 if (IS_ACCESSIBLE_INSIDE(last_element))
2622 DrawLevelField(last_jx, last_jy);
2623 else if (IS_ACCESSIBLE_UNDER(last_element))
2624 DrawLevelFieldThruMask(last_jx, last_jy);
2627 /* do not redraw accessible elements if the player is just pushing them */
2628 if (!player_is_moving || !player->is_pushing)
2630 /* ... and the field the player is entering */
2631 if (IS_ACCESSIBLE_INSIDE(element))
2632 DrawLevelField(jx, jy);
2633 else if (IS_ACCESSIBLE_UNDER(element))
2634 DrawLevelFieldThruMask(jx, jy);
2637 if (setup.direct_draw)
2639 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2640 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2641 int x_size = TILEX * (1 + ABS(jx - last_jx));
2642 int y_size = TILEY * (1 + ABS(jy - last_jy));
2644 BlitBitmap(drawto_field, window,
2645 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2646 SetDrawtoField(DRAW_DIRECT);
2649 MarkTileDirty(sx, sy);
2652 /* ------------------------------------------------------------------------- */
2654 void WaitForEventToContinue()
2656 boolean still_wait = TRUE;
2658 /* simulate releasing mouse button over last gadget, if still pressed */
2660 HandleGadgets(-1, -1, 0);
2662 button_status = MB_RELEASED;
2678 case EVENT_BUTTONPRESS:
2679 case EVENT_KEYPRESS:
2683 case EVENT_KEYRELEASE:
2684 ClearPlayerAction();
2688 HandleOtherEvents(&event);
2692 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2699 /* don't eat all CPU time */
2704 #define MAX_REQUEST_LINES 13
2705 #define MAX_REQUEST_LINE_FONT1_LEN 7
2706 #define MAX_REQUEST_LINE_FONT2_LEN 10
2708 boolean Request(char *text, unsigned int req_state)
2710 int mx, my, ty, result = -1;
2711 unsigned int old_door_state;
2712 int last_game_status = game_status; /* save current game status */
2713 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2714 int font_nr = FONT_TEXT_2;
2715 int max_word_len = 0;
2718 for (text_ptr = text; *text_ptr; text_ptr++)
2720 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2722 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2724 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2726 font_nr = FONT_TEXT_1;
2728 font_nr = FONT_LEVEL_NUMBER;
2735 if (game_status == GAME_MODE_PLAYING &&
2736 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2737 BlitScreenToBitmap_EM(backbuffer);
2739 /* disable deactivated drawing when quick-loading level tape recording */
2740 if (tape.playing && tape.deactivate_display)
2741 TapeDeactivateDisplayOff(TRUE);
2743 SetMouseCursor(CURSOR_DEFAULT);
2745 #if defined(NETWORK_AVALIABLE)
2746 /* pause network game while waiting for request to answer */
2747 if (options.network &&
2748 game_status == GAME_MODE_PLAYING &&
2749 req_state & REQUEST_WAIT_FOR_INPUT)
2750 SendToServer_PausePlaying();
2753 old_door_state = GetDoorState();
2755 /* simulate releasing mouse button over last gadget, if still pressed */
2757 HandleGadgets(-1, -1, 0);
2761 if (old_door_state & DOOR_OPEN_1)
2763 CloseDoor(DOOR_CLOSE_1);
2765 /* save old door content */
2766 BlitBitmap(bitmap_db_door, bitmap_db_door,
2767 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2768 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2772 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2775 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2777 /* clear door drawing field */
2778 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2780 /* force DOOR font inside door area */
2781 game_status = GAME_MODE_PSEUDO_DOOR;
2783 /* write text for request */
2784 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2786 char text_line[max_request_line_len + 1];
2792 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2795 if (!tc || tc == ' ')
2806 strncpy(text_line, text, tl);
2809 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2810 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2811 text_line, font_nr);
2813 text += tl + (tc == ' ' ? 1 : 0);
2816 game_status = last_game_status; /* restore current game status */
2818 if (req_state & REQ_ASK)
2820 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2821 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2823 else if (req_state & REQ_CONFIRM)
2825 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2827 else if (req_state & REQ_PLAYER)
2829 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2830 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2831 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2832 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2835 /* copy request gadgets to door backbuffer */
2836 BlitBitmap(drawto, bitmap_db_door,
2837 DX, DY, DXSIZE, DYSIZE,
2838 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2840 OpenDoor(DOOR_OPEN_1);
2842 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2844 if (game_status == GAME_MODE_PLAYING)
2846 SetPanelBackground();
2847 SetDrawBackgroundMask(REDRAW_DOOR_1);
2851 SetDrawBackgroundMask(REDRAW_FIELD);
2857 if (game_status != GAME_MODE_MAIN)
2860 button_status = MB_RELEASED;
2862 request_gadget_id = -1;
2864 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2876 case EVENT_BUTTONPRESS:
2877 case EVENT_BUTTONRELEASE:
2878 case EVENT_MOTIONNOTIFY:
2880 if (event.type == EVENT_MOTIONNOTIFY)
2882 if (!PointerInWindow(window))
2883 continue; /* window and pointer are on different screens */
2888 motion_status = TRUE;
2889 mx = ((MotionEvent *) &event)->x;
2890 my = ((MotionEvent *) &event)->y;
2894 motion_status = FALSE;
2895 mx = ((ButtonEvent *) &event)->x;
2896 my = ((ButtonEvent *) &event)->y;
2897 if (event.type == EVENT_BUTTONPRESS)
2898 button_status = ((ButtonEvent *) &event)->button;
2900 button_status = MB_RELEASED;
2903 /* this sets 'request_gadget_id' */
2904 HandleGadgets(mx, my, button_status);
2906 switch (request_gadget_id)
2908 case TOOL_CTRL_ID_YES:
2911 case TOOL_CTRL_ID_NO:
2914 case TOOL_CTRL_ID_CONFIRM:
2915 result = TRUE | FALSE;
2918 case TOOL_CTRL_ID_PLAYER_1:
2921 case TOOL_CTRL_ID_PLAYER_2:
2924 case TOOL_CTRL_ID_PLAYER_3:
2927 case TOOL_CTRL_ID_PLAYER_4:
2938 case EVENT_KEYPRESS:
2939 switch (GetEventKey((KeyEvent *)&event, TRUE))
2952 if (req_state & REQ_PLAYER)
2956 case EVENT_KEYRELEASE:
2957 ClearPlayerAction();
2961 HandleOtherEvents(&event);
2965 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2967 int joy = AnyJoystick();
2969 if (joy & JOY_BUTTON_1)
2971 else if (joy & JOY_BUTTON_2)
2977 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2979 HandleGameActions();
2986 if (!PendingEvent()) /* delay only if no pending events */
2995 if (!PendingEvent()) /* delay only if no pending events */
2998 /* don't eat all CPU time */
3005 if (game_status != GAME_MODE_MAIN)
3010 if (!(req_state & REQ_STAY_OPEN))
3012 CloseDoor(DOOR_CLOSE_1);
3014 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3015 (req_state & REQ_REOPEN))
3016 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3021 if (game_status == GAME_MODE_PLAYING)
3023 SetPanelBackground();
3024 SetDrawBackgroundMask(REDRAW_DOOR_1);
3028 SetDrawBackgroundMask(REDRAW_FIELD);
3031 #if defined(NETWORK_AVALIABLE)
3032 /* continue network game after request */
3033 if (options.network &&
3034 game_status == GAME_MODE_PLAYING &&
3035 req_state & REQUEST_WAIT_FOR_INPUT)
3036 SendToServer_ContinuePlaying();
3039 /* restore deactivated drawing when quick-loading level tape recording */
3040 if (tape.playing && tape.deactivate_display)
3041 TapeDeactivateDisplayOn();
3046 unsigned int OpenDoor(unsigned int door_state)
3048 if (door_state & DOOR_COPY_BACK)
3050 if (door_state & DOOR_OPEN_1)
3051 BlitBitmap(bitmap_db_door, bitmap_db_door,
3052 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3053 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3055 if (door_state & DOOR_OPEN_2)
3056 BlitBitmap(bitmap_db_door, bitmap_db_door,
3057 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3058 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3060 door_state &= ~DOOR_COPY_BACK;
3063 return MoveDoor(door_state);
3066 unsigned int CloseDoor(unsigned int door_state)
3068 unsigned int old_door_state = GetDoorState();
3070 if (!(door_state & DOOR_NO_COPY_BACK))
3072 if (old_door_state & DOOR_OPEN_1)
3073 BlitBitmap(backbuffer, bitmap_db_door,
3074 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3076 if (old_door_state & DOOR_OPEN_2)
3077 BlitBitmap(backbuffer, bitmap_db_door,
3078 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3080 door_state &= ~DOOR_NO_COPY_BACK;
3083 return MoveDoor(door_state);
3086 unsigned int GetDoorState()
3088 return MoveDoor(DOOR_GET_STATE);
3091 unsigned int SetDoorState(unsigned int door_state)
3093 return MoveDoor(door_state | DOOR_SET_STATE);
3096 unsigned int MoveDoor(unsigned int door_state)
3098 static int door1 = DOOR_OPEN_1;
3099 static int door2 = DOOR_CLOSE_2;
3100 unsigned long door_delay = 0;
3101 unsigned long door_delay_value;
3104 if (door_1.width < 0 || door_1.width > DXSIZE)
3105 door_1.width = DXSIZE;
3106 if (door_1.height < 0 || door_1.height > DYSIZE)
3107 door_1.height = DYSIZE;
3108 if (door_2.width < 0 || door_2.width > VXSIZE)
3109 door_2.width = VXSIZE;
3110 if (door_2.height < 0 || door_2.height > VYSIZE)
3111 door_2.height = VYSIZE;
3113 if (door_state == DOOR_GET_STATE)
3114 return (door1 | door2);
3116 if (door_state & DOOR_SET_STATE)
3118 if (door_state & DOOR_ACTION_1)
3119 door1 = door_state & DOOR_ACTION_1;
3120 if (door_state & DOOR_ACTION_2)
3121 door2 = door_state & DOOR_ACTION_2;
3123 return (door1 | door2);
3126 if (!(door_state & DOOR_FORCE_REDRAW))
3128 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3129 door_state &= ~DOOR_OPEN_1;
3130 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3131 door_state &= ~DOOR_CLOSE_1;
3132 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3133 door_state &= ~DOOR_OPEN_2;
3134 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3135 door_state &= ~DOOR_CLOSE_2;
3138 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3141 if (setup.quick_doors)
3143 stepsize = 20; /* must be chosen to always draw last frame */
3144 door_delay_value = 0;
3147 if (global.autoplay_leveldir)
3149 door_state |= DOOR_NO_DELAY;
3150 door_state &= ~DOOR_CLOSE_ALL;
3153 if (door_state & DOOR_ACTION)
3155 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3156 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3157 boolean door_1_done = (!handle_door_1);
3158 boolean door_2_done = (!handle_door_2);
3159 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3160 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3161 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3162 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3163 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3164 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3165 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3166 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3167 int door_skip = max_door_size - door_size;
3168 int end = door_size;
3169 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3172 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3174 /* opening door sound has priority over simultaneously closing door */
3175 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3176 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3177 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3178 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3181 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3184 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3185 GC gc = bitmap->stored_clip_gc;
3187 if (door_state & DOOR_ACTION_1)
3189 int a = MIN(x * door_1.step_offset, end);
3190 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3191 int i = p + door_skip;
3193 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3195 BlitBitmap(bitmap_db_door, drawto,
3196 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3197 DXSIZE, DYSIZE, DX, DY);
3201 BlitBitmap(bitmap_db_door, drawto,
3202 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3203 DXSIZE, DYSIZE - p / 2, DX, DY);
3205 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3208 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3210 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3211 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3212 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3213 int dst2_x = DX, dst2_y = DY;
3214 int width = i, height = DYSIZE;
3216 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3217 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3220 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3221 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3224 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3226 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3227 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3228 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3229 int dst2_x = DX, dst2_y = DY;
3230 int width = DXSIZE, height = i;
3232 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3233 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3236 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3237 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3240 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3242 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3244 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3245 BlitBitmapMasked(bitmap, drawto,
3246 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3247 DX + DXSIZE - i, DY + j);
3248 BlitBitmapMasked(bitmap, drawto,
3249 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3250 DX + DXSIZE - i, DY + 140 + j);
3251 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3252 DY - (DOOR_GFX_PAGEY1 + j));
3253 BlitBitmapMasked(bitmap, drawto,
3254 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3256 BlitBitmapMasked(bitmap, drawto,
3257 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3260 BlitBitmapMasked(bitmap, drawto,
3261 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3263 BlitBitmapMasked(bitmap, drawto,
3264 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3266 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3267 BlitBitmapMasked(bitmap, drawto,
3268 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3269 DX + DXSIZE - i, DY + 77 + j);
3270 BlitBitmapMasked(bitmap, drawto,
3271 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3272 DX + DXSIZE - i, DY + 203 + j);
3275 redraw_mask |= REDRAW_DOOR_1;
3276 door_1_done = (a == end);
3279 if (door_state & DOOR_ACTION_2)
3281 int a = MIN(x * door_2.step_offset, door_size);
3282 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3283 int i = p + door_skip;
3285 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3287 BlitBitmap(bitmap_db_door, drawto,
3288 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3289 VXSIZE, VYSIZE, VX, VY);
3291 else if (x <= VYSIZE)
3293 BlitBitmap(bitmap_db_door, drawto,
3294 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3295 VXSIZE, VYSIZE - p / 2, VX, VY);
3297 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3300 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3302 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3303 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3304 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3305 int dst2_x = VX, dst2_y = VY;
3306 int width = i, height = VYSIZE;
3308 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3309 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3312 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3313 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3316 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3318 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3319 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3320 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3321 int dst2_x = VX, dst2_y = VY;
3322 int width = VXSIZE, height = i;
3324 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3325 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3328 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3329 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3332 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3334 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3336 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3337 BlitBitmapMasked(bitmap, drawto,
3338 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3339 VX + VXSIZE - i, VY + j);
3340 SetClipOrigin(bitmap, gc,
3341 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3342 BlitBitmapMasked(bitmap, drawto,
3343 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3346 BlitBitmapMasked(bitmap, drawto,
3347 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3348 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3349 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3350 BlitBitmapMasked(bitmap, drawto,
3351 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3353 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3356 redraw_mask |= REDRAW_DOOR_2;
3357 door_2_done = (a == VXSIZE);
3360 if (!(door_state & DOOR_NO_DELAY))
3364 if (game_status == GAME_MODE_MAIN)
3367 WaitUntilDelayReached(&door_delay, door_delay_value);
3372 if (door_state & DOOR_ACTION_1)
3373 door1 = door_state & DOOR_ACTION_1;
3374 if (door_state & DOOR_ACTION_2)
3375 door2 = door_state & DOOR_ACTION_2;
3377 return (door1 | door2);
3380 void DrawSpecialEditorDoor()
3382 /* draw bigger toolbox window */
3383 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3384 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3386 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3387 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3390 redraw_mask |= REDRAW_ALL;
3393 void UndrawSpecialEditorDoor()
3395 /* draw normal tape recorder window */
3396 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3397 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3400 redraw_mask |= REDRAW_ALL;
3404 /* ---------- new tool button stuff ---------------------------------------- */
3406 /* graphic position values for tool buttons */
3407 #define TOOL_BUTTON_YES_XPOS 2
3408 #define TOOL_BUTTON_YES_YPOS 250
3409 #define TOOL_BUTTON_YES_GFX_YPOS 0
3410 #define TOOL_BUTTON_YES_XSIZE 46
3411 #define TOOL_BUTTON_YES_YSIZE 28
3412 #define TOOL_BUTTON_NO_XPOS 52
3413 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3414 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3415 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3416 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3417 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3418 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3419 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3420 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3421 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3422 #define TOOL_BUTTON_PLAYER_XSIZE 30
3423 #define TOOL_BUTTON_PLAYER_YSIZE 30
3424 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3425 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3426 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3427 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3428 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3429 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3430 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3431 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3432 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3433 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3434 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3435 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3436 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3437 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3438 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3439 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3440 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3441 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3442 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3443 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3452 } toolbutton_info[NUM_TOOL_BUTTONS] =
3455 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3456 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3457 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3462 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3463 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3464 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3469 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3470 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3471 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3472 TOOL_CTRL_ID_CONFIRM,
3476 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3477 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3478 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3479 TOOL_CTRL_ID_PLAYER_1,
3483 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3484 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3485 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3486 TOOL_CTRL_ID_PLAYER_2,
3490 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3491 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3492 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3493 TOOL_CTRL_ID_PLAYER_3,
3497 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3498 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3499 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3500 TOOL_CTRL_ID_PLAYER_4,
3505 void CreateToolButtons()
3509 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3511 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3512 Bitmap *deco_bitmap = None;
3513 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3514 struct GadgetInfo *gi;
3515 unsigned long event_mask;
3516 int gd_xoffset, gd_yoffset;
3517 int gd_x1, gd_x2, gd_y;
3520 event_mask = GD_EVENT_RELEASED;
3522 gd_xoffset = toolbutton_info[i].xpos;
3523 gd_yoffset = toolbutton_info[i].ypos;
3524 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3525 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3526 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3528 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3530 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3532 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3533 &deco_bitmap, &deco_x, &deco_y);
3534 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3535 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3538 gi = CreateGadget(GDI_CUSTOM_ID, id,
3539 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3540 GDI_X, DX + toolbutton_info[i].x,
3541 GDI_Y, DY + toolbutton_info[i].y,
3542 GDI_WIDTH, toolbutton_info[i].width,
3543 GDI_HEIGHT, toolbutton_info[i].height,
3544 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3545 GDI_STATE, GD_BUTTON_UNPRESSED,
3546 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3547 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3548 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3549 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3550 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3551 GDI_DECORATION_SHIFTING, 1, 1,
3552 GDI_DIRECT_DRAW, FALSE,
3553 GDI_EVENT_MASK, event_mask,
3554 GDI_CALLBACK_ACTION, HandleToolButtons,
3558 Error(ERR_EXIT, "cannot create gadget");
3560 tool_gadget[id] = gi;
3564 void FreeToolButtons()
3568 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3569 FreeGadget(tool_gadget[i]);
3572 static void UnmapToolButtons()
3576 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3577 UnmapGadget(tool_gadget[i]);
3580 static void HandleToolButtons(struct GadgetInfo *gi)
3582 request_gadget_id = gi->custom_id;
3585 static struct Mapping_EM_to_RND_object
3588 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3589 boolean is_backside; /* backside of moving element */
3595 em_object_mapping_list[] =
3598 Xblank, TRUE, FALSE,
3602 Yacid_splash_eB, FALSE, FALSE,
3603 EL_ACID_SPLASH_RIGHT, -1, -1
3606 Yacid_splash_wB, FALSE, FALSE,
3607 EL_ACID_SPLASH_LEFT, -1, -1
3610 #ifdef EM_ENGINE_BAD_ROLL
3612 Xstone_force_e, FALSE, FALSE,
3613 EL_ROCK, -1, MV_BIT_RIGHT
3616 Xstone_force_w, FALSE, FALSE,
3617 EL_ROCK, -1, MV_BIT_LEFT
3620 Xnut_force_e, FALSE, FALSE,
3621 EL_NUT, -1, MV_BIT_RIGHT
3624 Xnut_force_w, FALSE, FALSE,
3625 EL_NUT, -1, MV_BIT_LEFT
3628 Xspring_force_e, FALSE, FALSE,
3629 EL_SPRING, -1, MV_BIT_RIGHT
3632 Xspring_force_w, FALSE, FALSE,
3633 EL_SPRING, -1, MV_BIT_LEFT
3636 Xemerald_force_e, FALSE, FALSE,
3637 EL_EMERALD, -1, MV_BIT_RIGHT
3640 Xemerald_force_w, FALSE, FALSE,
3641 EL_EMERALD, -1, MV_BIT_LEFT
3644 Xdiamond_force_e, FALSE, FALSE,
3645 EL_DIAMOND, -1, MV_BIT_RIGHT
3648 Xdiamond_force_w, FALSE, FALSE,
3649 EL_DIAMOND, -1, MV_BIT_LEFT
3652 Xbomb_force_e, FALSE, FALSE,
3653 EL_BOMB, -1, MV_BIT_RIGHT
3656 Xbomb_force_w, FALSE, FALSE,
3657 EL_BOMB, -1, MV_BIT_LEFT
3659 #endif /* EM_ENGINE_BAD_ROLL */
3662 Xstone, TRUE, FALSE,
3666 Xstone_pause, FALSE, FALSE,
3670 Xstone_fall, FALSE, FALSE,
3674 Ystone_s, FALSE, FALSE,
3675 EL_ROCK, ACTION_FALLING, -1
3678 Ystone_sB, FALSE, TRUE,
3679 EL_ROCK, ACTION_FALLING, -1
3682 Ystone_e, FALSE, FALSE,
3683 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3686 Ystone_eB, FALSE, TRUE,
3687 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3690 Ystone_w, FALSE, FALSE,
3691 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3694 Ystone_wB, FALSE, TRUE,
3695 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3702 Xnut_pause, FALSE, FALSE,
3706 Xnut_fall, FALSE, FALSE,
3710 Ynut_s, FALSE, FALSE,
3711 EL_NUT, ACTION_FALLING, -1
3714 Ynut_sB, FALSE, TRUE,
3715 EL_NUT, ACTION_FALLING, -1
3718 Ynut_e, FALSE, FALSE,
3719 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3722 Ynut_eB, FALSE, TRUE,
3723 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3726 Ynut_w, FALSE, FALSE,
3727 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3730 Ynut_wB, FALSE, TRUE,
3731 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3734 Xbug_n, TRUE, FALSE,
3738 Xbug_e, TRUE, FALSE,
3739 EL_BUG_RIGHT, -1, -1
3742 Xbug_s, TRUE, FALSE,
3746 Xbug_w, TRUE, FALSE,
3750 Xbug_gon, FALSE, FALSE,
3754 Xbug_goe, FALSE, FALSE,
3755 EL_BUG_RIGHT, -1, -1
3758 Xbug_gos, FALSE, FALSE,
3762 Xbug_gow, FALSE, FALSE,
3766 Ybug_n, FALSE, FALSE,
3767 EL_BUG, ACTION_MOVING, MV_BIT_UP
3770 Ybug_nB, FALSE, TRUE,
3771 EL_BUG, ACTION_MOVING, MV_BIT_UP
3774 Ybug_e, FALSE, FALSE,
3775 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3778 Ybug_eB, FALSE, TRUE,
3779 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3782 Ybug_s, FALSE, FALSE,
3783 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3786 Ybug_sB, FALSE, TRUE,
3787 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3790 Ybug_w, FALSE, FALSE,
3791 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3794 Ybug_wB, FALSE, TRUE,
3795 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3798 Ybug_w_n, FALSE, FALSE,
3799 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3802 Ybug_n_e, FALSE, FALSE,
3803 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3806 Ybug_e_s, FALSE, FALSE,
3807 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3810 Ybug_s_w, FALSE, FALSE,
3811 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3814 Ybug_e_n, FALSE, FALSE,
3815 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3818 Ybug_s_e, FALSE, FALSE,
3819 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3822 Ybug_w_s, FALSE, FALSE,
3823 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3826 Ybug_n_w, FALSE, FALSE,
3827 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3830 Ybug_stone, FALSE, FALSE,
3831 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3834 Ybug_spring, FALSE, FALSE,
3835 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3838 Xtank_n, TRUE, FALSE,
3839 EL_SPACESHIP_UP, -1, -1
3842 Xtank_e, TRUE, FALSE,
3843 EL_SPACESHIP_RIGHT, -1, -1
3846 Xtank_s, TRUE, FALSE,
3847 EL_SPACESHIP_DOWN, -1, -1
3850 Xtank_w, TRUE, FALSE,
3851 EL_SPACESHIP_LEFT, -1, -1
3854 Xtank_gon, FALSE, FALSE,
3855 EL_SPACESHIP_UP, -1, -1
3858 Xtank_goe, FALSE, FALSE,
3859 EL_SPACESHIP_RIGHT, -1, -1
3862 Xtank_gos, FALSE, FALSE,
3863 EL_SPACESHIP_DOWN, -1, -1
3866 Xtank_gow, FALSE, FALSE,
3867 EL_SPACESHIP_LEFT, -1, -1
3870 Ytank_n, FALSE, FALSE,
3871 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3874 Ytank_nB, FALSE, TRUE,
3875 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3878 Ytank_e, FALSE, FALSE,
3879 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3882 Ytank_eB, FALSE, TRUE,
3883 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3886 Ytank_s, FALSE, FALSE,
3887 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3890 Ytank_sB, FALSE, TRUE,
3891 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3894 Ytank_w, FALSE, FALSE,
3895 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3898 Ytank_wB, FALSE, TRUE,
3899 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3902 Ytank_w_n, FALSE, FALSE,
3903 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3906 Ytank_n_e, FALSE, FALSE,
3907 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3910 Ytank_e_s, FALSE, FALSE,
3911 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3914 Ytank_s_w, FALSE, FALSE,
3915 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3918 Ytank_e_n, FALSE, FALSE,
3919 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3922 Ytank_s_e, FALSE, FALSE,
3923 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3926 Ytank_w_s, FALSE, FALSE,
3927 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3930 Ytank_n_w, FALSE, FALSE,
3931 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3934 Ytank_stone, FALSE, FALSE,
3935 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3938 Ytank_spring, FALSE, FALSE,
3939 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3942 Xandroid, TRUE, FALSE,
3943 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3946 Xandroid_1_n, FALSE, FALSE,
3947 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3950 Xandroid_2_n, FALSE, FALSE,
3951 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3954 Xandroid_1_e, FALSE, FALSE,
3955 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3958 Xandroid_2_e, FALSE, FALSE,
3959 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3962 Xandroid_1_w, FALSE, FALSE,
3963 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3966 Xandroid_2_w, FALSE, FALSE,
3967 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3970 Xandroid_1_s, FALSE, FALSE,
3971 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3974 Xandroid_2_s, FALSE, FALSE,
3975 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3978 Yandroid_n, FALSE, FALSE,
3979 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3982 Yandroid_nB, FALSE, TRUE,
3983 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3986 Yandroid_ne, FALSE, FALSE,
3987 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3990 Yandroid_neB, FALSE, TRUE,
3991 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3994 Yandroid_e, FALSE, FALSE,
3995 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3998 Yandroid_eB, FALSE, TRUE,
3999 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4002 Yandroid_se, FALSE, FALSE,
4003 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4006 Yandroid_seB, FALSE, TRUE,
4007 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4010 Yandroid_s, FALSE, FALSE,
4011 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4014 Yandroid_sB, FALSE, TRUE,
4015 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4018 Yandroid_sw, FALSE, FALSE,
4019 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4022 Yandroid_swB, FALSE, TRUE,
4023 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4026 Yandroid_w, FALSE, FALSE,
4027 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4030 Yandroid_wB, FALSE, TRUE,
4031 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4034 Yandroid_nw, FALSE, FALSE,
4035 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4038 Yandroid_nwB, FALSE, TRUE,
4039 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4042 Xspring, TRUE, FALSE,
4046 Xspring_pause, FALSE, FALSE,
4050 Xspring_e, FALSE, FALSE,
4054 Xspring_w, FALSE, FALSE,
4058 Xspring_fall, FALSE, FALSE,
4062 Yspring_s, FALSE, FALSE,
4063 EL_SPRING, ACTION_FALLING, -1
4066 Yspring_sB, FALSE, TRUE,
4067 EL_SPRING, ACTION_FALLING, -1
4070 Yspring_e, FALSE, FALSE,
4071 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4074 Yspring_eB, FALSE, TRUE,
4075 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4078 Yspring_w, FALSE, FALSE,
4079 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4082 Yspring_wB, FALSE, TRUE,
4083 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4086 Yspring_kill_e, FALSE, FALSE,
4087 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4090 Yspring_kill_eB, FALSE, TRUE,
4091 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4094 Yspring_kill_w, FALSE, FALSE,
4095 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4098 Yspring_kill_wB, FALSE, TRUE,
4099 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4102 Xeater_n, TRUE, FALSE,
4103 EL_YAMYAM_UP, -1, -1
4106 Xeater_e, TRUE, FALSE,
4107 EL_YAMYAM_RIGHT, -1, -1
4110 Xeater_w, TRUE, FALSE,
4111 EL_YAMYAM_LEFT, -1, -1
4114 Xeater_s, TRUE, FALSE,
4115 EL_YAMYAM_DOWN, -1, -1
4118 Yeater_n, FALSE, FALSE,
4119 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4122 Yeater_nB, FALSE, TRUE,
4123 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4126 Yeater_e, FALSE, FALSE,
4127 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4130 Yeater_eB, FALSE, TRUE,
4131 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4134 Yeater_s, FALSE, FALSE,
4135 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4138 Yeater_sB, FALSE, TRUE,
4139 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4142 Yeater_w, FALSE, FALSE,
4143 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4146 Yeater_wB, FALSE, TRUE,
4147 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4150 Yeater_stone, FALSE, FALSE,
4151 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4154 Yeater_spring, FALSE, FALSE,
4155 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4158 Xalien, TRUE, FALSE,
4162 Xalien_pause, FALSE, FALSE,
4166 Yalien_n, FALSE, FALSE,
4167 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4170 Yalien_nB, FALSE, TRUE,
4171 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4174 Yalien_e, FALSE, FALSE,
4175 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4178 Yalien_eB, FALSE, TRUE,
4179 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4182 Yalien_s, FALSE, FALSE,
4183 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4186 Yalien_sB, FALSE, TRUE,
4187 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4190 Yalien_w, FALSE, FALSE,
4191 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4194 Yalien_wB, FALSE, TRUE,
4195 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4198 Yalien_stone, FALSE, FALSE,
4199 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4202 Yalien_spring, FALSE, FALSE,
4203 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4206 Xemerald, TRUE, FALSE,
4210 Xemerald_pause, FALSE, FALSE,
4214 Xemerald_fall, FALSE, FALSE,
4218 Xemerald_shine, FALSE, FALSE,
4219 EL_EMERALD, ACTION_TWINKLING, -1
4222 Yemerald_s, FALSE, FALSE,
4223 EL_EMERALD, ACTION_FALLING, -1
4226 Yemerald_sB, FALSE, TRUE,
4227 EL_EMERALD, ACTION_FALLING, -1
4230 Yemerald_e, FALSE, FALSE,
4231 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4234 Yemerald_eB, FALSE, TRUE,
4235 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4238 Yemerald_w, FALSE, FALSE,
4239 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4242 Yemerald_wB, FALSE, TRUE,
4243 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4246 Yemerald_eat, FALSE, FALSE,
4247 EL_EMERALD, ACTION_COLLECTING, -1
4250 Yemerald_stone, FALSE, FALSE,
4251 EL_NUT, ACTION_BREAKING, -1
4254 Xdiamond, TRUE, FALSE,
4258 Xdiamond_pause, FALSE, FALSE,
4262 Xdiamond_fall, FALSE, FALSE,
4266 Xdiamond_shine, FALSE, FALSE,
4267 EL_DIAMOND, ACTION_TWINKLING, -1
4270 Ydiamond_s, FALSE, FALSE,
4271 EL_DIAMOND, ACTION_FALLING, -1
4274 Ydiamond_sB, FALSE, TRUE,
4275 EL_DIAMOND, ACTION_FALLING, -1
4278 Ydiamond_e, FALSE, FALSE,
4279 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4282 Ydiamond_eB, FALSE, TRUE,
4283 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4286 Ydiamond_w, FALSE, FALSE,
4287 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4290 Ydiamond_wB, FALSE, TRUE,
4291 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4294 Ydiamond_eat, FALSE, FALSE,
4295 EL_DIAMOND, ACTION_COLLECTING, -1
4298 Ydiamond_stone, FALSE, FALSE,
4299 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4302 Xdrip_fall, TRUE, FALSE,
4303 EL_AMOEBA_DROP, -1, -1
4306 Xdrip_stretch, FALSE, FALSE,
4307 EL_AMOEBA_DROP, ACTION_FALLING, -1
4310 Xdrip_stretchB, FALSE, TRUE,
4311 EL_AMOEBA_DROP, ACTION_FALLING, -1
4314 Xdrip_eat, FALSE, FALSE,
4315 EL_AMOEBA_DROP, ACTION_GROWING, -1
4318 Ydrip_s1, FALSE, FALSE,
4319 EL_AMOEBA_DROP, ACTION_FALLING, -1
4322 Ydrip_s1B, FALSE, TRUE,
4323 EL_AMOEBA_DROP, ACTION_FALLING, -1
4326 Ydrip_s2, FALSE, FALSE,
4327 EL_AMOEBA_DROP, ACTION_FALLING, -1
4330 Ydrip_s2B, FALSE, TRUE,
4331 EL_AMOEBA_DROP, ACTION_FALLING, -1
4338 Xbomb_pause, FALSE, FALSE,
4342 Xbomb_fall, FALSE, FALSE,
4346 Ybomb_s, FALSE, FALSE,
4347 EL_BOMB, ACTION_FALLING, -1
4350 Ybomb_sB, FALSE, TRUE,
4351 EL_BOMB, ACTION_FALLING, -1
4354 Ybomb_e, FALSE, FALSE,
4355 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4358 Ybomb_eB, FALSE, TRUE,
4359 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4362 Ybomb_w, FALSE, FALSE,
4363 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4366 Ybomb_wB, FALSE, TRUE,
4367 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4370 Ybomb_eat, FALSE, FALSE,
4371 EL_BOMB, ACTION_ACTIVATING, -1
4374 Xballoon, TRUE, FALSE,
4378 Yballoon_n, FALSE, FALSE,
4379 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4382 Yballoon_nB, FALSE, TRUE,
4383 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4386 Yballoon_e, FALSE, FALSE,
4387 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4390 Yballoon_eB, FALSE, TRUE,
4391 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4394 Yballoon_s, FALSE, FALSE,
4395 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4398 Yballoon_sB, FALSE, TRUE,
4399 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4402 Yballoon_w, FALSE, FALSE,
4403 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4406 Yballoon_wB, FALSE, TRUE,
4407 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4410 Xgrass, TRUE, FALSE,
4411 EL_EMC_GRASS, -1, -1
4414 Ygrass_nB, FALSE, FALSE,
4415 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4418 Ygrass_eB, FALSE, FALSE,
4419 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4422 Ygrass_sB, FALSE, FALSE,
4423 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4426 Ygrass_wB, FALSE, FALSE,
4427 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4434 Ydirt_nB, FALSE, FALSE,
4435 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4438 Ydirt_eB, FALSE, FALSE,
4439 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4442 Ydirt_sB, FALSE, FALSE,
4443 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4446 Ydirt_wB, FALSE, FALSE,
4447 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4450 Xacid_ne, TRUE, FALSE,
4451 EL_ACID_POOL_TOPRIGHT, -1, -1
4454 Xacid_se, TRUE, FALSE,
4455 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4458 Xacid_s, TRUE, FALSE,
4459 EL_ACID_POOL_BOTTOM, -1, -1
4462 Xacid_sw, TRUE, FALSE,
4463 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4466 Xacid_nw, TRUE, FALSE,
4467 EL_ACID_POOL_TOPLEFT, -1, -1
4470 Xacid_1, TRUE, FALSE,
4474 Xacid_2, FALSE, FALSE,
4478 Xacid_3, FALSE, FALSE,
4482 Xacid_4, FALSE, FALSE,
4486 Xacid_5, FALSE, FALSE,
4490 Xacid_6, FALSE, FALSE,
4494 Xacid_7, FALSE, FALSE,
4498 Xacid_8, FALSE, FALSE,
4502 Xball_1, TRUE, FALSE,
4503 EL_EMC_MAGIC_BALL, -1, -1
4506 Xball_1B, FALSE, FALSE,
4507 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4510 Xball_2, FALSE, FALSE,
4511 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4514 Xball_2B, FALSE, FALSE,
4515 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4518 Yball_eat, FALSE, FALSE,
4519 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4522 Ykey_1_eat, FALSE, FALSE,
4523 EL_EM_KEY_1, ACTION_COLLECTING, -1
4526 Ykey_2_eat, FALSE, FALSE,
4527 EL_EM_KEY_2, ACTION_COLLECTING, -1
4530 Ykey_3_eat, FALSE, FALSE,
4531 EL_EM_KEY_3, ACTION_COLLECTING, -1
4534 Ykey_4_eat, FALSE, FALSE,
4535 EL_EM_KEY_4, ACTION_COLLECTING, -1
4538 Ykey_5_eat, FALSE, FALSE,
4539 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4542 Ykey_6_eat, FALSE, FALSE,
4543 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4546 Ykey_7_eat, FALSE, FALSE,
4547 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4550 Ykey_8_eat, FALSE, FALSE,
4551 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4554 Ylenses_eat, FALSE, FALSE,
4555 EL_EMC_LENSES, ACTION_COLLECTING, -1
4558 Ymagnify_eat, FALSE, FALSE,
4559 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4562 Ygrass_eat, FALSE, FALSE,
4563 EL_EMC_GRASS, ACTION_SNAPPING, -1
4566 Ydirt_eat, FALSE, FALSE,
4567 EL_SAND, ACTION_SNAPPING, -1
4570 Xgrow_ns, TRUE, FALSE,
4571 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4574 Ygrow_ns_eat, FALSE, FALSE,
4575 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4578 Xgrow_ew, TRUE, FALSE,
4579 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4582 Ygrow_ew_eat, FALSE, FALSE,
4583 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4586 Xwonderwall, TRUE, FALSE,
4587 EL_MAGIC_WALL, -1, -1
4590 XwonderwallB, FALSE, FALSE,
4591 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4594 Xamoeba_1, TRUE, FALSE,
4595 EL_AMOEBA_DRY, ACTION_OTHER, -1
4598 Xamoeba_2, FALSE, FALSE,
4599 EL_AMOEBA_DRY, ACTION_OTHER, -1
4602 Xamoeba_3, FALSE, FALSE,
4603 EL_AMOEBA_DRY, ACTION_OTHER, -1
4606 Xamoeba_4, FALSE, FALSE,
4607 EL_AMOEBA_DRY, ACTION_OTHER, -1
4610 Xamoeba_5, TRUE, FALSE,
4611 EL_AMOEBA_WET, ACTION_OTHER, -1
4614 Xamoeba_6, FALSE, FALSE,
4615 EL_AMOEBA_WET, ACTION_OTHER, -1
4618 Xamoeba_7, FALSE, FALSE,
4619 EL_AMOEBA_WET, ACTION_OTHER, -1
4622 Xamoeba_8, FALSE, FALSE,
4623 EL_AMOEBA_WET, ACTION_OTHER, -1
4626 Xdoor_1, TRUE, FALSE,
4627 EL_EM_GATE_1, -1, -1
4630 Xdoor_2, TRUE, FALSE,
4631 EL_EM_GATE_2, -1, -1
4634 Xdoor_3, TRUE, FALSE,
4635 EL_EM_GATE_3, -1, -1
4638 Xdoor_4, TRUE, FALSE,
4639 EL_EM_GATE_4, -1, -1
4642 Xdoor_5, TRUE, FALSE,
4643 EL_EMC_GATE_5, -1, -1
4646 Xdoor_6, TRUE, FALSE,
4647 EL_EMC_GATE_6, -1, -1
4650 Xdoor_7, TRUE, FALSE,
4651 EL_EMC_GATE_7, -1, -1
4654 Xdoor_8, TRUE, FALSE,
4655 EL_EMC_GATE_8, -1, -1
4658 Xkey_1, TRUE, FALSE,
4662 Xkey_2, TRUE, FALSE,
4666 Xkey_3, TRUE, FALSE,
4670 Xkey_4, TRUE, FALSE,
4674 Xkey_5, TRUE, FALSE,
4675 EL_EMC_KEY_5, -1, -1
4678 Xkey_6, TRUE, FALSE,
4679 EL_EMC_KEY_6, -1, -1
4682 Xkey_7, TRUE, FALSE,
4683 EL_EMC_KEY_7, -1, -1
4686 Xkey_8, TRUE, FALSE,
4687 EL_EMC_KEY_8, -1, -1
4690 Xwind_n, TRUE, FALSE,
4691 EL_BALLOON_SWITCH_UP, -1, -1
4694 Xwind_e, TRUE, FALSE,
4695 EL_BALLOON_SWITCH_RIGHT, -1, -1
4698 Xwind_s, TRUE, FALSE,
4699 EL_BALLOON_SWITCH_DOWN, -1, -1
4702 Xwind_w, TRUE, FALSE,
4703 EL_BALLOON_SWITCH_LEFT, -1, -1
4706 Xwind_nesw, TRUE, FALSE,
4707 EL_BALLOON_SWITCH_ANY, -1, -1
4710 Xwind_stop, TRUE, FALSE,
4711 EL_BALLOON_SWITCH_NONE, -1, -1
4715 EL_EM_EXIT_CLOSED, -1, -1
4718 Xexit_1, TRUE, FALSE,
4719 EL_EM_EXIT_OPEN, -1, -1
4722 Xexit_2, FALSE, FALSE,
4723 EL_EM_EXIT_OPEN, -1, -1
4726 Xexit_3, FALSE, FALSE,
4727 EL_EM_EXIT_OPEN, -1, -1
4730 Xdynamite, TRUE, FALSE,
4731 EL_EM_DYNAMITE, -1, -1
4734 Ydynamite_eat, FALSE, FALSE,
4735 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4738 Xdynamite_1, TRUE, FALSE,
4739 EL_EM_DYNAMITE_ACTIVE, -1, -1
4742 Xdynamite_2, FALSE, FALSE,
4743 EL_EM_DYNAMITE_ACTIVE, -1, -1
4746 Xdynamite_3, FALSE, FALSE,
4747 EL_EM_DYNAMITE_ACTIVE, -1, -1
4750 Xdynamite_4, FALSE, FALSE,
4751 EL_EM_DYNAMITE_ACTIVE, -1, -1
4754 Xbumper, TRUE, FALSE,
4755 EL_EMC_SPRING_BUMPER, -1, -1
4758 XbumperB, FALSE, FALSE,
4759 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4762 Xwheel, TRUE, FALSE,
4763 EL_ROBOT_WHEEL, -1, -1
4766 XwheelB, FALSE, FALSE,
4767 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4770 Xswitch, TRUE, FALSE,
4771 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4774 XswitchB, FALSE, FALSE,
4775 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4779 EL_QUICKSAND_EMPTY, -1, -1
4782 Xsand_stone, TRUE, FALSE,
4783 EL_QUICKSAND_FULL, -1, -1
4786 Xsand_stonein_1, FALSE, TRUE,
4787 EL_ROCK, ACTION_FILLING, -1
4790 Xsand_stonein_2, FALSE, TRUE,
4791 EL_ROCK, ACTION_FILLING, -1
4794 Xsand_stonein_3, FALSE, TRUE,
4795 EL_ROCK, ACTION_FILLING, -1
4798 Xsand_stonein_4, FALSE, TRUE,
4799 EL_ROCK, ACTION_FILLING, -1
4802 Xsand_stonesand_1, FALSE, FALSE,
4803 EL_QUICKSAND_FULL, -1, -1
4806 Xsand_stonesand_2, FALSE, FALSE,
4807 EL_QUICKSAND_FULL, -1, -1
4810 Xsand_stonesand_3, FALSE, FALSE,
4811 EL_QUICKSAND_FULL, -1, -1
4814 Xsand_stonesand_4, FALSE, FALSE,
4815 EL_QUICKSAND_FULL, -1, -1
4818 Xsand_stoneout_1, FALSE, FALSE,
4819 EL_ROCK, ACTION_EMPTYING, -1
4822 Xsand_stoneout_2, FALSE, FALSE,
4823 EL_ROCK, ACTION_EMPTYING, -1
4826 Xsand_sandstone_1, FALSE, FALSE,
4827 EL_QUICKSAND_FULL, -1, -1
4830 Xsand_sandstone_2, FALSE, FALSE,
4831 EL_QUICKSAND_FULL, -1, -1
4834 Xsand_sandstone_3, FALSE, FALSE,
4835 EL_QUICKSAND_FULL, -1, -1
4838 Xsand_sandstone_4, FALSE, FALSE,
4839 EL_QUICKSAND_FULL, -1, -1
4842 Xplant, TRUE, FALSE,
4843 EL_EMC_PLANT, -1, -1
4846 Yplant, FALSE, FALSE,
4847 EL_EMC_PLANT, -1, -1
4850 Xlenses, TRUE, FALSE,
4851 EL_EMC_LENSES, -1, -1
4854 Xmagnify, TRUE, FALSE,
4855 EL_EMC_MAGNIFIER, -1, -1
4858 Xdripper, TRUE, FALSE,
4859 EL_EMC_DRIPPER, -1, -1
4862 XdripperB, FALSE, FALSE,
4863 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4866 Xfake_blank, TRUE, FALSE,
4867 EL_INVISIBLE_WALL, -1, -1
4870 Xfake_blankB, FALSE, FALSE,
4871 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4874 Xfake_grass, TRUE, FALSE,
4875 EL_EMC_FAKE_GRASS, -1, -1
4878 Xfake_grassB, FALSE, FALSE,
4879 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4882 Xfake_door_1, TRUE, FALSE,
4883 EL_EM_GATE_1_GRAY, -1, -1
4886 Xfake_door_2, TRUE, FALSE,
4887 EL_EM_GATE_2_GRAY, -1, -1
4890 Xfake_door_3, TRUE, FALSE,
4891 EL_EM_GATE_3_GRAY, -1, -1
4894 Xfake_door_4, TRUE, FALSE,
4895 EL_EM_GATE_4_GRAY, -1, -1
4898 Xfake_door_5, TRUE, FALSE,
4899 EL_EMC_GATE_5_GRAY, -1, -1
4902 Xfake_door_6, TRUE, FALSE,
4903 EL_EMC_GATE_6_GRAY, -1, -1
4906 Xfake_door_7, TRUE, FALSE,
4907 EL_EMC_GATE_7_GRAY, -1, -1
4910 Xfake_door_8, TRUE, FALSE,
4911 EL_EMC_GATE_8_GRAY, -1, -1
4914 Xfake_acid_1, TRUE, FALSE,
4915 EL_EMC_FAKE_ACID, -1, -1
4918 Xfake_acid_2, FALSE, FALSE,
4919 EL_EMC_FAKE_ACID, -1, -1
4922 Xfake_acid_3, FALSE, FALSE,
4923 EL_EMC_FAKE_ACID, -1, -1
4926 Xfake_acid_4, FALSE, FALSE,
4927 EL_EMC_FAKE_ACID, -1, -1
4930 Xfake_acid_5, FALSE, FALSE,
4931 EL_EMC_FAKE_ACID, -1, -1
4934 Xfake_acid_6, FALSE, FALSE,
4935 EL_EMC_FAKE_ACID, -1, -1
4938 Xfake_acid_7, FALSE, FALSE,
4939 EL_EMC_FAKE_ACID, -1, -1
4942 Xfake_acid_8, FALSE, FALSE,
4943 EL_EMC_FAKE_ACID, -1, -1
4946 Xsteel_1, TRUE, FALSE,
4947 EL_STEELWALL, -1, -1
4950 Xsteel_2, TRUE, FALSE,
4951 EL_EMC_STEELWALL_2, -1, -1
4954 Xsteel_3, TRUE, FALSE,
4955 EL_EMC_STEELWALL_3, -1, -1
4958 Xsteel_4, TRUE, FALSE,
4959 EL_EMC_STEELWALL_4, -1, -1
4962 Xwall_1, TRUE, FALSE,
4966 Xwall_2, TRUE, FALSE,
4967 EL_EMC_WALL_14, -1, -1
4970 Xwall_3, TRUE, FALSE,
4971 EL_EMC_WALL_15, -1, -1
4974 Xwall_4, TRUE, FALSE,
4975 EL_EMC_WALL_16, -1, -1
4978 Xround_wall_1, TRUE, FALSE,
4979 EL_WALL_SLIPPERY, -1, -1
4982 Xround_wall_2, TRUE, FALSE,
4983 EL_EMC_WALL_SLIPPERY_2, -1, -1
4986 Xround_wall_3, TRUE, FALSE,
4987 EL_EMC_WALL_SLIPPERY_3, -1, -1
4990 Xround_wall_4, TRUE, FALSE,
4991 EL_EMC_WALL_SLIPPERY_4, -1, -1
4994 Xdecor_1, TRUE, FALSE,
4995 EL_EMC_WALL_8, -1, -1
4998 Xdecor_2, TRUE, FALSE,
4999 EL_EMC_WALL_6, -1, -1
5002 Xdecor_3, TRUE, FALSE,
5003 EL_EMC_WALL_4, -1, -1
5006 Xdecor_4, TRUE, FALSE,
5007 EL_EMC_WALL_7, -1, -1
5010 Xdecor_5, TRUE, FALSE,
5011 EL_EMC_WALL_5, -1, -1
5014 Xdecor_6, TRUE, FALSE,
5015 EL_EMC_WALL_9, -1, -1
5018 Xdecor_7, TRUE, FALSE,
5019 EL_EMC_WALL_10, -1, -1
5022 Xdecor_8, TRUE, FALSE,
5023 EL_EMC_WALL_1, -1, -1
5026 Xdecor_9, TRUE, FALSE,
5027 EL_EMC_WALL_2, -1, -1
5030 Xdecor_10, TRUE, FALSE,
5031 EL_EMC_WALL_3, -1, -1
5034 Xdecor_11, TRUE, FALSE,
5035 EL_EMC_WALL_11, -1, -1
5038 Xdecor_12, TRUE, FALSE,
5039 EL_EMC_WALL_12, -1, -1
5042 Xalpha_0, TRUE, FALSE,
5043 EL_CHAR('0'), -1, -1
5046 Xalpha_1, TRUE, FALSE,
5047 EL_CHAR('1'), -1, -1
5050 Xalpha_2, TRUE, FALSE,
5051 EL_CHAR('2'), -1, -1
5054 Xalpha_3, TRUE, FALSE,
5055 EL_CHAR('3'), -1, -1
5058 Xalpha_4, TRUE, FALSE,
5059 EL_CHAR('4'), -1, -1
5062 Xalpha_5, TRUE, FALSE,
5063 EL_CHAR('5'), -1, -1
5066 Xalpha_6, TRUE, FALSE,
5067 EL_CHAR('6'), -1, -1
5070 Xalpha_7, TRUE, FALSE,
5071 EL_CHAR('7'), -1, -1
5074 Xalpha_8, TRUE, FALSE,
5075 EL_CHAR('8'), -1, -1
5078 Xalpha_9, TRUE, FALSE,
5079 EL_CHAR('9'), -1, -1
5082 Xalpha_excla, TRUE, FALSE,
5083 EL_CHAR('!'), -1, -1
5086 Xalpha_quote, TRUE, FALSE,
5087 EL_CHAR('"'), -1, -1
5090 Xalpha_comma, TRUE, FALSE,
5091 EL_CHAR(','), -1, -1
5094 Xalpha_minus, TRUE, FALSE,
5095 EL_CHAR('-'), -1, -1
5098 Xalpha_perio, TRUE, FALSE,
5099 EL_CHAR('.'), -1, -1
5102 Xalpha_colon, TRUE, FALSE,
5103 EL_CHAR(':'), -1, -1
5106 Xalpha_quest, TRUE, FALSE,
5107 EL_CHAR('?'), -1, -1
5110 Xalpha_a, TRUE, FALSE,
5111 EL_CHAR('A'), -1, -1
5114 Xalpha_b, TRUE, FALSE,
5115 EL_CHAR('B'), -1, -1
5118 Xalpha_c, TRUE, FALSE,
5119 EL_CHAR('C'), -1, -1
5122 Xalpha_d, TRUE, FALSE,
5123 EL_CHAR('D'), -1, -1
5126 Xalpha_e, TRUE, FALSE,
5127 EL_CHAR('E'), -1, -1
5130 Xalpha_f, TRUE, FALSE,
5131 EL_CHAR('F'), -1, -1
5134 Xalpha_g, TRUE, FALSE,
5135 EL_CHAR('G'), -1, -1
5138 Xalpha_h, TRUE, FALSE,
5139 EL_CHAR('H'), -1, -1
5142 Xalpha_i, TRUE, FALSE,
5143 EL_CHAR('I'), -1, -1
5146 Xalpha_j, TRUE, FALSE,
5147 EL_CHAR('J'), -1, -1
5150 Xalpha_k, TRUE, FALSE,
5151 EL_CHAR('K'), -1, -1
5154 Xalpha_l, TRUE, FALSE,
5155 EL_CHAR('L'), -1, -1
5158 Xalpha_m, TRUE, FALSE,
5159 EL_CHAR('M'), -1, -1
5162 Xalpha_n, TRUE, FALSE,
5163 EL_CHAR('N'), -1, -1
5166 Xalpha_o, TRUE, FALSE,
5167 EL_CHAR('O'), -1, -1
5170 Xalpha_p, TRUE, FALSE,
5171 EL_CHAR('P'), -1, -1
5174 Xalpha_q, TRUE, FALSE,
5175 EL_CHAR('Q'), -1, -1
5178 Xalpha_r, TRUE, FALSE,
5179 EL_CHAR('R'), -1, -1
5182 Xalpha_s, TRUE, FALSE,
5183 EL_CHAR('S'), -1, -1
5186 Xalpha_t, TRUE, FALSE,
5187 EL_CHAR('T'), -1, -1
5190 Xalpha_u, TRUE, FALSE,
5191 EL_CHAR('U'), -1, -1
5194 Xalpha_v, TRUE, FALSE,
5195 EL_CHAR('V'), -1, -1
5198 Xalpha_w, TRUE, FALSE,
5199 EL_CHAR('W'), -1, -1
5202 Xalpha_x, TRUE, FALSE,
5203 EL_CHAR('X'), -1, -1
5206 Xalpha_y, TRUE, FALSE,
5207 EL_CHAR('Y'), -1, -1
5210 Xalpha_z, TRUE, FALSE,
5211 EL_CHAR('Z'), -1, -1
5214 Xalpha_arrow_e, TRUE, FALSE,
5215 EL_CHAR('>'), -1, -1
5218 Xalpha_arrow_w, TRUE, FALSE,
5219 EL_CHAR('<'), -1, -1
5222 Xalpha_copyr, TRUE, FALSE,
5223 EL_CHAR('©'), -1, -1
5227 Xboom_bug, FALSE, FALSE,
5228 EL_BUG, ACTION_EXPLODING, -1
5231 Xboom_bomb, FALSE, FALSE,
5232 EL_BOMB, ACTION_EXPLODING, -1
5235 Xboom_android, FALSE, FALSE,
5236 EL_EMC_ANDROID, ACTION_OTHER, -1
5239 Xboom_1, FALSE, FALSE,
5240 EL_DEFAULT, ACTION_EXPLODING, -1
5243 Xboom_2, FALSE, FALSE,
5244 EL_DEFAULT, ACTION_EXPLODING, -1
5247 Znormal, FALSE, FALSE,
5251 Zdynamite, FALSE, FALSE,
5255 Zplayer, FALSE, FALSE,
5259 ZBORDER, FALSE, FALSE,
5269 static struct Mapping_EM_to_RND_player
5278 em_player_mapping_list[] =
5282 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5286 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5290 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5294 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5298 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5302 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5306 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5310 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5314 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5318 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5322 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5326 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5330 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5334 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5338 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5342 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5346 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5350 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5354 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5358 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5362 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5366 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5370 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5374 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5378 EL_PLAYER_1, ACTION_DEFAULT, -1,
5382 EL_PLAYER_2, ACTION_DEFAULT, -1,
5386 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5390 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5394 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5398 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5402 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5406 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5410 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5414 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5418 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5422 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5426 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5430 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5434 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5438 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5442 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5446 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5450 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5454 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5458 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5462 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5466 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5470 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5474 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5478 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5482 EL_PLAYER_3, ACTION_DEFAULT, -1,
5486 EL_PLAYER_4, ACTION_DEFAULT, -1,
5495 int map_element_RND_to_EM(int element_rnd)
5497 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5498 static boolean mapping_initialized = FALSE;
5500 if (!mapping_initialized)
5504 /* return "Xalpha_quest" for all undefined elements in mapping array */
5505 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5506 mapping_RND_to_EM[i] = Xalpha_quest;
5508 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5509 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5510 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5511 em_object_mapping_list[i].element_em;
5513 mapping_initialized = TRUE;
5516 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5517 return mapping_RND_to_EM[element_rnd];
5519 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5524 int map_element_EM_to_RND(int element_em)
5526 static unsigned short mapping_EM_to_RND[TILE_MAX];
5527 static boolean mapping_initialized = FALSE;
5529 if (!mapping_initialized)
5533 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5534 for (i = 0; i < TILE_MAX; i++)
5535 mapping_EM_to_RND[i] = EL_UNKNOWN;
5537 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5538 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5539 em_object_mapping_list[i].element_rnd;
5541 mapping_initialized = TRUE;
5544 if (element_em >= 0 && element_em < TILE_MAX)
5545 return mapping_EM_to_RND[element_em];
5547 Error(ERR_WARN, "invalid EM level element %d", element_em);
5552 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5554 struct LevelInfo_EM *level_em = level->native_em_level;
5555 struct LEVEL *lev = level_em->lev;
5558 for (i = 0; i < TILE_MAX; i++)
5559 lev->android_array[i] = Xblank;
5561 for (i = 0; i < level->num_android_clone_elements; i++)
5563 int element_rnd = level->android_clone_element[i];
5564 int element_em = map_element_RND_to_EM(element_rnd);
5566 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5567 if (em_object_mapping_list[j].element_rnd == element_rnd)
5568 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5572 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5574 struct LevelInfo_EM *level_em = level->native_em_level;
5575 struct LEVEL *lev = level_em->lev;
5578 level->num_android_clone_elements = 0;
5580 for (i = 0; i < TILE_MAX; i++)
5582 int element_em = lev->android_array[i];
5584 boolean element_found = FALSE;
5586 if (element_em == Xblank)
5589 element_rnd = map_element_EM_to_RND(element_em);
5591 for (j = 0; j < level->num_android_clone_elements; j++)
5592 if (level->android_clone_element[j] == element_rnd)
5593 element_found = TRUE;
5597 level->android_clone_element[level->num_android_clone_elements++] =
5600 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5605 if (level->num_android_clone_elements == 0)
5607 level->num_android_clone_elements = 1;
5608 level->android_clone_element[0] = EL_EMPTY;
5612 int map_direction_RND_to_EM(int direction)
5614 return (direction == MV_UP ? 0 :
5615 direction == MV_RIGHT ? 1 :
5616 direction == MV_DOWN ? 2 :
5617 direction == MV_LEFT ? 3 :
5621 int map_direction_EM_to_RND(int direction)
5623 return (direction == 0 ? MV_UP :
5624 direction == 1 ? MV_RIGHT :
5625 direction == 2 ? MV_DOWN :
5626 direction == 3 ? MV_LEFT :
5630 int get_next_element(int element)
5634 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5635 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5636 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5637 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5638 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5639 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5640 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5641 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5642 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5643 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5644 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5646 default: return element;
5651 int el_act_dir2img(int element, int action, int direction)
5653 element = GFX_ELEMENT(element);
5655 if (direction == MV_NONE)
5656 return element_info[element].graphic[action];
5658 direction = MV_DIR_TO_BIT(direction);
5660 return element_info[element].direction_graphic[action][direction];
5663 int el_act_dir2img(int element, int action, int direction)
5665 element = GFX_ELEMENT(element);
5666 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5668 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5669 return element_info[element].direction_graphic[action][direction];
5674 static int el_act_dir2crm(int element, int action, int direction)
5676 element = GFX_ELEMENT(element);
5678 if (direction == MV_NONE)
5679 return element_info[element].crumbled[action];
5681 direction = MV_DIR_TO_BIT(direction);
5683 return element_info[element].direction_crumbled[action][direction];
5686 static int el_act_dir2crm(int element, int action, int direction)
5688 element = GFX_ELEMENT(element);
5689 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5691 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5692 return element_info[element].direction_crumbled[action][direction];
5696 int el_act2img(int element, int action)
5698 element = GFX_ELEMENT(element);
5700 return element_info[element].graphic[action];
5703 int el_act2crm(int element, int action)
5705 element = GFX_ELEMENT(element);
5707 return element_info[element].crumbled[action];
5710 int el_dir2img(int element, int direction)
5712 element = GFX_ELEMENT(element);
5714 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5717 int el2baseimg(int element)
5719 return element_info[element].graphic[ACTION_DEFAULT];
5722 int el2img(int element)
5724 element = GFX_ELEMENT(element);
5726 return element_info[element].graphic[ACTION_DEFAULT];
5729 int el2edimg(int element)
5731 element = GFX_ELEMENT(element);
5733 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5736 int el2preimg(int element)
5738 element = GFX_ELEMENT(element);
5740 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5743 int font2baseimg(int font_nr)
5745 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5748 int getBeltNrFromBeltElement(int element)
5750 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5751 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5752 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5755 int getBeltNrFromBeltActiveElement(int element)
5757 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5758 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5759 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5762 int getBeltNrFromBeltSwitchElement(int element)
5764 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5765 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5766 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5769 int getBeltDirNrFromBeltElement(int element)
5771 static int belt_base_element[4] =
5773 EL_CONVEYOR_BELT_1_LEFT,
5774 EL_CONVEYOR_BELT_2_LEFT,
5775 EL_CONVEYOR_BELT_3_LEFT,
5776 EL_CONVEYOR_BELT_4_LEFT
5779 int belt_nr = getBeltNrFromBeltElement(element);
5780 int belt_dir_nr = element - belt_base_element[belt_nr];
5782 return (belt_dir_nr % 3);
5785 int getBeltDirNrFromBeltSwitchElement(int element)
5787 static int belt_base_element[4] =
5789 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5790 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5791 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5792 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5795 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5796 int belt_dir_nr = element - belt_base_element[belt_nr];
5798 return (belt_dir_nr % 3);
5801 int getBeltDirFromBeltElement(int element)
5803 static int belt_move_dir[3] =
5810 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5812 return belt_move_dir[belt_dir_nr];
5815 int getBeltDirFromBeltSwitchElement(int element)
5817 static int belt_move_dir[3] =
5824 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5826 return belt_move_dir[belt_dir_nr];
5829 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5831 static int belt_base_element[4] =
5833 EL_CONVEYOR_BELT_1_LEFT,
5834 EL_CONVEYOR_BELT_2_LEFT,
5835 EL_CONVEYOR_BELT_3_LEFT,
5836 EL_CONVEYOR_BELT_4_LEFT
5838 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5840 return belt_base_element[belt_nr] + belt_dir_nr;
5843 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5845 static int belt_base_element[4] =
5847 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5848 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5849 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5850 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5852 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5854 return belt_base_element[belt_nr] + belt_dir_nr;
5857 int getNumActivePlayers_EM()
5859 int num_players = 0;
5865 for (i = 0; i < MAX_PLAYERS; i++)
5866 if (tape.player_participates[i])
5872 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5874 int game_frame_delay_value;
5876 game_frame_delay_value =
5877 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5878 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5881 if (tape.playing && tape.warp_forward && !tape.pausing)
5882 game_frame_delay_value = 0;
5884 return game_frame_delay_value;
5887 unsigned int InitRND(long seed)
5889 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5890 return InitEngineRandom_EM(seed);
5892 return InitEngineRandom_RND(seed);
5896 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5897 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5900 void ResetGfxAnimation_EM(int x, int y, int tile)
5905 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5906 Bitmap **src_bitmap, int *src_x, int *src_y,
5909 int element = object_mapping[tile].element_rnd;
5910 int action = object_mapping[tile].action;
5911 int direction = object_mapping[tile].direction;
5912 boolean is_backside = object_mapping[tile].is_backside;
5913 boolean action_removing = (action == ACTION_DIGGING ||
5914 action == ACTION_SNAPPING ||
5915 action == ACTION_COLLECTING);
5916 int effective_element = (frame_em > 0 ? element :
5917 is_backside ? EL_EMPTY :
5918 action_removing ? EL_EMPTY :
5920 int graphic = (direction == MV_NONE ?
5921 el_act2img(effective_element, action) :
5922 el_act_dir2img(effective_element, action, direction));
5923 struct GraphicInfo *g = &graphic_info[graphic];
5926 if (graphic_info[graphic].anim_global_sync)
5927 sync_frame = FrameCounter;
5929 sync_frame = 7 - frame_em;
5931 SetRandomAnimationValue(x, y);
5933 int frame = getAnimationFrame(g->anim_frames,
5936 g->anim_start_frame,
5939 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5942 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
5943 Bitmap **src_bitmap, int *src_x, int *src_y)
5945 int element = player_mapping[player_nr][anim].element_rnd;
5946 int action = player_mapping[player_nr][anim].action;
5947 int direction = player_mapping[player_nr][anim].direction;
5948 int graphic = (direction == MV_NONE ?
5949 el_act2img(element, action) :
5950 el_act_dir2img(element, action, direction));
5951 struct GraphicInfo *g = &graphic_info[graphic];
5954 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
5956 stored_player[player_nr].StepFrame = 7 - frame_em;
5958 sync_frame = stored_player[player_nr].Frame;
5961 printf("::: %d: %d, %d [%d]\n",
5963 stored_player[player_nr].Frame,
5964 stored_player[player_nr].StepFrame,
5968 int frame = getAnimationFrame(g->anim_frames,
5971 g->anim_start_frame,
5974 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5977 void InitGraphicInfo_EM(void)
5980 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5981 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5986 int num_em_gfx_errors = 0;
5988 if (graphic_info_em_object[0][0].bitmap == NULL)
5990 /* EM graphics not yet initialized in em_open_all() */
5995 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5998 /* always start with reliable default values */
5999 for (i = 0; i < TILE_MAX; i++)
6001 object_mapping[i].element_rnd = EL_UNKNOWN;
6002 object_mapping[i].is_backside = FALSE;
6003 object_mapping[i].action = ACTION_DEFAULT;
6004 object_mapping[i].direction = MV_NONE;
6007 /* always start with reliable default values */
6008 for (p = 0; p < MAX_PLAYERS; p++)
6010 for (i = 0; i < SPR_MAX; i++)
6012 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6013 player_mapping[p][i].action = ACTION_DEFAULT;
6014 player_mapping[p][i].direction = MV_NONE;
6018 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6020 int e = em_object_mapping_list[i].element_em;
6022 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6023 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6025 if (em_object_mapping_list[i].action != -1)
6026 object_mapping[e].action = em_object_mapping_list[i].action;
6028 if (em_object_mapping_list[i].direction != -1)
6029 object_mapping[e].direction =
6030 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6033 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6035 int a = em_player_mapping_list[i].action_em;
6036 int p = em_player_mapping_list[i].player_nr;
6038 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6040 if (em_player_mapping_list[i].action != -1)
6041 player_mapping[p][a].action = em_player_mapping_list[i].action;
6043 if (em_player_mapping_list[i].direction != -1)
6044 player_mapping[p][a].direction =
6045 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6048 for (i = 0; i < TILE_MAX; i++)
6050 int element = object_mapping[i].element_rnd;
6051 int action = object_mapping[i].action;
6052 int direction = object_mapping[i].direction;
6053 boolean is_backside = object_mapping[i].is_backside;
6054 boolean action_removing = (action == ACTION_DIGGING ||
6055 action == ACTION_SNAPPING ||
6056 action == ACTION_COLLECTING);
6057 boolean action_exploding = ((action == ACTION_EXPLODING ||
6058 action == ACTION_SMASHED_BY_ROCK ||
6059 action == ACTION_SMASHED_BY_SPRING) &&
6060 element != EL_DIAMOND);
6061 boolean action_active = (action == ACTION_ACTIVE);
6062 boolean action_other = (action == ACTION_OTHER);
6064 for (j = 0; j < 8; j++)
6066 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6067 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6069 i == Xdrip_stretch ? element :
6070 i == Xdrip_stretchB ? element :
6071 i == Ydrip_s1 ? element :
6072 i == Ydrip_s1B ? element :
6073 i == Xball_1B ? element :
6074 i == Xball_2 ? element :
6075 i == Xball_2B ? element :
6076 i == Yball_eat ? element :
6077 i == Ykey_1_eat ? element :
6078 i == Ykey_2_eat ? element :
6079 i == Ykey_3_eat ? element :
6080 i == Ykey_4_eat ? element :
6081 i == Ykey_5_eat ? element :
6082 i == Ykey_6_eat ? element :
6083 i == Ykey_7_eat ? element :
6084 i == Ykey_8_eat ? element :
6085 i == Ylenses_eat ? element :
6086 i == Ymagnify_eat ? element :
6087 i == Ygrass_eat ? element :
6088 i == Ydirt_eat ? element :
6089 i == Yemerald_stone ? EL_EMERALD :
6090 i == Ydiamond_stone ? EL_ROCK :
6091 i == Xsand_stonein_1 ? element :
6092 i == Xsand_stonein_2 ? element :
6093 i == Xsand_stonein_3 ? element :
6094 i == Xsand_stonein_4 ? element :
6095 is_backside ? EL_EMPTY :
6096 action_removing ? EL_EMPTY :
6098 int effective_action = (j < 7 ? action :
6099 i == Xdrip_stretch ? action :
6100 i == Xdrip_stretchB ? action :
6101 i == Ydrip_s1 ? action :
6102 i == Ydrip_s1B ? action :
6103 i == Xball_1B ? action :
6104 i == Xball_2 ? action :
6105 i == Xball_2B ? action :
6106 i == Yball_eat ? action :
6107 i == Ykey_1_eat ? action :
6108 i == Ykey_2_eat ? action :
6109 i == Ykey_3_eat ? action :
6110 i == Ykey_4_eat ? action :
6111 i == Ykey_5_eat ? action :
6112 i == Ykey_6_eat ? action :
6113 i == Ykey_7_eat ? action :
6114 i == Ykey_8_eat ? action :
6115 i == Ylenses_eat ? action :
6116 i == Ymagnify_eat ? action :
6117 i == Ygrass_eat ? action :
6118 i == Ydirt_eat ? action :
6119 i == Xsand_stonein_1 ? action :
6120 i == Xsand_stonein_2 ? action :
6121 i == Xsand_stonein_3 ? action :
6122 i == Xsand_stonein_4 ? action :
6123 i == Xsand_stoneout_1 ? action :
6124 i == Xsand_stoneout_2 ? action :
6125 i == Xboom_android ? ACTION_EXPLODING :
6126 action_exploding ? ACTION_EXPLODING :
6127 action_active ? action :
6128 action_other ? action :
6130 int graphic = (el_act_dir2img(effective_element, effective_action,
6132 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6134 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6135 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6136 boolean has_action_graphics = (graphic != base_graphic);
6137 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6138 struct GraphicInfo *g = &graphic_info[graphic];
6139 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6142 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6143 boolean special_animation = (action != ACTION_DEFAULT &&
6144 g->anim_frames == 3 &&
6145 g->anim_delay == 2 &&
6146 g->anim_mode & ANIM_LINEAR);
6147 int sync_frame = (i == Xdrip_stretch ? 7 :
6148 i == Xdrip_stretchB ? 7 :
6149 i == Ydrip_s2 ? j + 8 :
6150 i == Ydrip_s2B ? j + 8 :
6159 i == Xfake_acid_1 ? 0 :
6160 i == Xfake_acid_2 ? 10 :
6161 i == Xfake_acid_3 ? 20 :
6162 i == Xfake_acid_4 ? 30 :
6163 i == Xfake_acid_5 ? 40 :
6164 i == Xfake_acid_6 ? 50 :
6165 i == Xfake_acid_7 ? 60 :
6166 i == Xfake_acid_8 ? 70 :
6168 i == Xball_2B ? j + 8 :
6169 i == Yball_eat ? j + 1 :
6170 i == Ykey_1_eat ? j + 1 :
6171 i == Ykey_2_eat ? j + 1 :
6172 i == Ykey_3_eat ? j + 1 :
6173 i == Ykey_4_eat ? j + 1 :
6174 i == Ykey_5_eat ? j + 1 :
6175 i == Ykey_6_eat ? j + 1 :
6176 i == Ykey_7_eat ? j + 1 :
6177 i == Ykey_8_eat ? j + 1 :
6178 i == Ylenses_eat ? j + 1 :
6179 i == Ymagnify_eat ? j + 1 :
6180 i == Ygrass_eat ? j + 1 :
6181 i == Ydirt_eat ? j + 1 :
6182 i == Xamoeba_1 ? 0 :
6183 i == Xamoeba_2 ? 1 :
6184 i == Xamoeba_3 ? 2 :
6185 i == Xamoeba_4 ? 3 :
6186 i == Xamoeba_5 ? 0 :
6187 i == Xamoeba_6 ? 1 :
6188 i == Xamoeba_7 ? 2 :
6189 i == Xamoeba_8 ? 3 :
6190 i == Xexit_2 ? j + 8 :
6191 i == Xexit_3 ? j + 16 :
6192 i == Xdynamite_1 ? 0 :
6193 i == Xdynamite_2 ? 8 :
6194 i == Xdynamite_3 ? 16 :
6195 i == Xdynamite_4 ? 24 :
6196 i == Xsand_stonein_1 ? j + 1 :
6197 i == Xsand_stonein_2 ? j + 9 :
6198 i == Xsand_stonein_3 ? j + 17 :
6199 i == Xsand_stonein_4 ? j + 25 :
6200 i == Xsand_stoneout_1 && j == 0 ? 0 :
6201 i == Xsand_stoneout_1 && j == 1 ? 0 :
6202 i == Xsand_stoneout_1 && j == 2 ? 1 :
6203 i == Xsand_stoneout_1 && j == 3 ? 2 :
6204 i == Xsand_stoneout_1 && j == 4 ? 2 :
6205 i == Xsand_stoneout_1 && j == 5 ? 3 :
6206 i == Xsand_stoneout_1 && j == 6 ? 4 :
6207 i == Xsand_stoneout_1 && j == 7 ? 4 :
6208 i == Xsand_stoneout_2 && j == 0 ? 5 :
6209 i == Xsand_stoneout_2 && j == 1 ? 6 :
6210 i == Xsand_stoneout_2 && j == 2 ? 7 :
6211 i == Xsand_stoneout_2 && j == 3 ? 8 :
6212 i == Xsand_stoneout_2 && j == 4 ? 9 :
6213 i == Xsand_stoneout_2 && j == 5 ? 11 :
6214 i == Xsand_stoneout_2 && j == 6 ? 13 :
6215 i == Xsand_stoneout_2 && j == 7 ? 15 :
6216 i == Xboom_bug && j == 1 ? 2 :
6217 i == Xboom_bug && j == 2 ? 2 :
6218 i == Xboom_bug && j == 3 ? 4 :
6219 i == Xboom_bug && j == 4 ? 4 :
6220 i == Xboom_bug && j == 5 ? 2 :
6221 i == Xboom_bug && j == 6 ? 2 :
6222 i == Xboom_bug && j == 7 ? 0 :
6223 i == Xboom_bomb && j == 1 ? 2 :
6224 i == Xboom_bomb && j == 2 ? 2 :
6225 i == Xboom_bomb && j == 3 ? 4 :
6226 i == Xboom_bomb && j == 4 ? 4 :
6227 i == Xboom_bomb && j == 5 ? 2 :
6228 i == Xboom_bomb && j == 6 ? 2 :
6229 i == Xboom_bomb && j == 7 ? 0 :
6230 i == Xboom_android && j == 7 ? 6 :
6231 i == Xboom_1 && j == 1 ? 2 :
6232 i == Xboom_1 && j == 2 ? 2 :
6233 i == Xboom_1 && j == 3 ? 4 :
6234 i == Xboom_1 && j == 4 ? 4 :
6235 i == Xboom_1 && j == 5 ? 6 :
6236 i == Xboom_1 && j == 6 ? 6 :
6237 i == Xboom_1 && j == 7 ? 8 :
6238 i == Xboom_2 && j == 0 ? 8 :
6239 i == Xboom_2 && j == 1 ? 8 :
6240 i == Xboom_2 && j == 2 ? 10 :
6241 i == Xboom_2 && j == 3 ? 10 :
6242 i == Xboom_2 && j == 4 ? 10 :
6243 i == Xboom_2 && j == 5 ? 12 :
6244 i == Xboom_2 && j == 6 ? 12 :
6245 i == Xboom_2 && j == 7 ? 12 :
6246 special_animation && j == 4 ? 3 :
6247 effective_action != action ? 0 :
6251 Bitmap *debug_bitmap = g_em->bitmap;
6252 int debug_src_x = g_em->src_x;
6253 int debug_src_y = g_em->src_y;
6256 int frame = getAnimationFrame(g->anim_frames,
6259 g->anim_start_frame,
6262 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6263 g->double_movement && is_backside);
6265 g_em->bitmap = src_bitmap;
6266 g_em->src_x = src_x;
6267 g_em->src_y = src_y;
6268 g_em->src_offset_x = 0;
6269 g_em->src_offset_y = 0;
6270 g_em->dst_offset_x = 0;
6271 g_em->dst_offset_y = 0;
6272 g_em->width = TILEX;
6273 g_em->height = TILEY;
6275 g_em->crumbled_bitmap = NULL;
6276 g_em->crumbled_src_x = 0;
6277 g_em->crumbled_src_y = 0;
6278 g_em->crumbled_border_size = 0;
6280 g_em->has_crumbled_graphics = FALSE;
6281 g_em->preserve_background = FALSE;
6284 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6285 printf("::: empty crumbled: %d [%s], %d, %d\n",
6286 effective_element, element_info[effective_element].token_name,
6287 effective_action, direction);
6290 /* if element can be crumbled, but certain action graphics are just empty
6291 space (like snapping sand with the original R'n'D graphics), do not
6292 treat these empty space graphics as crumbled graphics in EMC engine */
6293 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6295 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6297 g_em->has_crumbled_graphics = TRUE;
6298 g_em->crumbled_bitmap = src_bitmap;
6299 g_em->crumbled_src_x = src_x;
6300 g_em->crumbled_src_y = src_y;
6301 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6305 if (element == EL_ROCK &&
6306 effective_action == ACTION_FILLING)
6307 printf("::: has_action_graphics == %d\n", has_action_graphics);
6310 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6311 effective_action == ACTION_MOVING ||
6312 effective_action == ACTION_PUSHING ||
6313 effective_action == ACTION_EATING)) ||
6314 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6315 effective_action == ACTION_EMPTYING)))
6318 (effective_action == ACTION_FALLING ||
6319 effective_action == ACTION_FILLING ||
6320 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6321 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6322 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6323 int num_steps = (i == Ydrip_s1 ? 16 :
6324 i == Ydrip_s1B ? 16 :
6325 i == Ydrip_s2 ? 16 :
6326 i == Ydrip_s2B ? 16 :
6327 i == Xsand_stonein_1 ? 32 :
6328 i == Xsand_stonein_2 ? 32 :
6329 i == Xsand_stonein_3 ? 32 :
6330 i == Xsand_stonein_4 ? 32 :
6331 i == Xsand_stoneout_1 ? 16 :
6332 i == Xsand_stoneout_2 ? 16 : 8);
6333 int cx = ABS(dx) * (TILEX / num_steps);
6334 int cy = ABS(dy) * (TILEY / num_steps);
6335 int step_frame = (i == Ydrip_s2 ? j + 8 :
6336 i == Ydrip_s2B ? j + 8 :
6337 i == Xsand_stonein_2 ? j + 8 :
6338 i == Xsand_stonein_3 ? j + 16 :
6339 i == Xsand_stonein_4 ? j + 24 :
6340 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6341 int step = (is_backside ? step_frame : num_steps - step_frame);
6343 if (is_backside) /* tile where movement starts */
6345 if (dx < 0 || dy < 0)
6347 g_em->src_offset_x = cx * step;
6348 g_em->src_offset_y = cy * step;
6352 g_em->dst_offset_x = cx * step;
6353 g_em->dst_offset_y = cy * step;
6356 else /* tile where movement ends */
6358 if (dx < 0 || dy < 0)
6360 g_em->dst_offset_x = cx * step;
6361 g_em->dst_offset_y = cy * step;
6365 g_em->src_offset_x = cx * step;
6366 g_em->src_offset_y = cy * step;
6370 g_em->width = TILEX - cx * step;
6371 g_em->height = TILEY - cy * step;
6374 /* create unique graphic identifier to decide if tile must be redrawn */
6375 /* bit 31 - 16 (16 bit): EM style graphic
6376 bit 15 - 12 ( 4 bit): EM style frame
6377 bit 11 - 6 ( 6 bit): graphic width
6378 bit 5 - 0 ( 6 bit): graphic height */
6379 g_em->unique_identifier =
6380 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6384 /* skip check for EMC elements not contained in original EMC artwork */
6385 if (element == EL_EMC_FAKE_ACID)
6388 if (g_em->bitmap != debug_bitmap ||
6389 g_em->src_x != debug_src_x ||
6390 g_em->src_y != debug_src_y ||
6391 g_em->src_offset_x != 0 ||
6392 g_em->src_offset_y != 0 ||
6393 g_em->dst_offset_x != 0 ||
6394 g_em->dst_offset_y != 0 ||
6395 g_em->width != TILEX ||
6396 g_em->height != TILEY)
6398 static int last_i = -1;
6406 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6407 i, element, element_info[element].token_name,
6408 element_action_info[effective_action].suffix, direction);
6410 if (element != effective_element)
6411 printf(" [%d ('%s')]",
6413 element_info[effective_element].token_name);
6417 if (g_em->bitmap != debug_bitmap)
6418 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6419 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6421 if (g_em->src_x != debug_src_x ||
6422 g_em->src_y != debug_src_y)
6423 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6424 j, (is_backside ? 'B' : 'F'),
6425 g_em->src_x, g_em->src_y,
6426 g_em->src_x / 32, g_em->src_y / 32,
6427 debug_src_x, debug_src_y,
6428 debug_src_x / 32, debug_src_y / 32);
6430 if (g_em->src_offset_x != 0 ||
6431 g_em->src_offset_y != 0 ||
6432 g_em->dst_offset_x != 0 ||
6433 g_em->dst_offset_y != 0)
6434 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6436 g_em->src_offset_x, g_em->src_offset_y,
6437 g_em->dst_offset_x, g_em->dst_offset_y);
6439 if (g_em->width != TILEX ||
6440 g_em->height != TILEY)
6441 printf(" %d (%d): size %d,%d should be %d,%d\n",
6443 g_em->width, g_em->height, TILEX, TILEY);
6445 num_em_gfx_errors++;
6452 for (i = 0; i < TILE_MAX; i++)
6454 for (j = 0; j < 8; j++)
6456 int element = object_mapping[i].element_rnd;
6457 int action = object_mapping[i].action;
6458 int direction = object_mapping[i].direction;
6459 boolean is_backside = object_mapping[i].is_backside;
6460 int graphic_action = el_act_dir2img(element, action, direction);
6461 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6463 if ((action == ACTION_SMASHED_BY_ROCK ||
6464 action == ACTION_SMASHED_BY_SPRING ||
6465 action == ACTION_EATING) &&
6466 graphic_action == graphic_default)
6468 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6469 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6470 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6471 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6474 /* no separate animation for "smashed by rock" -- use rock instead */
6475 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6476 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6478 g_em->bitmap = g_xx->bitmap;
6479 g_em->src_x = g_xx->src_x;
6480 g_em->src_y = g_xx->src_y;
6481 g_em->src_offset_x = g_xx->src_offset_x;
6482 g_em->src_offset_y = g_xx->src_offset_y;
6483 g_em->dst_offset_x = g_xx->dst_offset_x;
6484 g_em->dst_offset_y = g_xx->dst_offset_y;
6485 g_em->width = g_xx->width;
6486 g_em->height = g_xx->height;
6487 g_em->unique_identifier = g_xx->unique_identifier;
6490 g_em->preserve_background = TRUE;
6495 for (p = 0; p < MAX_PLAYERS; p++)
6497 for (i = 0; i < SPR_MAX; i++)
6499 int element = player_mapping[p][i].element_rnd;
6500 int action = player_mapping[p][i].action;
6501 int direction = player_mapping[p][i].direction;
6503 for (j = 0; j < 8; j++)
6505 int effective_element = element;
6506 int effective_action = action;
6507 int graphic = (direction == MV_NONE ?
6508 el_act2img(effective_element, effective_action) :
6509 el_act_dir2img(effective_element, effective_action,
6511 struct GraphicInfo *g = &graphic_info[graphic];
6512 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6518 Bitmap *debug_bitmap = g_em->bitmap;
6519 int debug_src_x = g_em->src_x;
6520 int debug_src_y = g_em->src_y;
6523 int frame = getAnimationFrame(g->anim_frames,
6526 g->anim_start_frame,
6529 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6531 g_em->bitmap = src_bitmap;
6532 g_em->src_x = src_x;
6533 g_em->src_y = src_y;
6534 g_em->src_offset_x = 0;
6535 g_em->src_offset_y = 0;
6536 g_em->dst_offset_x = 0;
6537 g_em->dst_offset_y = 0;
6538 g_em->width = TILEX;
6539 g_em->height = TILEY;
6543 /* skip check for EMC elements not contained in original EMC artwork */
6544 if (element == EL_PLAYER_3 ||
6545 element == EL_PLAYER_4)
6548 if (g_em->bitmap != debug_bitmap ||
6549 g_em->src_x != debug_src_x ||
6550 g_em->src_y != debug_src_y)
6552 static int last_i = -1;
6560 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6561 p, i, element, element_info[element].token_name,
6562 element_action_info[effective_action].suffix, direction);
6564 if (element != effective_element)
6565 printf(" [%d ('%s')]",
6567 element_info[effective_element].token_name);
6571 if (g_em->bitmap != debug_bitmap)
6572 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6573 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6575 if (g_em->src_x != debug_src_x ||
6576 g_em->src_y != debug_src_y)
6577 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6579 g_em->src_x, g_em->src_y,
6580 g_em->src_x / 32, g_em->src_y / 32,
6581 debug_src_x, debug_src_y,
6582 debug_src_x / 32, debug_src_y / 32);
6584 num_em_gfx_errors++;
6594 printf("::: [%d errors found]\n", num_em_gfx_errors);
6600 void PlayMenuSoundExt(int sound)
6602 if (sound == SND_UNDEFINED)
6605 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6606 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6609 if (IS_LOOP_SOUND(sound))
6610 PlaySoundLoop(sound);
6615 void PlayMenuSound()
6617 PlayMenuSoundExt(menu.sound[game_status]);
6620 void PlayMenuSoundStereo(int sound, int stereo_position)
6622 if (sound == SND_UNDEFINED)
6625 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6626 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6629 if (IS_LOOP_SOUND(sound))
6630 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6632 PlaySoundStereo(sound, stereo_position);
6635 void PlayMenuSoundIfLoopExt(int sound)
6637 if (sound == SND_UNDEFINED)
6640 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6641 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6644 if (IS_LOOP_SOUND(sound))
6645 PlaySoundLoop(sound);
6648 void PlayMenuSoundIfLoop()
6650 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6653 void PlayMenuMusicExt(int music)
6655 if (music == MUS_UNDEFINED)
6658 if (!setup.sound_music)
6664 void PlayMenuMusic()
6666 PlayMenuMusicExt(menu.music[game_status]);
6669 void PlaySoundActivating()
6672 PlaySound(SND_MENU_ITEM_ACTIVATING);
6676 void PlaySoundSelecting()
6679 PlaySound(SND_MENU_ITEM_SELECTING);
6683 void ToggleFullscreenIfNeeded()
6685 boolean change_fullscreen = (setup.fullscreen !=
6686 video.fullscreen_enabled);
6687 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6688 !strEqual(setup.fullscreen_mode,
6689 video.fullscreen_mode_current));
6691 if (!video.fullscreen_available)
6695 if (change_fullscreen || change_fullscreen_mode)
6697 if (setup.fullscreen != video.fullscreen_enabled ||
6698 setup.fullscreen_mode != video.fullscreen_mode_current)
6701 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6703 /* save backbuffer content which gets lost when toggling fullscreen mode */
6704 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6707 if (change_fullscreen_mode)
6709 if (setup.fullscreen && video.fullscreen_enabled)
6712 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6714 /* (this is now set in sdl.c) */
6716 video.fullscreen_mode_current = setup.fullscreen_mode;
6718 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6721 /* toggle fullscreen */
6722 ChangeVideoModeIfNeeded(setup.fullscreen);
6724 setup.fullscreen = video.fullscreen_enabled;
6726 /* restore backbuffer content from temporary backbuffer backup bitmap */
6727 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6729 FreeBitmap(tmp_backbuffer);
6732 /* update visible window/screen */
6733 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6735 redraw_mask = REDRAW_ALL;