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))
2942 if (req_state & REQ_CONFIRM)
2958 if (req_state & REQ_PLAYER)
2962 case EVENT_KEYRELEASE:
2963 ClearPlayerAction();
2967 HandleOtherEvents(&event);
2971 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2973 int joy = AnyJoystick();
2975 if (joy & JOY_BUTTON_1)
2977 else if (joy & JOY_BUTTON_2)
2983 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2985 HandleGameActions();
2992 if (!PendingEvent()) /* delay only if no pending events */
3001 if (!PendingEvent()) /* delay only if no pending events */
3004 /* don't eat all CPU time */
3011 if (game_status != GAME_MODE_MAIN)
3016 if (!(req_state & REQ_STAY_OPEN))
3018 CloseDoor(DOOR_CLOSE_1);
3020 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3021 (req_state & REQ_REOPEN))
3022 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3027 if (game_status == GAME_MODE_PLAYING)
3029 SetPanelBackground();
3030 SetDrawBackgroundMask(REDRAW_DOOR_1);
3034 SetDrawBackgroundMask(REDRAW_FIELD);
3037 #if defined(NETWORK_AVALIABLE)
3038 /* continue network game after request */
3039 if (options.network &&
3040 game_status == GAME_MODE_PLAYING &&
3041 req_state & REQUEST_WAIT_FOR_INPUT)
3042 SendToServer_ContinuePlaying();
3045 /* restore deactivated drawing when quick-loading level tape recording */
3046 if (tape.playing && tape.deactivate_display)
3047 TapeDeactivateDisplayOn();
3052 unsigned int OpenDoor(unsigned int door_state)
3054 if (door_state & DOOR_COPY_BACK)
3056 if (door_state & DOOR_OPEN_1)
3057 BlitBitmap(bitmap_db_door, bitmap_db_door,
3058 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3059 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3061 if (door_state & DOOR_OPEN_2)
3062 BlitBitmap(bitmap_db_door, bitmap_db_door,
3063 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3064 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3066 door_state &= ~DOOR_COPY_BACK;
3069 return MoveDoor(door_state);
3072 unsigned int CloseDoor(unsigned int door_state)
3074 unsigned int old_door_state = GetDoorState();
3076 if (!(door_state & DOOR_NO_COPY_BACK))
3078 if (old_door_state & DOOR_OPEN_1)
3079 BlitBitmap(backbuffer, bitmap_db_door,
3080 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3082 if (old_door_state & DOOR_OPEN_2)
3083 BlitBitmap(backbuffer, bitmap_db_door,
3084 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3086 door_state &= ~DOOR_NO_COPY_BACK;
3089 return MoveDoor(door_state);
3092 unsigned int GetDoorState()
3094 return MoveDoor(DOOR_GET_STATE);
3097 unsigned int SetDoorState(unsigned int door_state)
3099 return MoveDoor(door_state | DOOR_SET_STATE);
3102 unsigned int MoveDoor(unsigned int door_state)
3104 static int door1 = DOOR_OPEN_1;
3105 static int door2 = DOOR_CLOSE_2;
3106 unsigned long door_delay = 0;
3107 unsigned long door_delay_value;
3110 if (door_1.width < 0 || door_1.width > DXSIZE)
3111 door_1.width = DXSIZE;
3112 if (door_1.height < 0 || door_1.height > DYSIZE)
3113 door_1.height = DYSIZE;
3114 if (door_2.width < 0 || door_2.width > VXSIZE)
3115 door_2.width = VXSIZE;
3116 if (door_2.height < 0 || door_2.height > VYSIZE)
3117 door_2.height = VYSIZE;
3119 if (door_state == DOOR_GET_STATE)
3120 return (door1 | door2);
3122 if (door_state & DOOR_SET_STATE)
3124 if (door_state & DOOR_ACTION_1)
3125 door1 = door_state & DOOR_ACTION_1;
3126 if (door_state & DOOR_ACTION_2)
3127 door2 = door_state & DOOR_ACTION_2;
3129 return (door1 | door2);
3132 if (!(door_state & DOOR_FORCE_REDRAW))
3134 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3135 door_state &= ~DOOR_OPEN_1;
3136 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3137 door_state &= ~DOOR_CLOSE_1;
3138 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3139 door_state &= ~DOOR_OPEN_2;
3140 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3141 door_state &= ~DOOR_CLOSE_2;
3144 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3147 if (setup.quick_doors)
3149 stepsize = 20; /* must be chosen to always draw last frame */
3150 door_delay_value = 0;
3153 if (global.autoplay_leveldir)
3155 door_state |= DOOR_NO_DELAY;
3156 door_state &= ~DOOR_CLOSE_ALL;
3159 if (door_state & DOOR_ACTION)
3161 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3162 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3163 boolean door_1_done = (!handle_door_1);
3164 boolean door_2_done = (!handle_door_2);
3165 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3166 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3167 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3168 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3169 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3170 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3171 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3172 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3173 int door_skip = max_door_size - door_size;
3174 int end = door_size;
3175 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3178 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3180 /* opening door sound has priority over simultaneously closing door */
3181 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3182 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3183 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3184 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3187 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3190 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3191 GC gc = bitmap->stored_clip_gc;
3193 if (door_state & DOOR_ACTION_1)
3195 int a = MIN(x * door_1.step_offset, end);
3196 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3197 int i = p + door_skip;
3199 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3201 BlitBitmap(bitmap_db_door, drawto,
3202 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3203 DXSIZE, DYSIZE, DX, DY);
3207 BlitBitmap(bitmap_db_door, drawto,
3208 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3209 DXSIZE, DYSIZE - p / 2, DX, DY);
3211 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3214 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3216 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3217 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3218 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3219 int dst2_x = DX, dst2_y = DY;
3220 int width = i, height = DYSIZE;
3222 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3223 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3226 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3227 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3230 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3232 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3233 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3234 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3235 int dst2_x = DX, dst2_y = DY;
3236 int width = DXSIZE, height = i;
3238 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3239 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3242 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3243 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3246 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3248 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3250 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3251 BlitBitmapMasked(bitmap, drawto,
3252 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3253 DX + DXSIZE - i, DY + j);
3254 BlitBitmapMasked(bitmap, drawto,
3255 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3256 DX + DXSIZE - i, DY + 140 + j);
3257 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3258 DY - (DOOR_GFX_PAGEY1 + j));
3259 BlitBitmapMasked(bitmap, drawto,
3260 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3262 BlitBitmapMasked(bitmap, drawto,
3263 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3266 BlitBitmapMasked(bitmap, drawto,
3267 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3269 BlitBitmapMasked(bitmap, drawto,
3270 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3272 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3273 BlitBitmapMasked(bitmap, drawto,
3274 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3275 DX + DXSIZE - i, DY + 77 + j);
3276 BlitBitmapMasked(bitmap, drawto,
3277 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3278 DX + DXSIZE - i, DY + 203 + j);
3281 redraw_mask |= REDRAW_DOOR_1;
3282 door_1_done = (a == end);
3285 if (door_state & DOOR_ACTION_2)
3287 int a = MIN(x * door_2.step_offset, door_size);
3288 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3289 int i = p + door_skip;
3291 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3293 BlitBitmap(bitmap_db_door, drawto,
3294 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3295 VXSIZE, VYSIZE, VX, VY);
3297 else if (x <= VYSIZE)
3299 BlitBitmap(bitmap_db_door, drawto,
3300 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3301 VXSIZE, VYSIZE - p / 2, VX, VY);
3303 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3306 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3308 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3309 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3310 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3311 int dst2_x = VX, dst2_y = VY;
3312 int width = i, height = VYSIZE;
3314 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3315 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3318 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3319 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3322 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3324 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3325 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3326 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3327 int dst2_x = VX, dst2_y = VY;
3328 int width = VXSIZE, height = i;
3330 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3331 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3334 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3335 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3338 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3340 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3342 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3343 BlitBitmapMasked(bitmap, drawto,
3344 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3345 VX + VXSIZE - i, VY + j);
3346 SetClipOrigin(bitmap, gc,
3347 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3348 BlitBitmapMasked(bitmap, drawto,
3349 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3352 BlitBitmapMasked(bitmap, drawto,
3353 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3354 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3355 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3356 BlitBitmapMasked(bitmap, drawto,
3357 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3359 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3362 redraw_mask |= REDRAW_DOOR_2;
3363 door_2_done = (a == VXSIZE);
3366 if (!(door_state & DOOR_NO_DELAY))
3370 if (game_status == GAME_MODE_MAIN)
3373 WaitUntilDelayReached(&door_delay, door_delay_value);
3378 if (door_state & DOOR_ACTION_1)
3379 door1 = door_state & DOOR_ACTION_1;
3380 if (door_state & DOOR_ACTION_2)
3381 door2 = door_state & DOOR_ACTION_2;
3383 return (door1 | door2);
3386 void DrawSpecialEditorDoor()
3388 /* draw bigger toolbox window */
3389 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3390 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3392 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3393 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3396 redraw_mask |= REDRAW_ALL;
3399 void UndrawSpecialEditorDoor()
3401 /* draw normal tape recorder window */
3402 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3403 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3406 redraw_mask |= REDRAW_ALL;
3410 /* ---------- new tool button stuff ---------------------------------------- */
3412 /* graphic position values for tool buttons */
3413 #define TOOL_BUTTON_YES_XPOS 2
3414 #define TOOL_BUTTON_YES_YPOS 250
3415 #define TOOL_BUTTON_YES_GFX_YPOS 0
3416 #define TOOL_BUTTON_YES_XSIZE 46
3417 #define TOOL_BUTTON_YES_YSIZE 28
3418 #define TOOL_BUTTON_NO_XPOS 52
3419 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3420 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3421 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3422 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3423 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3424 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3425 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3426 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3427 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3428 #define TOOL_BUTTON_PLAYER_XSIZE 30
3429 #define TOOL_BUTTON_PLAYER_YSIZE 30
3430 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3431 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3432 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3433 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3434 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3435 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3436 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3437 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3438 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3439 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3440 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3441 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3442 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3443 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3444 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3445 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3446 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3447 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3448 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3449 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3458 } toolbutton_info[NUM_TOOL_BUTTONS] =
3461 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3462 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3463 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3468 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3469 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3470 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3475 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3476 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3477 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3478 TOOL_CTRL_ID_CONFIRM,
3482 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3483 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3484 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3485 TOOL_CTRL_ID_PLAYER_1,
3489 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3490 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3491 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3492 TOOL_CTRL_ID_PLAYER_2,
3496 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3497 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3498 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3499 TOOL_CTRL_ID_PLAYER_3,
3503 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3504 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3505 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3506 TOOL_CTRL_ID_PLAYER_4,
3511 void CreateToolButtons()
3515 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3517 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3518 Bitmap *deco_bitmap = None;
3519 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3520 struct GadgetInfo *gi;
3521 unsigned long event_mask;
3522 int gd_xoffset, gd_yoffset;
3523 int gd_x1, gd_x2, gd_y;
3526 event_mask = GD_EVENT_RELEASED;
3528 gd_xoffset = toolbutton_info[i].xpos;
3529 gd_yoffset = toolbutton_info[i].ypos;
3530 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3531 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3532 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3534 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3536 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3538 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3539 &deco_bitmap, &deco_x, &deco_y);
3540 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3541 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3544 gi = CreateGadget(GDI_CUSTOM_ID, id,
3545 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3546 GDI_X, DX + toolbutton_info[i].x,
3547 GDI_Y, DY + toolbutton_info[i].y,
3548 GDI_WIDTH, toolbutton_info[i].width,
3549 GDI_HEIGHT, toolbutton_info[i].height,
3550 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3551 GDI_STATE, GD_BUTTON_UNPRESSED,
3552 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3553 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3554 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3555 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3556 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3557 GDI_DECORATION_SHIFTING, 1, 1,
3558 GDI_DIRECT_DRAW, FALSE,
3559 GDI_EVENT_MASK, event_mask,
3560 GDI_CALLBACK_ACTION, HandleToolButtons,
3564 Error(ERR_EXIT, "cannot create gadget");
3566 tool_gadget[id] = gi;
3570 void FreeToolButtons()
3574 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3575 FreeGadget(tool_gadget[i]);
3578 static void UnmapToolButtons()
3582 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3583 UnmapGadget(tool_gadget[i]);
3586 static void HandleToolButtons(struct GadgetInfo *gi)
3588 request_gadget_id = gi->custom_id;
3591 static struct Mapping_EM_to_RND_object
3594 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3595 boolean is_backside; /* backside of moving element */
3601 em_object_mapping_list[] =
3604 Xblank, TRUE, FALSE,
3608 Yacid_splash_eB, FALSE, FALSE,
3609 EL_ACID_SPLASH_RIGHT, -1, -1
3612 Yacid_splash_wB, FALSE, FALSE,
3613 EL_ACID_SPLASH_LEFT, -1, -1
3616 #ifdef EM_ENGINE_BAD_ROLL
3618 Xstone_force_e, FALSE, FALSE,
3619 EL_ROCK, -1, MV_BIT_RIGHT
3622 Xstone_force_w, FALSE, FALSE,
3623 EL_ROCK, -1, MV_BIT_LEFT
3626 Xnut_force_e, FALSE, FALSE,
3627 EL_NUT, -1, MV_BIT_RIGHT
3630 Xnut_force_w, FALSE, FALSE,
3631 EL_NUT, -1, MV_BIT_LEFT
3634 Xspring_force_e, FALSE, FALSE,
3635 EL_SPRING, -1, MV_BIT_RIGHT
3638 Xspring_force_w, FALSE, FALSE,
3639 EL_SPRING, -1, MV_BIT_LEFT
3642 Xemerald_force_e, FALSE, FALSE,
3643 EL_EMERALD, -1, MV_BIT_RIGHT
3646 Xemerald_force_w, FALSE, FALSE,
3647 EL_EMERALD, -1, MV_BIT_LEFT
3650 Xdiamond_force_e, FALSE, FALSE,
3651 EL_DIAMOND, -1, MV_BIT_RIGHT
3654 Xdiamond_force_w, FALSE, FALSE,
3655 EL_DIAMOND, -1, MV_BIT_LEFT
3658 Xbomb_force_e, FALSE, FALSE,
3659 EL_BOMB, -1, MV_BIT_RIGHT
3662 Xbomb_force_w, FALSE, FALSE,
3663 EL_BOMB, -1, MV_BIT_LEFT
3665 #endif /* EM_ENGINE_BAD_ROLL */
3668 Xstone, TRUE, FALSE,
3672 Xstone_pause, FALSE, FALSE,
3676 Xstone_fall, FALSE, FALSE,
3680 Ystone_s, FALSE, FALSE,
3681 EL_ROCK, ACTION_FALLING, -1
3684 Ystone_sB, FALSE, TRUE,
3685 EL_ROCK, ACTION_FALLING, -1
3688 Ystone_e, FALSE, FALSE,
3689 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3692 Ystone_eB, FALSE, TRUE,
3693 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3696 Ystone_w, FALSE, FALSE,
3697 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3700 Ystone_wB, FALSE, TRUE,
3701 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3708 Xnut_pause, FALSE, FALSE,
3712 Xnut_fall, FALSE, FALSE,
3716 Ynut_s, FALSE, FALSE,
3717 EL_NUT, ACTION_FALLING, -1
3720 Ynut_sB, FALSE, TRUE,
3721 EL_NUT, ACTION_FALLING, -1
3724 Ynut_e, FALSE, FALSE,
3725 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3728 Ynut_eB, FALSE, TRUE,
3729 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3732 Ynut_w, FALSE, FALSE,
3733 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3736 Ynut_wB, FALSE, TRUE,
3737 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3740 Xbug_n, TRUE, FALSE,
3744 Xbug_e, TRUE, FALSE,
3745 EL_BUG_RIGHT, -1, -1
3748 Xbug_s, TRUE, FALSE,
3752 Xbug_w, TRUE, FALSE,
3756 Xbug_gon, FALSE, FALSE,
3760 Xbug_goe, FALSE, FALSE,
3761 EL_BUG_RIGHT, -1, -1
3764 Xbug_gos, FALSE, FALSE,
3768 Xbug_gow, FALSE, FALSE,
3772 Ybug_n, FALSE, FALSE,
3773 EL_BUG, ACTION_MOVING, MV_BIT_UP
3776 Ybug_nB, FALSE, TRUE,
3777 EL_BUG, ACTION_MOVING, MV_BIT_UP
3780 Ybug_e, FALSE, FALSE,
3781 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3784 Ybug_eB, FALSE, TRUE,
3785 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3788 Ybug_s, FALSE, FALSE,
3789 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3792 Ybug_sB, FALSE, TRUE,
3793 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3796 Ybug_w, FALSE, FALSE,
3797 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3800 Ybug_wB, FALSE, TRUE,
3801 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3804 Ybug_w_n, FALSE, FALSE,
3805 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3808 Ybug_n_e, FALSE, FALSE,
3809 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3812 Ybug_e_s, FALSE, FALSE,
3813 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3816 Ybug_s_w, FALSE, FALSE,
3817 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3820 Ybug_e_n, FALSE, FALSE,
3821 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3824 Ybug_s_e, FALSE, FALSE,
3825 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3828 Ybug_w_s, FALSE, FALSE,
3829 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3832 Ybug_n_w, FALSE, FALSE,
3833 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3836 Ybug_stone, FALSE, FALSE,
3837 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3840 Ybug_spring, FALSE, FALSE,
3841 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3844 Xtank_n, TRUE, FALSE,
3845 EL_SPACESHIP_UP, -1, -1
3848 Xtank_e, TRUE, FALSE,
3849 EL_SPACESHIP_RIGHT, -1, -1
3852 Xtank_s, TRUE, FALSE,
3853 EL_SPACESHIP_DOWN, -1, -1
3856 Xtank_w, TRUE, FALSE,
3857 EL_SPACESHIP_LEFT, -1, -1
3860 Xtank_gon, FALSE, FALSE,
3861 EL_SPACESHIP_UP, -1, -1
3864 Xtank_goe, FALSE, FALSE,
3865 EL_SPACESHIP_RIGHT, -1, -1
3868 Xtank_gos, FALSE, FALSE,
3869 EL_SPACESHIP_DOWN, -1, -1
3872 Xtank_gow, FALSE, FALSE,
3873 EL_SPACESHIP_LEFT, -1, -1
3876 Ytank_n, FALSE, FALSE,
3877 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3880 Ytank_nB, FALSE, TRUE,
3881 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3884 Ytank_e, FALSE, FALSE,
3885 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3888 Ytank_eB, FALSE, TRUE,
3889 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3892 Ytank_s, FALSE, FALSE,
3893 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3896 Ytank_sB, FALSE, TRUE,
3897 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3900 Ytank_w, FALSE, FALSE,
3901 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3904 Ytank_wB, FALSE, TRUE,
3905 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3908 Ytank_w_n, FALSE, FALSE,
3909 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3912 Ytank_n_e, FALSE, FALSE,
3913 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3916 Ytank_e_s, FALSE, FALSE,
3917 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3920 Ytank_s_w, FALSE, FALSE,
3921 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3924 Ytank_e_n, FALSE, FALSE,
3925 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3928 Ytank_s_e, FALSE, FALSE,
3929 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3932 Ytank_w_s, FALSE, FALSE,
3933 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3936 Ytank_n_w, FALSE, FALSE,
3937 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3940 Ytank_stone, FALSE, FALSE,
3941 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3944 Ytank_spring, FALSE, FALSE,
3945 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3948 Xandroid, TRUE, FALSE,
3949 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3952 Xandroid_1_n, FALSE, FALSE,
3953 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3956 Xandroid_2_n, FALSE, FALSE,
3957 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3960 Xandroid_1_e, FALSE, FALSE,
3961 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3964 Xandroid_2_e, FALSE, FALSE,
3965 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3968 Xandroid_1_w, FALSE, FALSE,
3969 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3972 Xandroid_2_w, FALSE, FALSE,
3973 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3976 Xandroid_1_s, FALSE, FALSE,
3977 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3980 Xandroid_2_s, FALSE, FALSE,
3981 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3984 Yandroid_n, FALSE, FALSE,
3985 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3988 Yandroid_nB, FALSE, TRUE,
3989 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3992 Yandroid_ne, FALSE, FALSE,
3993 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3996 Yandroid_neB, FALSE, TRUE,
3997 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4000 Yandroid_e, FALSE, FALSE,
4001 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4004 Yandroid_eB, FALSE, TRUE,
4005 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4008 Yandroid_se, FALSE, FALSE,
4009 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4012 Yandroid_seB, FALSE, TRUE,
4013 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4016 Yandroid_s, FALSE, FALSE,
4017 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4020 Yandroid_sB, FALSE, TRUE,
4021 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4024 Yandroid_sw, FALSE, FALSE,
4025 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4028 Yandroid_swB, FALSE, TRUE,
4029 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4032 Yandroid_w, FALSE, FALSE,
4033 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4036 Yandroid_wB, FALSE, TRUE,
4037 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4040 Yandroid_nw, FALSE, FALSE,
4041 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4044 Yandroid_nwB, FALSE, TRUE,
4045 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4048 Xspring, TRUE, FALSE,
4052 Xspring_pause, FALSE, FALSE,
4056 Xspring_e, FALSE, FALSE,
4060 Xspring_w, FALSE, FALSE,
4064 Xspring_fall, FALSE, FALSE,
4068 Yspring_s, FALSE, FALSE,
4069 EL_SPRING, ACTION_FALLING, -1
4072 Yspring_sB, FALSE, TRUE,
4073 EL_SPRING, ACTION_FALLING, -1
4076 Yspring_e, FALSE, FALSE,
4077 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4080 Yspring_eB, FALSE, TRUE,
4081 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4084 Yspring_w, FALSE, FALSE,
4085 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4088 Yspring_wB, FALSE, TRUE,
4089 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4092 Yspring_kill_e, FALSE, FALSE,
4093 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4096 Yspring_kill_eB, FALSE, TRUE,
4097 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4100 Yspring_kill_w, FALSE, FALSE,
4101 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4104 Yspring_kill_wB, FALSE, TRUE,
4105 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4108 Xeater_n, TRUE, FALSE,
4109 EL_YAMYAM_UP, -1, -1
4112 Xeater_e, TRUE, FALSE,
4113 EL_YAMYAM_RIGHT, -1, -1
4116 Xeater_w, TRUE, FALSE,
4117 EL_YAMYAM_LEFT, -1, -1
4120 Xeater_s, TRUE, FALSE,
4121 EL_YAMYAM_DOWN, -1, -1
4124 Yeater_n, FALSE, FALSE,
4125 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4128 Yeater_nB, FALSE, TRUE,
4129 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4132 Yeater_e, FALSE, FALSE,
4133 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4136 Yeater_eB, FALSE, TRUE,
4137 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4140 Yeater_s, FALSE, FALSE,
4141 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4144 Yeater_sB, FALSE, TRUE,
4145 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4148 Yeater_w, FALSE, FALSE,
4149 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4152 Yeater_wB, FALSE, TRUE,
4153 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4156 Yeater_stone, FALSE, FALSE,
4157 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4160 Yeater_spring, FALSE, FALSE,
4161 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4164 Xalien, TRUE, FALSE,
4168 Xalien_pause, FALSE, FALSE,
4172 Yalien_n, FALSE, FALSE,
4173 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4176 Yalien_nB, FALSE, TRUE,
4177 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4180 Yalien_e, FALSE, FALSE,
4181 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4184 Yalien_eB, FALSE, TRUE,
4185 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4188 Yalien_s, FALSE, FALSE,
4189 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4192 Yalien_sB, FALSE, TRUE,
4193 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4196 Yalien_w, FALSE, FALSE,
4197 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4200 Yalien_wB, FALSE, TRUE,
4201 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4204 Yalien_stone, FALSE, FALSE,
4205 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4208 Yalien_spring, FALSE, FALSE,
4209 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4212 Xemerald, TRUE, FALSE,
4216 Xemerald_pause, FALSE, FALSE,
4220 Xemerald_fall, FALSE, FALSE,
4224 Xemerald_shine, FALSE, FALSE,
4225 EL_EMERALD, ACTION_TWINKLING, -1
4228 Yemerald_s, FALSE, FALSE,
4229 EL_EMERALD, ACTION_FALLING, -1
4232 Yemerald_sB, FALSE, TRUE,
4233 EL_EMERALD, ACTION_FALLING, -1
4236 Yemerald_e, FALSE, FALSE,
4237 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4240 Yemerald_eB, FALSE, TRUE,
4241 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4244 Yemerald_w, FALSE, FALSE,
4245 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4248 Yemerald_wB, FALSE, TRUE,
4249 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4252 Yemerald_eat, FALSE, FALSE,
4253 EL_EMERALD, ACTION_COLLECTING, -1
4256 Yemerald_stone, FALSE, FALSE,
4257 EL_NUT, ACTION_BREAKING, -1
4260 Xdiamond, TRUE, FALSE,
4264 Xdiamond_pause, FALSE, FALSE,
4268 Xdiamond_fall, FALSE, FALSE,
4272 Xdiamond_shine, FALSE, FALSE,
4273 EL_DIAMOND, ACTION_TWINKLING, -1
4276 Ydiamond_s, FALSE, FALSE,
4277 EL_DIAMOND, ACTION_FALLING, -1
4280 Ydiamond_sB, FALSE, TRUE,
4281 EL_DIAMOND, ACTION_FALLING, -1
4284 Ydiamond_e, FALSE, FALSE,
4285 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4288 Ydiamond_eB, FALSE, TRUE,
4289 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4292 Ydiamond_w, FALSE, FALSE,
4293 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4296 Ydiamond_wB, FALSE, TRUE,
4297 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4300 Ydiamond_eat, FALSE, FALSE,
4301 EL_DIAMOND, ACTION_COLLECTING, -1
4304 Ydiamond_stone, FALSE, FALSE,
4305 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4308 Xdrip_fall, TRUE, FALSE,
4309 EL_AMOEBA_DROP, -1, -1
4312 Xdrip_stretch, FALSE, FALSE,
4313 EL_AMOEBA_DROP, ACTION_FALLING, -1
4316 Xdrip_stretchB, FALSE, TRUE,
4317 EL_AMOEBA_DROP, ACTION_FALLING, -1
4320 Xdrip_eat, FALSE, FALSE,
4321 EL_AMOEBA_DROP, ACTION_GROWING, -1
4324 Ydrip_s1, FALSE, FALSE,
4325 EL_AMOEBA_DROP, ACTION_FALLING, -1
4328 Ydrip_s1B, FALSE, TRUE,
4329 EL_AMOEBA_DROP, ACTION_FALLING, -1
4332 Ydrip_s2, FALSE, FALSE,
4333 EL_AMOEBA_DROP, ACTION_FALLING, -1
4336 Ydrip_s2B, FALSE, TRUE,
4337 EL_AMOEBA_DROP, ACTION_FALLING, -1
4344 Xbomb_pause, FALSE, FALSE,
4348 Xbomb_fall, FALSE, FALSE,
4352 Ybomb_s, FALSE, FALSE,
4353 EL_BOMB, ACTION_FALLING, -1
4356 Ybomb_sB, FALSE, TRUE,
4357 EL_BOMB, ACTION_FALLING, -1
4360 Ybomb_e, FALSE, FALSE,
4361 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4364 Ybomb_eB, FALSE, TRUE,
4365 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4368 Ybomb_w, FALSE, FALSE,
4369 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4372 Ybomb_wB, FALSE, TRUE,
4373 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4376 Ybomb_eat, FALSE, FALSE,
4377 EL_BOMB, ACTION_ACTIVATING, -1
4380 Xballoon, TRUE, FALSE,
4384 Yballoon_n, FALSE, FALSE,
4385 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4388 Yballoon_nB, FALSE, TRUE,
4389 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4392 Yballoon_e, FALSE, FALSE,
4393 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4396 Yballoon_eB, FALSE, TRUE,
4397 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4400 Yballoon_s, FALSE, FALSE,
4401 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4404 Yballoon_sB, FALSE, TRUE,
4405 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4408 Yballoon_w, FALSE, FALSE,
4409 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4412 Yballoon_wB, FALSE, TRUE,
4413 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4416 Xgrass, TRUE, FALSE,
4417 EL_EMC_GRASS, -1, -1
4420 Ygrass_nB, FALSE, FALSE,
4421 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4424 Ygrass_eB, FALSE, FALSE,
4425 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4428 Ygrass_sB, FALSE, FALSE,
4429 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4432 Ygrass_wB, FALSE, FALSE,
4433 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4440 Ydirt_nB, FALSE, FALSE,
4441 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4444 Ydirt_eB, FALSE, FALSE,
4445 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4448 Ydirt_sB, FALSE, FALSE,
4449 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4452 Ydirt_wB, FALSE, FALSE,
4453 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4456 Xacid_ne, TRUE, FALSE,
4457 EL_ACID_POOL_TOPRIGHT, -1, -1
4460 Xacid_se, TRUE, FALSE,
4461 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4464 Xacid_s, TRUE, FALSE,
4465 EL_ACID_POOL_BOTTOM, -1, -1
4468 Xacid_sw, TRUE, FALSE,
4469 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4472 Xacid_nw, TRUE, FALSE,
4473 EL_ACID_POOL_TOPLEFT, -1, -1
4476 Xacid_1, TRUE, FALSE,
4480 Xacid_2, FALSE, FALSE,
4484 Xacid_3, FALSE, FALSE,
4488 Xacid_4, FALSE, FALSE,
4492 Xacid_5, FALSE, FALSE,
4496 Xacid_6, FALSE, FALSE,
4500 Xacid_7, FALSE, FALSE,
4504 Xacid_8, FALSE, FALSE,
4508 Xball_1, TRUE, FALSE,
4509 EL_EMC_MAGIC_BALL, -1, -1
4512 Xball_1B, FALSE, FALSE,
4513 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4516 Xball_2, FALSE, FALSE,
4517 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4520 Xball_2B, FALSE, FALSE,
4521 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4524 Yball_eat, FALSE, FALSE,
4525 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4528 Ykey_1_eat, FALSE, FALSE,
4529 EL_EM_KEY_1, ACTION_COLLECTING, -1
4532 Ykey_2_eat, FALSE, FALSE,
4533 EL_EM_KEY_2, ACTION_COLLECTING, -1
4536 Ykey_3_eat, FALSE, FALSE,
4537 EL_EM_KEY_3, ACTION_COLLECTING, -1
4540 Ykey_4_eat, FALSE, FALSE,
4541 EL_EM_KEY_4, ACTION_COLLECTING, -1
4544 Ykey_5_eat, FALSE, FALSE,
4545 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4548 Ykey_6_eat, FALSE, FALSE,
4549 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4552 Ykey_7_eat, FALSE, FALSE,
4553 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4556 Ykey_8_eat, FALSE, FALSE,
4557 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4560 Ylenses_eat, FALSE, FALSE,
4561 EL_EMC_LENSES, ACTION_COLLECTING, -1
4564 Ymagnify_eat, FALSE, FALSE,
4565 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4568 Ygrass_eat, FALSE, FALSE,
4569 EL_EMC_GRASS, ACTION_SNAPPING, -1
4572 Ydirt_eat, FALSE, FALSE,
4573 EL_SAND, ACTION_SNAPPING, -1
4576 Xgrow_ns, TRUE, FALSE,
4577 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4580 Ygrow_ns_eat, FALSE, FALSE,
4581 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4584 Xgrow_ew, TRUE, FALSE,
4585 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4588 Ygrow_ew_eat, FALSE, FALSE,
4589 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4592 Xwonderwall, TRUE, FALSE,
4593 EL_MAGIC_WALL, -1, -1
4596 XwonderwallB, FALSE, FALSE,
4597 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4600 Xamoeba_1, TRUE, FALSE,
4601 EL_AMOEBA_DRY, ACTION_OTHER, -1
4604 Xamoeba_2, FALSE, FALSE,
4605 EL_AMOEBA_DRY, ACTION_OTHER, -1
4608 Xamoeba_3, FALSE, FALSE,
4609 EL_AMOEBA_DRY, ACTION_OTHER, -1
4612 Xamoeba_4, FALSE, FALSE,
4613 EL_AMOEBA_DRY, ACTION_OTHER, -1
4616 Xamoeba_5, TRUE, FALSE,
4617 EL_AMOEBA_WET, ACTION_OTHER, -1
4620 Xamoeba_6, FALSE, FALSE,
4621 EL_AMOEBA_WET, ACTION_OTHER, -1
4624 Xamoeba_7, FALSE, FALSE,
4625 EL_AMOEBA_WET, ACTION_OTHER, -1
4628 Xamoeba_8, FALSE, FALSE,
4629 EL_AMOEBA_WET, ACTION_OTHER, -1
4632 Xdoor_1, TRUE, FALSE,
4633 EL_EM_GATE_1, -1, -1
4636 Xdoor_2, TRUE, FALSE,
4637 EL_EM_GATE_2, -1, -1
4640 Xdoor_3, TRUE, FALSE,
4641 EL_EM_GATE_3, -1, -1
4644 Xdoor_4, TRUE, FALSE,
4645 EL_EM_GATE_4, -1, -1
4648 Xdoor_5, TRUE, FALSE,
4649 EL_EMC_GATE_5, -1, -1
4652 Xdoor_6, TRUE, FALSE,
4653 EL_EMC_GATE_6, -1, -1
4656 Xdoor_7, TRUE, FALSE,
4657 EL_EMC_GATE_7, -1, -1
4660 Xdoor_8, TRUE, FALSE,
4661 EL_EMC_GATE_8, -1, -1
4664 Xkey_1, TRUE, FALSE,
4668 Xkey_2, TRUE, FALSE,
4672 Xkey_3, TRUE, FALSE,
4676 Xkey_4, TRUE, FALSE,
4680 Xkey_5, TRUE, FALSE,
4681 EL_EMC_KEY_5, -1, -1
4684 Xkey_6, TRUE, FALSE,
4685 EL_EMC_KEY_6, -1, -1
4688 Xkey_7, TRUE, FALSE,
4689 EL_EMC_KEY_7, -1, -1
4692 Xkey_8, TRUE, FALSE,
4693 EL_EMC_KEY_8, -1, -1
4696 Xwind_n, TRUE, FALSE,
4697 EL_BALLOON_SWITCH_UP, -1, -1
4700 Xwind_e, TRUE, FALSE,
4701 EL_BALLOON_SWITCH_RIGHT, -1, -1
4704 Xwind_s, TRUE, FALSE,
4705 EL_BALLOON_SWITCH_DOWN, -1, -1
4708 Xwind_w, TRUE, FALSE,
4709 EL_BALLOON_SWITCH_LEFT, -1, -1
4712 Xwind_nesw, TRUE, FALSE,
4713 EL_BALLOON_SWITCH_ANY, -1, -1
4716 Xwind_stop, TRUE, FALSE,
4717 EL_BALLOON_SWITCH_NONE, -1, -1
4721 EL_EM_EXIT_CLOSED, -1, -1
4724 Xexit_1, TRUE, FALSE,
4725 EL_EM_EXIT_OPEN, -1, -1
4728 Xexit_2, FALSE, FALSE,
4729 EL_EM_EXIT_OPEN, -1, -1
4732 Xexit_3, FALSE, FALSE,
4733 EL_EM_EXIT_OPEN, -1, -1
4736 Xdynamite, TRUE, FALSE,
4737 EL_EM_DYNAMITE, -1, -1
4740 Ydynamite_eat, FALSE, FALSE,
4741 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4744 Xdynamite_1, TRUE, FALSE,
4745 EL_EM_DYNAMITE_ACTIVE, -1, -1
4748 Xdynamite_2, FALSE, FALSE,
4749 EL_EM_DYNAMITE_ACTIVE, -1, -1
4752 Xdynamite_3, FALSE, FALSE,
4753 EL_EM_DYNAMITE_ACTIVE, -1, -1
4756 Xdynamite_4, FALSE, FALSE,
4757 EL_EM_DYNAMITE_ACTIVE, -1, -1
4760 Xbumper, TRUE, FALSE,
4761 EL_EMC_SPRING_BUMPER, -1, -1
4764 XbumperB, FALSE, FALSE,
4765 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4768 Xwheel, TRUE, FALSE,
4769 EL_ROBOT_WHEEL, -1, -1
4772 XwheelB, FALSE, FALSE,
4773 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4776 Xswitch, TRUE, FALSE,
4777 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4780 XswitchB, FALSE, FALSE,
4781 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4785 EL_QUICKSAND_EMPTY, -1, -1
4788 Xsand_stone, TRUE, FALSE,
4789 EL_QUICKSAND_FULL, -1, -1
4792 Xsand_stonein_1, FALSE, TRUE,
4793 EL_ROCK, ACTION_FILLING, -1
4796 Xsand_stonein_2, FALSE, TRUE,
4797 EL_ROCK, ACTION_FILLING, -1
4800 Xsand_stonein_3, FALSE, TRUE,
4801 EL_ROCK, ACTION_FILLING, -1
4804 Xsand_stonein_4, FALSE, TRUE,
4805 EL_ROCK, ACTION_FILLING, -1
4808 Xsand_stonesand_1, FALSE, FALSE,
4809 EL_QUICKSAND_FULL, -1, -1
4812 Xsand_stonesand_2, FALSE, FALSE,
4813 EL_QUICKSAND_FULL, -1, -1
4816 Xsand_stonesand_3, FALSE, FALSE,
4817 EL_QUICKSAND_FULL, -1, -1
4820 Xsand_stonesand_4, FALSE, FALSE,
4821 EL_QUICKSAND_FULL, -1, -1
4824 Xsand_stoneout_1, FALSE, FALSE,
4825 EL_ROCK, ACTION_EMPTYING, -1
4828 Xsand_stoneout_2, FALSE, FALSE,
4829 EL_ROCK, ACTION_EMPTYING, -1
4832 Xsand_sandstone_1, FALSE, FALSE,
4833 EL_QUICKSAND_FULL, -1, -1
4836 Xsand_sandstone_2, FALSE, FALSE,
4837 EL_QUICKSAND_FULL, -1, -1
4840 Xsand_sandstone_3, FALSE, FALSE,
4841 EL_QUICKSAND_FULL, -1, -1
4844 Xsand_sandstone_4, FALSE, FALSE,
4845 EL_QUICKSAND_FULL, -1, -1
4848 Xplant, TRUE, FALSE,
4849 EL_EMC_PLANT, -1, -1
4852 Yplant, FALSE, FALSE,
4853 EL_EMC_PLANT, -1, -1
4856 Xlenses, TRUE, FALSE,
4857 EL_EMC_LENSES, -1, -1
4860 Xmagnify, TRUE, FALSE,
4861 EL_EMC_MAGNIFIER, -1, -1
4864 Xdripper, TRUE, FALSE,
4865 EL_EMC_DRIPPER, -1, -1
4868 XdripperB, FALSE, FALSE,
4869 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4872 Xfake_blank, TRUE, FALSE,
4873 EL_INVISIBLE_WALL, -1, -1
4876 Xfake_blankB, FALSE, FALSE,
4877 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4880 Xfake_grass, TRUE, FALSE,
4881 EL_EMC_FAKE_GRASS, -1, -1
4884 Xfake_grassB, FALSE, FALSE,
4885 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4888 Xfake_door_1, TRUE, FALSE,
4889 EL_EM_GATE_1_GRAY, -1, -1
4892 Xfake_door_2, TRUE, FALSE,
4893 EL_EM_GATE_2_GRAY, -1, -1
4896 Xfake_door_3, TRUE, FALSE,
4897 EL_EM_GATE_3_GRAY, -1, -1
4900 Xfake_door_4, TRUE, FALSE,
4901 EL_EM_GATE_4_GRAY, -1, -1
4904 Xfake_door_5, TRUE, FALSE,
4905 EL_EMC_GATE_5_GRAY, -1, -1
4908 Xfake_door_6, TRUE, FALSE,
4909 EL_EMC_GATE_6_GRAY, -1, -1
4912 Xfake_door_7, TRUE, FALSE,
4913 EL_EMC_GATE_7_GRAY, -1, -1
4916 Xfake_door_8, TRUE, FALSE,
4917 EL_EMC_GATE_8_GRAY, -1, -1
4920 Xfake_acid_1, TRUE, FALSE,
4921 EL_EMC_FAKE_ACID, -1, -1
4924 Xfake_acid_2, FALSE, FALSE,
4925 EL_EMC_FAKE_ACID, -1, -1
4928 Xfake_acid_3, FALSE, FALSE,
4929 EL_EMC_FAKE_ACID, -1, -1
4932 Xfake_acid_4, FALSE, FALSE,
4933 EL_EMC_FAKE_ACID, -1, -1
4936 Xfake_acid_5, FALSE, FALSE,
4937 EL_EMC_FAKE_ACID, -1, -1
4940 Xfake_acid_6, FALSE, FALSE,
4941 EL_EMC_FAKE_ACID, -1, -1
4944 Xfake_acid_7, FALSE, FALSE,
4945 EL_EMC_FAKE_ACID, -1, -1
4948 Xfake_acid_8, FALSE, FALSE,
4949 EL_EMC_FAKE_ACID, -1, -1
4952 Xsteel_1, TRUE, FALSE,
4953 EL_STEELWALL, -1, -1
4956 Xsteel_2, TRUE, FALSE,
4957 EL_EMC_STEELWALL_2, -1, -1
4960 Xsteel_3, TRUE, FALSE,
4961 EL_EMC_STEELWALL_3, -1, -1
4964 Xsteel_4, TRUE, FALSE,
4965 EL_EMC_STEELWALL_4, -1, -1
4968 Xwall_1, TRUE, FALSE,
4972 Xwall_2, TRUE, FALSE,
4973 EL_EMC_WALL_14, -1, -1
4976 Xwall_3, TRUE, FALSE,
4977 EL_EMC_WALL_15, -1, -1
4980 Xwall_4, TRUE, FALSE,
4981 EL_EMC_WALL_16, -1, -1
4984 Xround_wall_1, TRUE, FALSE,
4985 EL_WALL_SLIPPERY, -1, -1
4988 Xround_wall_2, TRUE, FALSE,
4989 EL_EMC_WALL_SLIPPERY_2, -1, -1
4992 Xround_wall_3, TRUE, FALSE,
4993 EL_EMC_WALL_SLIPPERY_3, -1, -1
4996 Xround_wall_4, TRUE, FALSE,
4997 EL_EMC_WALL_SLIPPERY_4, -1, -1
5000 Xdecor_1, TRUE, FALSE,
5001 EL_EMC_WALL_8, -1, -1
5004 Xdecor_2, TRUE, FALSE,
5005 EL_EMC_WALL_6, -1, -1
5008 Xdecor_3, TRUE, FALSE,
5009 EL_EMC_WALL_4, -1, -1
5012 Xdecor_4, TRUE, FALSE,
5013 EL_EMC_WALL_7, -1, -1
5016 Xdecor_5, TRUE, FALSE,
5017 EL_EMC_WALL_5, -1, -1
5020 Xdecor_6, TRUE, FALSE,
5021 EL_EMC_WALL_9, -1, -1
5024 Xdecor_7, TRUE, FALSE,
5025 EL_EMC_WALL_10, -1, -1
5028 Xdecor_8, TRUE, FALSE,
5029 EL_EMC_WALL_1, -1, -1
5032 Xdecor_9, TRUE, FALSE,
5033 EL_EMC_WALL_2, -1, -1
5036 Xdecor_10, TRUE, FALSE,
5037 EL_EMC_WALL_3, -1, -1
5040 Xdecor_11, TRUE, FALSE,
5041 EL_EMC_WALL_11, -1, -1
5044 Xdecor_12, TRUE, FALSE,
5045 EL_EMC_WALL_12, -1, -1
5048 Xalpha_0, TRUE, FALSE,
5049 EL_CHAR('0'), -1, -1
5052 Xalpha_1, TRUE, FALSE,
5053 EL_CHAR('1'), -1, -1
5056 Xalpha_2, TRUE, FALSE,
5057 EL_CHAR('2'), -1, -1
5060 Xalpha_3, TRUE, FALSE,
5061 EL_CHAR('3'), -1, -1
5064 Xalpha_4, TRUE, FALSE,
5065 EL_CHAR('4'), -1, -1
5068 Xalpha_5, TRUE, FALSE,
5069 EL_CHAR('5'), -1, -1
5072 Xalpha_6, TRUE, FALSE,
5073 EL_CHAR('6'), -1, -1
5076 Xalpha_7, TRUE, FALSE,
5077 EL_CHAR('7'), -1, -1
5080 Xalpha_8, TRUE, FALSE,
5081 EL_CHAR('8'), -1, -1
5084 Xalpha_9, TRUE, FALSE,
5085 EL_CHAR('9'), -1, -1
5088 Xalpha_excla, TRUE, FALSE,
5089 EL_CHAR('!'), -1, -1
5092 Xalpha_quote, TRUE, FALSE,
5093 EL_CHAR('"'), -1, -1
5096 Xalpha_comma, TRUE, FALSE,
5097 EL_CHAR(','), -1, -1
5100 Xalpha_minus, TRUE, FALSE,
5101 EL_CHAR('-'), -1, -1
5104 Xalpha_perio, TRUE, FALSE,
5105 EL_CHAR('.'), -1, -1
5108 Xalpha_colon, TRUE, FALSE,
5109 EL_CHAR(':'), -1, -1
5112 Xalpha_quest, TRUE, FALSE,
5113 EL_CHAR('?'), -1, -1
5116 Xalpha_a, TRUE, FALSE,
5117 EL_CHAR('A'), -1, -1
5120 Xalpha_b, TRUE, FALSE,
5121 EL_CHAR('B'), -1, -1
5124 Xalpha_c, TRUE, FALSE,
5125 EL_CHAR('C'), -1, -1
5128 Xalpha_d, TRUE, FALSE,
5129 EL_CHAR('D'), -1, -1
5132 Xalpha_e, TRUE, FALSE,
5133 EL_CHAR('E'), -1, -1
5136 Xalpha_f, TRUE, FALSE,
5137 EL_CHAR('F'), -1, -1
5140 Xalpha_g, TRUE, FALSE,
5141 EL_CHAR('G'), -1, -1
5144 Xalpha_h, TRUE, FALSE,
5145 EL_CHAR('H'), -1, -1
5148 Xalpha_i, TRUE, FALSE,
5149 EL_CHAR('I'), -1, -1
5152 Xalpha_j, TRUE, FALSE,
5153 EL_CHAR('J'), -1, -1
5156 Xalpha_k, TRUE, FALSE,
5157 EL_CHAR('K'), -1, -1
5160 Xalpha_l, TRUE, FALSE,
5161 EL_CHAR('L'), -1, -1
5164 Xalpha_m, TRUE, FALSE,
5165 EL_CHAR('M'), -1, -1
5168 Xalpha_n, TRUE, FALSE,
5169 EL_CHAR('N'), -1, -1
5172 Xalpha_o, TRUE, FALSE,
5173 EL_CHAR('O'), -1, -1
5176 Xalpha_p, TRUE, FALSE,
5177 EL_CHAR('P'), -1, -1
5180 Xalpha_q, TRUE, FALSE,
5181 EL_CHAR('Q'), -1, -1
5184 Xalpha_r, TRUE, FALSE,
5185 EL_CHAR('R'), -1, -1
5188 Xalpha_s, TRUE, FALSE,
5189 EL_CHAR('S'), -1, -1
5192 Xalpha_t, TRUE, FALSE,
5193 EL_CHAR('T'), -1, -1
5196 Xalpha_u, TRUE, FALSE,
5197 EL_CHAR('U'), -1, -1
5200 Xalpha_v, TRUE, FALSE,
5201 EL_CHAR('V'), -1, -1
5204 Xalpha_w, TRUE, FALSE,
5205 EL_CHAR('W'), -1, -1
5208 Xalpha_x, TRUE, FALSE,
5209 EL_CHAR('X'), -1, -1
5212 Xalpha_y, TRUE, FALSE,
5213 EL_CHAR('Y'), -1, -1
5216 Xalpha_z, TRUE, FALSE,
5217 EL_CHAR('Z'), -1, -1
5220 Xalpha_arrow_e, TRUE, FALSE,
5221 EL_CHAR('>'), -1, -1
5224 Xalpha_arrow_w, TRUE, FALSE,
5225 EL_CHAR('<'), -1, -1
5228 Xalpha_copyr, TRUE, FALSE,
5229 EL_CHAR('©'), -1, -1
5233 Xboom_bug, FALSE, FALSE,
5234 EL_BUG, ACTION_EXPLODING, -1
5237 Xboom_bomb, FALSE, FALSE,
5238 EL_BOMB, ACTION_EXPLODING, -1
5241 Xboom_android, FALSE, FALSE,
5242 EL_EMC_ANDROID, ACTION_OTHER, -1
5245 Xboom_1, FALSE, FALSE,
5246 EL_DEFAULT, ACTION_EXPLODING, -1
5249 Xboom_2, FALSE, FALSE,
5250 EL_DEFAULT, ACTION_EXPLODING, -1
5253 Znormal, FALSE, FALSE,
5257 Zdynamite, FALSE, FALSE,
5261 Zplayer, FALSE, FALSE,
5265 ZBORDER, FALSE, FALSE,
5275 static struct Mapping_EM_to_RND_player
5284 em_player_mapping_list[] =
5288 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5292 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5296 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5300 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5304 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5308 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5312 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5316 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5320 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5324 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5328 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5332 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5336 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5340 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5344 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5348 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5352 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5356 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5360 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5364 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5368 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5372 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5376 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5380 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5384 EL_PLAYER_1, ACTION_DEFAULT, -1,
5388 EL_PLAYER_2, ACTION_DEFAULT, -1,
5392 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5396 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5400 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5404 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5408 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5412 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5416 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5420 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5424 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5428 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5432 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5436 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5440 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5444 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5448 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5452 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5456 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5460 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5464 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5468 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5472 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5476 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5480 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5484 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5488 EL_PLAYER_3, ACTION_DEFAULT, -1,
5492 EL_PLAYER_4, ACTION_DEFAULT, -1,
5501 int map_element_RND_to_EM(int element_rnd)
5503 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5504 static boolean mapping_initialized = FALSE;
5506 if (!mapping_initialized)
5510 /* return "Xalpha_quest" for all undefined elements in mapping array */
5511 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5512 mapping_RND_to_EM[i] = Xalpha_quest;
5514 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5515 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5516 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5517 em_object_mapping_list[i].element_em;
5519 mapping_initialized = TRUE;
5522 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5523 return mapping_RND_to_EM[element_rnd];
5525 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5530 int map_element_EM_to_RND(int element_em)
5532 static unsigned short mapping_EM_to_RND[TILE_MAX];
5533 static boolean mapping_initialized = FALSE;
5535 if (!mapping_initialized)
5539 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5540 for (i = 0; i < TILE_MAX; i++)
5541 mapping_EM_to_RND[i] = EL_UNKNOWN;
5543 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5544 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5545 em_object_mapping_list[i].element_rnd;
5547 mapping_initialized = TRUE;
5550 if (element_em >= 0 && element_em < TILE_MAX)
5551 return mapping_EM_to_RND[element_em];
5553 Error(ERR_WARN, "invalid EM level element %d", element_em);
5558 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5560 struct LevelInfo_EM *level_em = level->native_em_level;
5561 struct LEVEL *lev = level_em->lev;
5564 for (i = 0; i < TILE_MAX; i++)
5565 lev->android_array[i] = Xblank;
5567 for (i = 0; i < level->num_android_clone_elements; i++)
5569 int element_rnd = level->android_clone_element[i];
5570 int element_em = map_element_RND_to_EM(element_rnd);
5572 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5573 if (em_object_mapping_list[j].element_rnd == element_rnd)
5574 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5578 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5580 struct LevelInfo_EM *level_em = level->native_em_level;
5581 struct LEVEL *lev = level_em->lev;
5584 level->num_android_clone_elements = 0;
5586 for (i = 0; i < TILE_MAX; i++)
5588 int element_em = lev->android_array[i];
5590 boolean element_found = FALSE;
5592 if (element_em == Xblank)
5595 element_rnd = map_element_EM_to_RND(element_em);
5597 for (j = 0; j < level->num_android_clone_elements; j++)
5598 if (level->android_clone_element[j] == element_rnd)
5599 element_found = TRUE;
5603 level->android_clone_element[level->num_android_clone_elements++] =
5606 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5611 if (level->num_android_clone_elements == 0)
5613 level->num_android_clone_elements = 1;
5614 level->android_clone_element[0] = EL_EMPTY;
5618 int map_direction_RND_to_EM(int direction)
5620 return (direction == MV_UP ? 0 :
5621 direction == MV_RIGHT ? 1 :
5622 direction == MV_DOWN ? 2 :
5623 direction == MV_LEFT ? 3 :
5627 int map_direction_EM_to_RND(int direction)
5629 return (direction == 0 ? MV_UP :
5630 direction == 1 ? MV_RIGHT :
5631 direction == 2 ? MV_DOWN :
5632 direction == 3 ? MV_LEFT :
5636 int get_next_element(int element)
5640 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5641 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5642 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5643 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5644 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5645 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5646 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5647 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5648 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5649 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5650 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5652 default: return element;
5657 int el_act_dir2img(int element, int action, int direction)
5659 element = GFX_ELEMENT(element);
5661 if (direction == MV_NONE)
5662 return element_info[element].graphic[action];
5664 direction = MV_DIR_TO_BIT(direction);
5666 return element_info[element].direction_graphic[action][direction];
5669 int el_act_dir2img(int element, int action, int direction)
5671 element = GFX_ELEMENT(element);
5672 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5674 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5675 return element_info[element].direction_graphic[action][direction];
5680 static int el_act_dir2crm(int element, int action, int direction)
5682 element = GFX_ELEMENT(element);
5684 if (direction == MV_NONE)
5685 return element_info[element].crumbled[action];
5687 direction = MV_DIR_TO_BIT(direction);
5689 return element_info[element].direction_crumbled[action][direction];
5692 static int el_act_dir2crm(int element, int action, int direction)
5694 element = GFX_ELEMENT(element);
5695 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5697 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5698 return element_info[element].direction_crumbled[action][direction];
5702 int el_act2img(int element, int action)
5704 element = GFX_ELEMENT(element);
5706 return element_info[element].graphic[action];
5709 int el_act2crm(int element, int action)
5711 element = GFX_ELEMENT(element);
5713 return element_info[element].crumbled[action];
5716 int el_dir2img(int element, int direction)
5718 element = GFX_ELEMENT(element);
5720 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5723 int el2baseimg(int element)
5725 return element_info[element].graphic[ACTION_DEFAULT];
5728 int el2img(int element)
5730 element = GFX_ELEMENT(element);
5732 return element_info[element].graphic[ACTION_DEFAULT];
5735 int el2edimg(int element)
5737 element = GFX_ELEMENT(element);
5739 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5742 int el2preimg(int element)
5744 element = GFX_ELEMENT(element);
5746 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5749 int font2baseimg(int font_nr)
5751 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5754 int getBeltNrFromBeltElement(int element)
5756 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5757 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5758 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5761 int getBeltNrFromBeltActiveElement(int element)
5763 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5764 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5765 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5768 int getBeltNrFromBeltSwitchElement(int element)
5770 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5771 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5772 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5775 int getBeltDirNrFromBeltElement(int element)
5777 static int belt_base_element[4] =
5779 EL_CONVEYOR_BELT_1_LEFT,
5780 EL_CONVEYOR_BELT_2_LEFT,
5781 EL_CONVEYOR_BELT_3_LEFT,
5782 EL_CONVEYOR_BELT_4_LEFT
5785 int belt_nr = getBeltNrFromBeltElement(element);
5786 int belt_dir_nr = element - belt_base_element[belt_nr];
5788 return (belt_dir_nr % 3);
5791 int getBeltDirNrFromBeltSwitchElement(int element)
5793 static int belt_base_element[4] =
5795 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5796 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5797 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5798 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5801 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5802 int belt_dir_nr = element - belt_base_element[belt_nr];
5804 return (belt_dir_nr % 3);
5807 int getBeltDirFromBeltElement(int element)
5809 static int belt_move_dir[3] =
5816 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5818 return belt_move_dir[belt_dir_nr];
5821 int getBeltDirFromBeltSwitchElement(int element)
5823 static int belt_move_dir[3] =
5830 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5832 return belt_move_dir[belt_dir_nr];
5835 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5837 static int belt_base_element[4] =
5839 EL_CONVEYOR_BELT_1_LEFT,
5840 EL_CONVEYOR_BELT_2_LEFT,
5841 EL_CONVEYOR_BELT_3_LEFT,
5842 EL_CONVEYOR_BELT_4_LEFT
5844 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5846 return belt_base_element[belt_nr] + belt_dir_nr;
5849 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5851 static int belt_base_element[4] =
5853 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5854 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5855 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5856 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5858 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5860 return belt_base_element[belt_nr] + belt_dir_nr;
5863 int getNumActivePlayers_EM()
5865 int num_players = 0;
5871 for (i = 0; i < MAX_PLAYERS; i++)
5872 if (tape.player_participates[i])
5878 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5880 int game_frame_delay_value;
5882 game_frame_delay_value =
5883 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5884 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5887 if (tape.playing && tape.warp_forward && !tape.pausing)
5888 game_frame_delay_value = 0;
5890 return game_frame_delay_value;
5893 unsigned int InitRND(long seed)
5895 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5896 return InitEngineRandom_EM(seed);
5898 return InitEngineRandom_RND(seed);
5902 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5903 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5906 void ResetGfxAnimation_EM(int x, int y, int tile)
5911 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5912 Bitmap **src_bitmap, int *src_x, int *src_y,
5915 int element = object_mapping[tile].element_rnd;
5916 int action = object_mapping[tile].action;
5917 int direction = object_mapping[tile].direction;
5918 boolean is_backside = object_mapping[tile].is_backside;
5919 boolean action_removing = (action == ACTION_DIGGING ||
5920 action == ACTION_SNAPPING ||
5921 action == ACTION_COLLECTING);
5922 int effective_element = (frame_em > 0 ? element :
5923 is_backside ? EL_EMPTY :
5924 action_removing ? EL_EMPTY :
5926 int graphic = (direction == MV_NONE ?
5927 el_act2img(effective_element, action) :
5928 el_act_dir2img(effective_element, action, direction));
5929 struct GraphicInfo *g = &graphic_info[graphic];
5932 if (graphic_info[graphic].anim_global_sync)
5933 sync_frame = FrameCounter;
5935 sync_frame = 7 - frame_em;
5937 SetRandomAnimationValue(x, y);
5939 int frame = getAnimationFrame(g->anim_frames,
5942 g->anim_start_frame,
5945 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5948 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
5949 Bitmap **src_bitmap, int *src_x, int *src_y)
5951 int element = player_mapping[player_nr][anim].element_rnd;
5952 int action = player_mapping[player_nr][anim].action;
5953 int direction = player_mapping[player_nr][anim].direction;
5954 int graphic = (direction == MV_NONE ?
5955 el_act2img(element, action) :
5956 el_act_dir2img(element, action, direction));
5957 struct GraphicInfo *g = &graphic_info[graphic];
5960 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
5962 stored_player[player_nr].StepFrame = 7 - frame_em;
5964 sync_frame = stored_player[player_nr].Frame;
5967 printf("::: %d: %d, %d [%d]\n",
5969 stored_player[player_nr].Frame,
5970 stored_player[player_nr].StepFrame,
5974 int frame = getAnimationFrame(g->anim_frames,
5977 g->anim_start_frame,
5980 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5983 void InitGraphicInfo_EM(void)
5986 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5987 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5992 int num_em_gfx_errors = 0;
5994 if (graphic_info_em_object[0][0].bitmap == NULL)
5996 /* EM graphics not yet initialized in em_open_all() */
6001 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6004 /* always start with reliable default values */
6005 for (i = 0; i < TILE_MAX; i++)
6007 object_mapping[i].element_rnd = EL_UNKNOWN;
6008 object_mapping[i].is_backside = FALSE;
6009 object_mapping[i].action = ACTION_DEFAULT;
6010 object_mapping[i].direction = MV_NONE;
6013 /* always start with reliable default values */
6014 for (p = 0; p < MAX_PLAYERS; p++)
6016 for (i = 0; i < SPR_MAX; i++)
6018 player_mapping[p][i].element_rnd = EL_UNKNOWN;
6019 player_mapping[p][i].action = ACTION_DEFAULT;
6020 player_mapping[p][i].direction = MV_NONE;
6024 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6026 int e = em_object_mapping_list[i].element_em;
6028 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6029 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6031 if (em_object_mapping_list[i].action != -1)
6032 object_mapping[e].action = em_object_mapping_list[i].action;
6034 if (em_object_mapping_list[i].direction != -1)
6035 object_mapping[e].direction =
6036 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6039 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6041 int a = em_player_mapping_list[i].action_em;
6042 int p = em_player_mapping_list[i].player_nr;
6044 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6046 if (em_player_mapping_list[i].action != -1)
6047 player_mapping[p][a].action = em_player_mapping_list[i].action;
6049 if (em_player_mapping_list[i].direction != -1)
6050 player_mapping[p][a].direction =
6051 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6054 for (i = 0; i < TILE_MAX; i++)
6056 int element = object_mapping[i].element_rnd;
6057 int action = object_mapping[i].action;
6058 int direction = object_mapping[i].direction;
6059 boolean is_backside = object_mapping[i].is_backside;
6060 boolean action_removing = (action == ACTION_DIGGING ||
6061 action == ACTION_SNAPPING ||
6062 action == ACTION_COLLECTING);
6063 boolean action_exploding = ((action == ACTION_EXPLODING ||
6064 action == ACTION_SMASHED_BY_ROCK ||
6065 action == ACTION_SMASHED_BY_SPRING) &&
6066 element != EL_DIAMOND);
6067 boolean action_active = (action == ACTION_ACTIVE);
6068 boolean action_other = (action == ACTION_OTHER);
6070 for (j = 0; j < 8; j++)
6072 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6073 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6075 i == Xdrip_stretch ? element :
6076 i == Xdrip_stretchB ? element :
6077 i == Ydrip_s1 ? element :
6078 i == Ydrip_s1B ? element :
6079 i == Xball_1B ? element :
6080 i == Xball_2 ? element :
6081 i == Xball_2B ? element :
6082 i == Yball_eat ? element :
6083 i == Ykey_1_eat ? element :
6084 i == Ykey_2_eat ? element :
6085 i == Ykey_3_eat ? element :
6086 i == Ykey_4_eat ? element :
6087 i == Ykey_5_eat ? element :
6088 i == Ykey_6_eat ? element :
6089 i == Ykey_7_eat ? element :
6090 i == Ykey_8_eat ? element :
6091 i == Ylenses_eat ? element :
6092 i == Ymagnify_eat ? element :
6093 i == Ygrass_eat ? element :
6094 i == Ydirt_eat ? element :
6095 i == Yemerald_stone ? EL_EMERALD :
6096 i == Ydiamond_stone ? EL_ROCK :
6097 i == Xsand_stonein_1 ? element :
6098 i == Xsand_stonein_2 ? element :
6099 i == Xsand_stonein_3 ? element :
6100 i == Xsand_stonein_4 ? element :
6101 is_backside ? EL_EMPTY :
6102 action_removing ? EL_EMPTY :
6104 int effective_action = (j < 7 ? action :
6105 i == Xdrip_stretch ? action :
6106 i == Xdrip_stretchB ? action :
6107 i == Ydrip_s1 ? action :
6108 i == Ydrip_s1B ? action :
6109 i == Xball_1B ? action :
6110 i == Xball_2 ? action :
6111 i == Xball_2B ? action :
6112 i == Yball_eat ? action :
6113 i == Ykey_1_eat ? action :
6114 i == Ykey_2_eat ? action :
6115 i == Ykey_3_eat ? action :
6116 i == Ykey_4_eat ? action :
6117 i == Ykey_5_eat ? action :
6118 i == Ykey_6_eat ? action :
6119 i == Ykey_7_eat ? action :
6120 i == Ykey_8_eat ? action :
6121 i == Ylenses_eat ? action :
6122 i == Ymagnify_eat ? action :
6123 i == Ygrass_eat ? action :
6124 i == Ydirt_eat ? action :
6125 i == Xsand_stonein_1 ? action :
6126 i == Xsand_stonein_2 ? action :
6127 i == Xsand_stonein_3 ? action :
6128 i == Xsand_stonein_4 ? action :
6129 i == Xsand_stoneout_1 ? action :
6130 i == Xsand_stoneout_2 ? action :
6131 i == Xboom_android ? ACTION_EXPLODING :
6132 action_exploding ? ACTION_EXPLODING :
6133 action_active ? action :
6134 action_other ? action :
6136 int graphic = (el_act_dir2img(effective_element, effective_action,
6138 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6140 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6141 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6142 boolean has_action_graphics = (graphic != base_graphic);
6143 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6144 struct GraphicInfo *g = &graphic_info[graphic];
6145 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6148 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6149 boolean special_animation = (action != ACTION_DEFAULT &&
6150 g->anim_frames == 3 &&
6151 g->anim_delay == 2 &&
6152 g->anim_mode & ANIM_LINEAR);
6153 int sync_frame = (i == Xdrip_stretch ? 7 :
6154 i == Xdrip_stretchB ? 7 :
6155 i == Ydrip_s2 ? j + 8 :
6156 i == Ydrip_s2B ? j + 8 :
6165 i == Xfake_acid_1 ? 0 :
6166 i == Xfake_acid_2 ? 10 :
6167 i == Xfake_acid_3 ? 20 :
6168 i == Xfake_acid_4 ? 30 :
6169 i == Xfake_acid_5 ? 40 :
6170 i == Xfake_acid_6 ? 50 :
6171 i == Xfake_acid_7 ? 60 :
6172 i == Xfake_acid_8 ? 70 :
6174 i == Xball_2B ? j + 8 :
6175 i == Yball_eat ? j + 1 :
6176 i == Ykey_1_eat ? j + 1 :
6177 i == Ykey_2_eat ? j + 1 :
6178 i == Ykey_3_eat ? j + 1 :
6179 i == Ykey_4_eat ? j + 1 :
6180 i == Ykey_5_eat ? j + 1 :
6181 i == Ykey_6_eat ? j + 1 :
6182 i == Ykey_7_eat ? j + 1 :
6183 i == Ykey_8_eat ? j + 1 :
6184 i == Ylenses_eat ? j + 1 :
6185 i == Ymagnify_eat ? j + 1 :
6186 i == Ygrass_eat ? j + 1 :
6187 i == Ydirt_eat ? j + 1 :
6188 i == Xamoeba_1 ? 0 :
6189 i == Xamoeba_2 ? 1 :
6190 i == Xamoeba_3 ? 2 :
6191 i == Xamoeba_4 ? 3 :
6192 i == Xamoeba_5 ? 0 :
6193 i == Xamoeba_6 ? 1 :
6194 i == Xamoeba_7 ? 2 :
6195 i == Xamoeba_8 ? 3 :
6196 i == Xexit_2 ? j + 8 :
6197 i == Xexit_3 ? j + 16 :
6198 i == Xdynamite_1 ? 0 :
6199 i == Xdynamite_2 ? 8 :
6200 i == Xdynamite_3 ? 16 :
6201 i == Xdynamite_4 ? 24 :
6202 i == Xsand_stonein_1 ? j + 1 :
6203 i == Xsand_stonein_2 ? j + 9 :
6204 i == Xsand_stonein_3 ? j + 17 :
6205 i == Xsand_stonein_4 ? j + 25 :
6206 i == Xsand_stoneout_1 && j == 0 ? 0 :
6207 i == Xsand_stoneout_1 && j == 1 ? 0 :
6208 i == Xsand_stoneout_1 && j == 2 ? 1 :
6209 i == Xsand_stoneout_1 && j == 3 ? 2 :
6210 i == Xsand_stoneout_1 && j == 4 ? 2 :
6211 i == Xsand_stoneout_1 && j == 5 ? 3 :
6212 i == Xsand_stoneout_1 && j == 6 ? 4 :
6213 i == Xsand_stoneout_1 && j == 7 ? 4 :
6214 i == Xsand_stoneout_2 && j == 0 ? 5 :
6215 i == Xsand_stoneout_2 && j == 1 ? 6 :
6216 i == Xsand_stoneout_2 && j == 2 ? 7 :
6217 i == Xsand_stoneout_2 && j == 3 ? 8 :
6218 i == Xsand_stoneout_2 && j == 4 ? 9 :
6219 i == Xsand_stoneout_2 && j == 5 ? 11 :
6220 i == Xsand_stoneout_2 && j == 6 ? 13 :
6221 i == Xsand_stoneout_2 && j == 7 ? 15 :
6222 i == Xboom_bug && j == 1 ? 2 :
6223 i == Xboom_bug && j == 2 ? 2 :
6224 i == Xboom_bug && j == 3 ? 4 :
6225 i == Xboom_bug && j == 4 ? 4 :
6226 i == Xboom_bug && j == 5 ? 2 :
6227 i == Xboom_bug && j == 6 ? 2 :
6228 i == Xboom_bug && j == 7 ? 0 :
6229 i == Xboom_bomb && j == 1 ? 2 :
6230 i == Xboom_bomb && j == 2 ? 2 :
6231 i == Xboom_bomb && j == 3 ? 4 :
6232 i == Xboom_bomb && j == 4 ? 4 :
6233 i == Xboom_bomb && j == 5 ? 2 :
6234 i == Xboom_bomb && j == 6 ? 2 :
6235 i == Xboom_bomb && j == 7 ? 0 :
6236 i == Xboom_android && j == 7 ? 6 :
6237 i == Xboom_1 && j == 1 ? 2 :
6238 i == Xboom_1 && j == 2 ? 2 :
6239 i == Xboom_1 && j == 3 ? 4 :
6240 i == Xboom_1 && j == 4 ? 4 :
6241 i == Xboom_1 && j == 5 ? 6 :
6242 i == Xboom_1 && j == 6 ? 6 :
6243 i == Xboom_1 && j == 7 ? 8 :
6244 i == Xboom_2 && j == 0 ? 8 :
6245 i == Xboom_2 && j == 1 ? 8 :
6246 i == Xboom_2 && j == 2 ? 10 :
6247 i == Xboom_2 && j == 3 ? 10 :
6248 i == Xboom_2 && j == 4 ? 10 :
6249 i == Xboom_2 && j == 5 ? 12 :
6250 i == Xboom_2 && j == 6 ? 12 :
6251 i == Xboom_2 && j == 7 ? 12 :
6252 special_animation && j == 4 ? 3 :
6253 effective_action != action ? 0 :
6257 Bitmap *debug_bitmap = g_em->bitmap;
6258 int debug_src_x = g_em->src_x;
6259 int debug_src_y = g_em->src_y;
6262 int frame = getAnimationFrame(g->anim_frames,
6265 g->anim_start_frame,
6268 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6269 g->double_movement && is_backside);
6271 g_em->bitmap = src_bitmap;
6272 g_em->src_x = src_x;
6273 g_em->src_y = src_y;
6274 g_em->src_offset_x = 0;
6275 g_em->src_offset_y = 0;
6276 g_em->dst_offset_x = 0;
6277 g_em->dst_offset_y = 0;
6278 g_em->width = TILEX;
6279 g_em->height = TILEY;
6281 g_em->crumbled_bitmap = NULL;
6282 g_em->crumbled_src_x = 0;
6283 g_em->crumbled_src_y = 0;
6284 g_em->crumbled_border_size = 0;
6286 g_em->has_crumbled_graphics = FALSE;
6287 g_em->preserve_background = FALSE;
6290 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6291 printf("::: empty crumbled: %d [%s], %d, %d\n",
6292 effective_element, element_info[effective_element].token_name,
6293 effective_action, direction);
6296 /* if element can be crumbled, but certain action graphics are just empty
6297 space (like snapping sand with the original R'n'D graphics), do not
6298 treat these empty space graphics as crumbled graphics in EMC engine */
6299 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6301 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6303 g_em->has_crumbled_graphics = TRUE;
6304 g_em->crumbled_bitmap = src_bitmap;
6305 g_em->crumbled_src_x = src_x;
6306 g_em->crumbled_src_y = src_y;
6307 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6311 if (element == EL_ROCK &&
6312 effective_action == ACTION_FILLING)
6313 printf("::: has_action_graphics == %d\n", has_action_graphics);
6316 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6317 effective_action == ACTION_MOVING ||
6318 effective_action == ACTION_PUSHING ||
6319 effective_action == ACTION_EATING)) ||
6320 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6321 effective_action == ACTION_EMPTYING)))
6324 (effective_action == ACTION_FALLING ||
6325 effective_action == ACTION_FILLING ||
6326 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6327 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6328 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6329 int num_steps = (i == Ydrip_s1 ? 16 :
6330 i == Ydrip_s1B ? 16 :
6331 i == Ydrip_s2 ? 16 :
6332 i == Ydrip_s2B ? 16 :
6333 i == Xsand_stonein_1 ? 32 :
6334 i == Xsand_stonein_2 ? 32 :
6335 i == Xsand_stonein_3 ? 32 :
6336 i == Xsand_stonein_4 ? 32 :
6337 i == Xsand_stoneout_1 ? 16 :
6338 i == Xsand_stoneout_2 ? 16 : 8);
6339 int cx = ABS(dx) * (TILEX / num_steps);
6340 int cy = ABS(dy) * (TILEY / num_steps);
6341 int step_frame = (i == Ydrip_s2 ? j + 8 :
6342 i == Ydrip_s2B ? j + 8 :
6343 i == Xsand_stonein_2 ? j + 8 :
6344 i == Xsand_stonein_3 ? j + 16 :
6345 i == Xsand_stonein_4 ? j + 24 :
6346 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6347 int step = (is_backside ? step_frame : num_steps - step_frame);
6349 if (is_backside) /* tile where movement starts */
6351 if (dx < 0 || dy < 0)
6353 g_em->src_offset_x = cx * step;
6354 g_em->src_offset_y = cy * step;
6358 g_em->dst_offset_x = cx * step;
6359 g_em->dst_offset_y = cy * step;
6362 else /* tile where movement ends */
6364 if (dx < 0 || dy < 0)
6366 g_em->dst_offset_x = cx * step;
6367 g_em->dst_offset_y = cy * step;
6371 g_em->src_offset_x = cx * step;
6372 g_em->src_offset_y = cy * step;
6376 g_em->width = TILEX - cx * step;
6377 g_em->height = TILEY - cy * step;
6380 /* create unique graphic identifier to decide if tile must be redrawn */
6381 /* bit 31 - 16 (16 bit): EM style graphic
6382 bit 15 - 12 ( 4 bit): EM style frame
6383 bit 11 - 6 ( 6 bit): graphic width
6384 bit 5 - 0 ( 6 bit): graphic height */
6385 g_em->unique_identifier =
6386 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6390 /* skip check for EMC elements not contained in original EMC artwork */
6391 if (element == EL_EMC_FAKE_ACID)
6394 if (g_em->bitmap != debug_bitmap ||
6395 g_em->src_x != debug_src_x ||
6396 g_em->src_y != debug_src_y ||
6397 g_em->src_offset_x != 0 ||
6398 g_em->src_offset_y != 0 ||
6399 g_em->dst_offset_x != 0 ||
6400 g_em->dst_offset_y != 0 ||
6401 g_em->width != TILEX ||
6402 g_em->height != TILEY)
6404 static int last_i = -1;
6412 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6413 i, element, element_info[element].token_name,
6414 element_action_info[effective_action].suffix, direction);
6416 if (element != effective_element)
6417 printf(" [%d ('%s')]",
6419 element_info[effective_element].token_name);
6423 if (g_em->bitmap != debug_bitmap)
6424 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6425 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6427 if (g_em->src_x != debug_src_x ||
6428 g_em->src_y != debug_src_y)
6429 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6430 j, (is_backside ? 'B' : 'F'),
6431 g_em->src_x, g_em->src_y,
6432 g_em->src_x / 32, g_em->src_y / 32,
6433 debug_src_x, debug_src_y,
6434 debug_src_x / 32, debug_src_y / 32);
6436 if (g_em->src_offset_x != 0 ||
6437 g_em->src_offset_y != 0 ||
6438 g_em->dst_offset_x != 0 ||
6439 g_em->dst_offset_y != 0)
6440 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6442 g_em->src_offset_x, g_em->src_offset_y,
6443 g_em->dst_offset_x, g_em->dst_offset_y);
6445 if (g_em->width != TILEX ||
6446 g_em->height != TILEY)
6447 printf(" %d (%d): size %d,%d should be %d,%d\n",
6449 g_em->width, g_em->height, TILEX, TILEY);
6451 num_em_gfx_errors++;
6458 for (i = 0; i < TILE_MAX; i++)
6460 for (j = 0; j < 8; j++)
6462 int element = object_mapping[i].element_rnd;
6463 int action = object_mapping[i].action;
6464 int direction = object_mapping[i].direction;
6465 boolean is_backside = object_mapping[i].is_backside;
6466 int graphic_action = el_act_dir2img(element, action, direction);
6467 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6469 if ((action == ACTION_SMASHED_BY_ROCK ||
6470 action == ACTION_SMASHED_BY_SPRING ||
6471 action == ACTION_EATING) &&
6472 graphic_action == graphic_default)
6474 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6475 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6476 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6477 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6480 /* no separate animation for "smashed by rock" -- use rock instead */
6481 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6482 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6484 g_em->bitmap = g_xx->bitmap;
6485 g_em->src_x = g_xx->src_x;
6486 g_em->src_y = g_xx->src_y;
6487 g_em->src_offset_x = g_xx->src_offset_x;
6488 g_em->src_offset_y = g_xx->src_offset_y;
6489 g_em->dst_offset_x = g_xx->dst_offset_x;
6490 g_em->dst_offset_y = g_xx->dst_offset_y;
6491 g_em->width = g_xx->width;
6492 g_em->height = g_xx->height;
6493 g_em->unique_identifier = g_xx->unique_identifier;
6496 g_em->preserve_background = TRUE;
6501 for (p = 0; p < MAX_PLAYERS; p++)
6503 for (i = 0; i < SPR_MAX; i++)
6505 int element = player_mapping[p][i].element_rnd;
6506 int action = player_mapping[p][i].action;
6507 int direction = player_mapping[p][i].direction;
6509 for (j = 0; j < 8; j++)
6511 int effective_element = element;
6512 int effective_action = action;
6513 int graphic = (direction == MV_NONE ?
6514 el_act2img(effective_element, effective_action) :
6515 el_act_dir2img(effective_element, effective_action,
6517 struct GraphicInfo *g = &graphic_info[graphic];
6518 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6524 Bitmap *debug_bitmap = g_em->bitmap;
6525 int debug_src_x = g_em->src_x;
6526 int debug_src_y = g_em->src_y;
6529 int frame = getAnimationFrame(g->anim_frames,
6532 g->anim_start_frame,
6535 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6537 g_em->bitmap = src_bitmap;
6538 g_em->src_x = src_x;
6539 g_em->src_y = src_y;
6540 g_em->src_offset_x = 0;
6541 g_em->src_offset_y = 0;
6542 g_em->dst_offset_x = 0;
6543 g_em->dst_offset_y = 0;
6544 g_em->width = TILEX;
6545 g_em->height = TILEY;
6549 /* skip check for EMC elements not contained in original EMC artwork */
6550 if (element == EL_PLAYER_3 ||
6551 element == EL_PLAYER_4)
6554 if (g_em->bitmap != debug_bitmap ||
6555 g_em->src_x != debug_src_x ||
6556 g_em->src_y != debug_src_y)
6558 static int last_i = -1;
6566 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6567 p, i, element, element_info[element].token_name,
6568 element_action_info[effective_action].suffix, direction);
6570 if (element != effective_element)
6571 printf(" [%d ('%s')]",
6573 element_info[effective_element].token_name);
6577 if (g_em->bitmap != debug_bitmap)
6578 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6579 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6581 if (g_em->src_x != debug_src_x ||
6582 g_em->src_y != debug_src_y)
6583 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6585 g_em->src_x, g_em->src_y,
6586 g_em->src_x / 32, g_em->src_y / 32,
6587 debug_src_x, debug_src_y,
6588 debug_src_x / 32, debug_src_y / 32);
6590 num_em_gfx_errors++;
6600 printf("::: [%d errors found]\n", num_em_gfx_errors);
6606 void PlayMenuSoundExt(int sound)
6608 if (sound == SND_UNDEFINED)
6611 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6612 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6615 if (IS_LOOP_SOUND(sound))
6616 PlaySoundLoop(sound);
6621 void PlayMenuSound()
6623 PlayMenuSoundExt(menu.sound[game_status]);
6626 void PlayMenuSoundStereo(int sound, int stereo_position)
6628 if (sound == SND_UNDEFINED)
6631 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6632 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6635 if (IS_LOOP_SOUND(sound))
6636 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6638 PlaySoundStereo(sound, stereo_position);
6641 void PlayMenuSoundIfLoopExt(int sound)
6643 if (sound == SND_UNDEFINED)
6646 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6647 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6650 if (IS_LOOP_SOUND(sound))
6651 PlaySoundLoop(sound);
6654 void PlayMenuSoundIfLoop()
6656 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6659 void PlayMenuMusicExt(int music)
6661 if (music == MUS_UNDEFINED)
6664 if (!setup.sound_music)
6670 void PlayMenuMusic()
6672 PlayMenuMusicExt(menu.music[game_status]);
6675 void PlaySoundActivating()
6678 PlaySound(SND_MENU_ITEM_ACTIVATING);
6682 void PlaySoundSelecting()
6685 PlaySound(SND_MENU_ITEM_SELECTING);
6689 void ToggleFullscreenIfNeeded()
6691 boolean change_fullscreen = (setup.fullscreen !=
6692 video.fullscreen_enabled);
6693 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6694 !strEqual(setup.fullscreen_mode,
6695 video.fullscreen_mode_current));
6697 if (!video.fullscreen_available)
6701 if (change_fullscreen || change_fullscreen_mode)
6703 if (setup.fullscreen != video.fullscreen_enabled ||
6704 setup.fullscreen_mode != video.fullscreen_mode_current)
6707 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6709 /* save backbuffer content which gets lost when toggling fullscreen mode */
6710 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6713 if (change_fullscreen_mode)
6715 if (setup.fullscreen && video.fullscreen_enabled)
6718 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6720 /* (this is now set in sdl.c) */
6722 video.fullscreen_mode_current = setup.fullscreen_mode;
6724 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6727 /* toggle fullscreen */
6728 ChangeVideoModeIfNeeded(setup.fullscreen);
6730 setup.fullscreen = video.fullscreen_enabled;
6732 /* restore backbuffer content from temporary backbuffer backup bitmap */
6733 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6735 FreeBitmap(tmp_backbuffer);
6738 /* update visible window/screen */
6739 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6741 redraw_mask = REDRAW_ALL;