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 void FadeSetEnterMenu()
667 fading = menu.enter_menu;
670 void FadeSetLeaveMenu()
672 fading = menu.leave_menu;
675 void FadeSetStartItem()
677 fading = menu.start_item;
680 void FadeSetFromType(int type)
682 if (type & TYPE_ENTER_SCREEN)
684 else if (type & TYPE_ENTER)
686 else if (type & TYPE_LEAVE)
690 void FadeSetDisabled()
692 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
694 fading = fading_none;
697 void FadeSkipNextFadeIn()
699 FadeExt(0, FADE_MODE_SKIP_FADE_IN);
702 void FadeSkipNextFadeOut()
704 FadeExt(0, FADE_MODE_SKIP_FADE_OUT);
707 void SetWindowBackgroundImageIfDefined(int graphic)
709 if (graphic_info[graphic].bitmap)
710 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
713 void SetMainBackgroundImageIfDefined(int graphic)
715 if (graphic_info[graphic].bitmap)
716 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
719 void SetDoorBackgroundImageIfDefined(int graphic)
721 if (graphic_info[graphic].bitmap)
722 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
725 void SetWindowBackgroundImage(int graphic)
727 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
728 graphic_info[graphic].bitmap ?
729 graphic_info[graphic].bitmap :
730 graphic_info[IMG_BACKGROUND].bitmap);
733 void SetMainBackgroundImage(int graphic)
735 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
736 graphic_info[graphic].bitmap ?
737 graphic_info[graphic].bitmap :
738 graphic_info[IMG_BACKGROUND].bitmap);
741 void SetDoorBackgroundImage(int graphic)
743 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
744 graphic_info[graphic].bitmap ?
745 graphic_info[graphic].bitmap :
746 graphic_info[IMG_BACKGROUND].bitmap);
749 void SetPanelBackground()
751 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
752 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
754 SetDoorBackgroundBitmap(bitmap_db_panel);
757 void DrawBackground(int x, int y, int width, int height)
759 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
760 /* (when entering hall of fame after playing) */
762 ClearRectangleOnBackground(drawto, x, y, width, height);
764 ClearRectangleOnBackground(backbuffer, x, y, width, height);
767 redraw_mask |= REDRAW_FIELD;
770 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
772 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
774 if (font->bitmap == NULL)
777 DrawBackground(x, y, width, height);
780 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
782 struct GraphicInfo *g = &graphic_info[graphic];
784 if (g->bitmap == NULL)
787 DrawBackground(x, y, width, height);
792 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
793 /* (when entering hall of fame after playing) */
794 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
796 /* !!! maybe this should be done before clearing the background !!! */
797 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
799 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
800 SetDrawtoField(DRAW_BUFFERED);
803 SetDrawtoField(DRAW_BACKBUFFER);
805 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
807 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
808 SetDrawtoField(DRAW_DIRECT);
812 void MarkTileDirty(int x, int y)
814 int xx = redraw_x1 + x;
815 int yy = redraw_y1 + y;
820 redraw[xx][yy] = TRUE;
821 redraw_mask |= REDRAW_TILES;
824 void SetBorderElement()
828 BorderElement = EL_EMPTY;
830 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
832 for (x = 0; x < lev_fieldx; x++)
834 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
835 BorderElement = EL_STEELWALL;
837 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
843 void FloodFillLevel(int from_x, int from_y, int fill_element,
844 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
845 int max_fieldx, int max_fieldy)
849 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
850 static int safety = 0;
852 /* check if starting field still has the desired content */
853 if (field[from_x][from_y] == fill_element)
858 if (safety > max_fieldx * max_fieldy)
859 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
861 old_element = field[from_x][from_y];
862 field[from_x][from_y] = fill_element;
864 for (i = 0; i < 4; i++)
866 x = from_x + check[i][0];
867 y = from_y + check[i][1];
869 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
870 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
876 void SetRandomAnimationValue(int x, int y)
878 gfx.anim_random_frame = GfxRandom[x][y];
881 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
883 /* animation synchronized with global frame counter, not move position */
884 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
885 sync_frame = FrameCounter;
887 return getAnimationFrame(graphic_info[graphic].anim_frames,
888 graphic_info[graphic].anim_delay,
889 graphic_info[graphic].anim_mode,
890 graphic_info[graphic].anim_start_frame,
894 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
895 int *x, int *y, boolean get_backside)
897 struct GraphicInfo *g = &graphic_info[graphic];
898 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
899 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
903 if (g->offset_y == 0) /* frames are ordered horizontally */
905 int max_width = g->anim_frames_per_line * g->width;
906 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
908 *x = pos % max_width;
909 *y = src_y % g->height + pos / max_width * g->height;
911 else if (g->offset_x == 0) /* frames are ordered vertically */
913 int max_height = g->anim_frames_per_line * g->height;
914 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
916 *x = src_x % g->width + pos / max_height * g->width;
917 *y = pos % max_height;
919 else /* frames are ordered diagonally */
921 *x = src_x + frame * g->offset_x;
922 *y = src_y + frame * g->offset_y;
926 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
928 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
931 void DrawGraphic(int x, int y, int graphic, int frame)
934 if (!IN_SCR_FIELD(x, y))
936 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
937 printf("DrawGraphic(): This should never happen!\n");
942 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
946 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
952 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
953 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
956 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
959 if (!IN_SCR_FIELD(x, y))
961 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
962 printf("DrawGraphicThruMask(): This should never happen!\n");
967 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
972 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
978 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
980 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
981 dst_x - src_x, dst_y - src_y);
982 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
985 void DrawMiniGraphic(int x, int y, int graphic)
987 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
988 MarkTileDirty(x / 2, y / 2);
991 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
993 struct GraphicInfo *g = &graphic_info[graphic];
995 int mini_starty = g->bitmap->height * 2 / 3;
998 *x = mini_startx + g->src_x / 2;
999 *y = mini_starty + g->src_y / 2;
1002 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1007 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1008 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1011 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1012 int graphic, int frame,
1013 int cut_mode, int mask_mode)
1018 int width = TILEX, height = TILEY;
1021 if (dx || dy) /* shifted graphic */
1023 if (x < BX1) /* object enters playfield from the left */
1030 else if (x > BX2) /* object enters playfield from the right */
1036 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1042 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1044 else if (dx) /* general horizontal movement */
1045 MarkTileDirty(x + SIGN(dx), y);
1047 if (y < BY1) /* object enters playfield from the top */
1049 if (cut_mode==CUT_BELOW) /* object completely above top border */
1057 else if (y > BY2) /* object enters playfield from the bottom */
1063 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1069 else if (dy > 0 && cut_mode == CUT_ABOVE)
1071 if (y == BY2) /* object completely above bottom border */
1077 MarkTileDirty(x, y + 1);
1078 } /* object leaves playfield to the bottom */
1079 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1081 else if (dy) /* general vertical movement */
1082 MarkTileDirty(x, y + SIGN(dy));
1086 if (!IN_SCR_FIELD(x, y))
1088 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1089 printf("DrawGraphicShifted(): This should never happen!\n");
1094 if (width > 0 && height > 0)
1096 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1101 dst_x = FX + x * TILEX + dx;
1102 dst_y = FY + y * TILEY + dy;
1104 if (mask_mode == USE_MASKING)
1106 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1107 dst_x - src_x, dst_y - src_y);
1108 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1112 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1115 MarkTileDirty(x, y);
1119 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1120 int graphic, int frame,
1121 int cut_mode, int mask_mode)
1126 int width = TILEX, height = TILEY;
1129 int x2 = x + SIGN(dx);
1130 int y2 = y + SIGN(dy);
1131 int anim_frames = graphic_info[graphic].anim_frames;
1132 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1133 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1134 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1136 /* re-calculate animation frame for two-tile movement animation */
1137 frame = getGraphicAnimationFrame(graphic, sync_frame);
1139 /* check if movement start graphic inside screen area and should be drawn */
1140 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1142 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1144 dst_x = FX + x1 * TILEX;
1145 dst_y = FY + y1 * TILEY;
1147 if (mask_mode == USE_MASKING)
1149 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1150 dst_x - src_x, dst_y - src_y);
1151 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1155 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1158 MarkTileDirty(x1, y1);
1161 /* check if movement end graphic inside screen area and should be drawn */
1162 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1164 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1166 dst_x = FX + x2 * TILEX;
1167 dst_y = FY + y2 * TILEY;
1169 if (mask_mode == USE_MASKING)
1171 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1172 dst_x - src_x, dst_y - src_y);
1173 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1177 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1180 MarkTileDirty(x2, y2);
1184 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1185 int graphic, int frame,
1186 int cut_mode, int mask_mode)
1190 DrawGraphic(x, y, graphic, frame);
1195 if (graphic_info[graphic].double_movement) /* EM style movement images */
1196 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1198 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1201 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1202 int frame, int cut_mode)
1204 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1207 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1208 int cut_mode, int mask_mode)
1210 int lx = LEVELX(x), ly = LEVELY(y);
1214 if (IN_LEV_FIELD(lx, ly))
1216 SetRandomAnimationValue(lx, ly);
1218 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1219 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1221 /* do not use double (EM style) movement graphic when not moving */
1222 if (graphic_info[graphic].double_movement && !dx && !dy)
1224 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1225 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1228 else /* border element */
1230 graphic = el2img(element);
1231 frame = getGraphicAnimationFrame(graphic, -1);
1234 if (element == EL_EXPANDABLE_WALL)
1236 boolean left_stopped = FALSE, right_stopped = FALSE;
1238 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1239 left_stopped = TRUE;
1240 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1241 right_stopped = TRUE;
1243 if (left_stopped && right_stopped)
1245 else if (left_stopped)
1247 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1248 frame = graphic_info[graphic].anim_frames - 1;
1250 else if (right_stopped)
1252 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1253 frame = graphic_info[graphic].anim_frames - 1;
1258 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1259 else if (mask_mode == USE_MASKING)
1260 DrawGraphicThruMask(x, y, graphic, frame);
1262 DrawGraphic(x, y, graphic, frame);
1265 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1266 int cut_mode, int mask_mode)
1268 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1269 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1270 cut_mode, mask_mode);
1273 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1276 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1279 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1282 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1285 void DrawLevelElementThruMask(int x, int y, int element)
1287 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1290 void DrawLevelFieldThruMask(int x, int y)
1292 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1295 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1299 int sx = SCREENX(x), sy = SCREENY(y);
1301 int width, height, cx, cy, i;
1302 int crumbled_border_size = graphic_info[graphic].border_size;
1303 static int xy[4][2] =
1311 if (!IN_LEV_FIELD(x, y))
1314 element = TILE_GFX_ELEMENT(x, y);
1316 /* crumble field itself */
1317 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1319 if (!IN_SCR_FIELD(sx, sy))
1322 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1324 for (i = 0; i < 4; i++)
1326 int xx = x + xy[i][0];
1327 int yy = y + xy[i][1];
1329 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1332 /* check if neighbour field is of same type */
1333 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1336 if (i == 1 || i == 2)
1338 width = crumbled_border_size;
1340 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1346 height = crumbled_border_size;
1348 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1351 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1352 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1355 MarkTileDirty(sx, sy);
1357 else /* crumble neighbour fields */
1359 for (i = 0; i < 4; i++)
1361 int xx = x + xy[i][0];
1362 int yy = y + xy[i][1];
1363 int sxx = sx + xy[i][0];
1364 int syy = sy + xy[i][1];
1366 if (!IN_LEV_FIELD(xx, yy) ||
1367 !IN_SCR_FIELD(sxx, syy) ||
1371 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1374 element = TILE_GFX_ELEMENT(xx, yy);
1376 if (!GFX_CRUMBLED(element))
1379 graphic = el_act2crm(element, ACTION_DEFAULT);
1380 crumbled_border_size = graphic_info[graphic].border_size;
1382 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1384 if (i == 1 || i == 2)
1386 width = crumbled_border_size;
1388 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1394 height = crumbled_border_size;
1396 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1399 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1400 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1402 MarkTileDirty(sxx, syy);
1407 void DrawLevelFieldCrumbledSand(int x, int y)
1411 if (!IN_LEV_FIELD(x, y))
1415 /* !!! CHECK THIS !!! */
1418 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1419 GFX_CRUMBLED(GfxElement[x][y]))
1422 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1423 GfxElement[x][y] != EL_UNDEFINED &&
1424 GFX_CRUMBLED(GfxElement[x][y]))
1426 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1433 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1435 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1438 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1441 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1444 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1445 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1446 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1447 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1448 int sx = SCREENX(x), sy = SCREENY(y);
1450 DrawGraphic(sx, sy, graphic1, frame1);
1451 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1454 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1456 int sx = SCREENX(x), sy = SCREENY(y);
1457 static int xy[4][2] =
1466 for (i = 0; i < 4; i++)
1468 int xx = x + xy[i][0];
1469 int yy = y + xy[i][1];
1470 int sxx = sx + xy[i][0];
1471 int syy = sy + xy[i][1];
1473 if (!IN_LEV_FIELD(xx, yy) ||
1474 !IN_SCR_FIELD(sxx, syy) ||
1475 !GFX_CRUMBLED(Feld[xx][yy]) ||
1479 DrawLevelField(xx, yy);
1483 static int getBorderElement(int x, int y)
1487 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1488 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1489 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1490 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1491 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1492 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1493 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1495 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1496 int steel_position = (x == -1 && y == -1 ? 0 :
1497 x == lev_fieldx && y == -1 ? 1 :
1498 x == -1 && y == lev_fieldy ? 2 :
1499 x == lev_fieldx && y == lev_fieldy ? 3 :
1500 x == -1 || x == lev_fieldx ? 4 :
1501 y == -1 || y == lev_fieldy ? 5 : 6);
1503 return border[steel_position][steel_type];
1506 void DrawScreenElement(int x, int y, int element)
1508 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1509 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1512 void DrawLevelElement(int x, int y, int element)
1514 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1515 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1518 void DrawScreenField(int x, int y)
1520 int lx = LEVELX(x), ly = LEVELY(y);
1521 int element, content;
1523 if (!IN_LEV_FIELD(lx, ly))
1525 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1528 element = getBorderElement(lx, ly);
1530 DrawScreenElement(x, y, element);
1534 element = Feld[lx][ly];
1535 content = Store[lx][ly];
1537 if (IS_MOVING(lx, ly))
1539 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1540 boolean cut_mode = NO_CUTTING;
1542 if (element == EL_QUICKSAND_EMPTYING ||
1543 element == EL_QUICKSAND_FAST_EMPTYING ||
1544 element == EL_MAGIC_WALL_EMPTYING ||
1545 element == EL_BD_MAGIC_WALL_EMPTYING ||
1546 element == EL_DC_MAGIC_WALL_EMPTYING ||
1547 element == EL_AMOEBA_DROPPING)
1548 cut_mode = CUT_ABOVE;
1549 else if (element == EL_QUICKSAND_FILLING ||
1550 element == EL_QUICKSAND_FAST_FILLING ||
1551 element == EL_MAGIC_WALL_FILLING ||
1552 element == EL_BD_MAGIC_WALL_FILLING ||
1553 element == EL_DC_MAGIC_WALL_FILLING)
1554 cut_mode = CUT_BELOW;
1556 if (cut_mode == CUT_ABOVE)
1557 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1559 DrawScreenElement(x, y, EL_EMPTY);
1562 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1563 else if (cut_mode == NO_CUTTING)
1564 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1566 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1568 if (content == EL_ACID)
1570 int dir = MovDir[lx][ly];
1571 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1572 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1574 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1577 else if (IS_BLOCKED(lx, ly))
1582 boolean cut_mode = NO_CUTTING;
1583 int element_old, content_old;
1585 Blocked2Moving(lx, ly, &oldx, &oldy);
1588 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1589 MovDir[oldx][oldy] == MV_RIGHT);
1591 element_old = Feld[oldx][oldy];
1592 content_old = Store[oldx][oldy];
1594 if (element_old == EL_QUICKSAND_EMPTYING ||
1595 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1596 element_old == EL_MAGIC_WALL_EMPTYING ||
1597 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1598 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1599 element_old == EL_AMOEBA_DROPPING)
1600 cut_mode = CUT_ABOVE;
1602 DrawScreenElement(x, y, EL_EMPTY);
1605 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1607 else if (cut_mode == NO_CUTTING)
1608 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1611 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1614 else if (IS_DRAWABLE(element))
1615 DrawScreenElement(x, y, element);
1617 DrawScreenElement(x, y, EL_EMPTY);
1620 void DrawLevelField(int x, int y)
1622 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1623 DrawScreenField(SCREENX(x), SCREENY(y));
1624 else if (IS_MOVING(x, y))
1628 Moving2Blocked(x, y, &newx, &newy);
1629 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1630 DrawScreenField(SCREENX(newx), SCREENY(newy));
1632 else if (IS_BLOCKED(x, y))
1636 Blocked2Moving(x, y, &oldx, &oldy);
1637 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1638 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1642 void DrawMiniElement(int x, int y, int element)
1646 graphic = el2edimg(element);
1647 DrawMiniGraphic(x, y, graphic);
1650 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1652 int x = sx + scroll_x, y = sy + scroll_y;
1654 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1655 DrawMiniElement(sx, sy, EL_EMPTY);
1656 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1657 DrawMiniElement(sx, sy, Feld[x][y]);
1659 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1662 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1663 int x, int y, int xsize, int ysize, int font_nr)
1665 int font_width = getFontWidth(font_nr);
1666 int font_height = getFontHeight(font_nr);
1667 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1670 int dst_x = SX + startx + x * font_width;
1671 int dst_y = SY + starty + y * font_height;
1672 int width = graphic_info[graphic].width;
1673 int height = graphic_info[graphic].height;
1674 int inner_width = MAX(width - 2 * font_width, font_width);
1675 int inner_height = MAX(height - 2 * font_height, font_height);
1676 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1677 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1678 boolean draw_masked = graphic_info[graphic].draw_masked;
1680 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1682 if (src_bitmap == NULL || width < font_width || height < font_height)
1684 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1688 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1689 inner_sx + (x - 1) * font_width % inner_width);
1690 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1691 inner_sy + (y - 1) * font_height % inner_height);
1695 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1696 dst_x - src_x, dst_y - src_y);
1697 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1701 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1705 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1707 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1708 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1709 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1710 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1711 boolean no_delay = (tape.warp_forward);
1712 unsigned long anim_delay = 0;
1713 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1714 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1715 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1716 int font_width = getFontWidth(font_nr);
1717 int font_height = getFontHeight(font_nr);
1718 int max_xsize = level.envelope[envelope_nr].xsize;
1719 int max_ysize = level.envelope[envelope_nr].ysize;
1720 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1721 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1722 int xend = max_xsize;
1723 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1724 int xstep = (xstart < xend ? 1 : 0);
1725 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1728 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1730 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1731 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1732 int sx = (SXSIZE - xsize * font_width) / 2;
1733 int sy = (SYSIZE - ysize * font_height) / 2;
1736 SetDrawtoField(DRAW_BUFFERED);
1738 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1740 SetDrawtoField(DRAW_BACKBUFFER);
1742 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1743 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1746 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1747 level.envelope[envelope_nr].text, font_nr, max_xsize,
1748 xsize - 2, ysize - 2, mask_mode,
1749 level.envelope[envelope_nr].autowrap,
1750 level.envelope[envelope_nr].centered, FALSE);
1752 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1753 level.envelope[envelope_nr].text, font_nr, max_xsize,
1754 xsize - 2, ysize - 2, mask_mode);
1757 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1760 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1764 void ShowEnvelope(int envelope_nr)
1766 int element = EL_ENVELOPE_1 + envelope_nr;
1767 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1768 int sound_opening = element_info[element].sound[ACTION_OPENING];
1769 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1770 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1771 boolean no_delay = (tape.warp_forward);
1772 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1773 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1774 int anim_mode = graphic_info[graphic].anim_mode;
1775 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1776 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1778 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1780 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1782 if (anim_mode == ANIM_DEFAULT)
1783 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1785 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1788 Delay(wait_delay_value);
1790 WaitForEventToContinue();
1792 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1794 if (anim_mode != ANIM_NONE)
1795 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1797 if (anim_mode == ANIM_DEFAULT)
1798 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1800 game.envelope_active = FALSE;
1802 SetDrawtoField(DRAW_BUFFERED);
1804 redraw_mask |= REDRAW_FIELD;
1808 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1813 int width_mult, width_div;
1814 int height_mult, height_div;
1832 int offset_calc_pos = (tilesize < MICRO_TILESIZE / 4 ||
1833 tilesize > TILESIZE ? 5 : 5 - log_2(tilesize));
1835 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1836 5 - log_2(tilesize));
1838 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1839 int width_mult = offset_calc[offset_calc_pos].width_mult;
1840 int width_div = offset_calc[offset_calc_pos].width_div;
1841 int height_mult = offset_calc[offset_calc_pos].height_mult;
1842 int height_div = offset_calc[offset_calc_pos].height_div;
1843 int mini_startx = src_bitmap->width * width_mult / width_div;
1844 int mini_starty = src_bitmap->height * height_mult / height_div;
1845 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1846 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1848 *bitmap = src_bitmap;
1853 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1857 int graphic = el2preimg(element);
1859 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1860 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1867 SetDrawBackgroundMask(REDRAW_NONE);
1870 for (x = BX1; x <= BX2; x++)
1871 for (y = BY1; y <= BY2; y++)
1872 DrawScreenField(x, y);
1874 redraw_mask |= REDRAW_FIELD;
1877 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1881 for (x = 0; x < size_x; x++)
1882 for (y = 0; y < size_y; y++)
1883 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1885 redraw_mask |= REDRAW_FIELD;
1888 static void DrawPreviewLevelExt(int from_x, int from_y)
1890 boolean show_level_border = (BorderElement != EL_EMPTY);
1891 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1892 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1893 int tile_size = preview.tile_size;
1894 int preview_width = preview.xsize * tile_size;
1895 int preview_height = preview.ysize * tile_size;
1896 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1897 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1898 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1899 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1902 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1904 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1905 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1907 for (x = 0; x < real_preview_xsize; x++)
1909 for (y = 0; y < real_preview_ysize; y++)
1911 int lx = from_x + x + (show_level_border ? -1 : 0);
1912 int ly = from_y + y + (show_level_border ? -1 : 0);
1913 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1914 getBorderElement(lx, ly));
1916 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1917 element, tile_size);
1921 redraw_mask |= REDRAW_MICROLEVEL;
1924 #define MICROLABEL_EMPTY 0
1925 #define MICROLABEL_LEVEL_NAME 1
1926 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1927 #define MICROLABEL_LEVEL_AUTHOR 3
1928 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1929 #define MICROLABEL_IMPORTED_FROM 5
1930 #define MICROLABEL_IMPORTED_BY_HEAD 6
1931 #define MICROLABEL_IMPORTED_BY 7
1933 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
1935 int max_text_width = SXSIZE;
1936 int font_width = getFontWidth(font_nr);
1938 if (pos->align == ALIGN_CENTER)
1939 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1940 else if (pos->align == ALIGN_RIGHT)
1941 max_text_width = pos->x;
1943 max_text_width = SXSIZE - pos->x;
1945 return max_text_width / font_width;
1948 static void DrawPreviewLevelLabelExt(int mode)
1950 struct TextPosInfo *pos = &menu.main.text.level_info_2;
1951 char label_text[MAX_OUTPUT_LINESIZE + 1];
1952 int max_len_label_text;
1954 int font_nr = pos->font;
1957 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1958 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1959 mode == MICROLABEL_IMPORTED_BY_HEAD)
1960 font_nr = pos->font_alt;
1962 int font_nr = FONT_TEXT_2;
1965 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1966 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1967 mode == MICROLABEL_IMPORTED_BY_HEAD)
1968 font_nr = FONT_TEXT_3;
1972 max_len_label_text = getMaxTextLength(pos, font_nr);
1974 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1978 if (pos->chars != -1)
1979 max_len_label_text = pos->chars;
1982 for (i = 0; i < max_len_label_text; i++)
1983 label_text[i] = ' ';
1984 label_text[max_len_label_text] = '\0';
1986 if (strlen(label_text) > 0)
1989 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1991 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1992 int lypos = MICROLABEL2_YPOS;
1994 DrawText(lxpos, lypos, label_text, font_nr);
1999 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2000 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2001 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2002 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2003 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2004 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2005 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2006 max_len_label_text);
2007 label_text[max_len_label_text] = '\0';
2009 if (strlen(label_text) > 0)
2012 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2014 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2015 int lypos = MICROLABEL2_YPOS;
2017 DrawText(lxpos, lypos, label_text, font_nr);
2021 redraw_mask |= REDRAW_MICROLEVEL;
2024 void DrawPreviewLevel(boolean restart)
2026 static unsigned long scroll_delay = 0;
2027 static unsigned long label_delay = 0;
2028 static int from_x, from_y, scroll_direction;
2029 static int label_state, label_counter;
2030 unsigned long scroll_delay_value = preview.step_delay;
2031 boolean show_level_border = (BorderElement != EL_EMPTY);
2032 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2033 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2034 int last_game_status = game_status; /* save current game status */
2037 /* force PREVIEW font on preview level */
2038 game_status = GAME_MODE_PSEUDO_PREVIEW;
2046 if (preview.anim_mode == ANIM_CENTERED)
2048 if (level_xsize > preview.xsize)
2049 from_x = (level_xsize - preview.xsize) / 2;
2050 if (level_ysize > preview.ysize)
2051 from_y = (level_ysize - preview.ysize) / 2;
2054 from_x += preview.xoffset;
2055 from_y += preview.yoffset;
2057 scroll_direction = MV_RIGHT;
2061 DrawPreviewLevelExt(from_x, from_y);
2062 DrawPreviewLevelLabelExt(label_state);
2064 /* initialize delay counters */
2065 DelayReached(&scroll_delay, 0);
2066 DelayReached(&label_delay, 0);
2068 if (leveldir_current->name)
2070 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2071 char label_text[MAX_OUTPUT_LINESIZE + 1];
2073 int font_nr = pos->font;
2075 int font_nr = FONT_TEXT_1;
2078 int max_len_label_text = getMaxTextLength(pos, font_nr);
2080 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2088 if (pos->chars != -1)
2089 max_len_label_text = pos->chars;
2092 strncpy(label_text, leveldir_current->name, max_len_label_text);
2093 label_text[max_len_label_text] = '\0';
2096 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2098 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2099 lypos = SY + MICROLABEL1_YPOS;
2101 DrawText(lxpos, lypos, label_text, font_nr);
2105 game_status = last_game_status; /* restore current game status */
2110 /* scroll preview level, if needed */
2111 if (preview.anim_mode != ANIM_NONE &&
2112 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2113 DelayReached(&scroll_delay, scroll_delay_value))
2115 switch (scroll_direction)
2120 from_x -= preview.step_offset;
2121 from_x = (from_x < 0 ? 0 : from_x);
2124 scroll_direction = MV_UP;
2128 if (from_x < level_xsize - preview.xsize)
2130 from_x += preview.step_offset;
2131 from_x = (from_x > level_xsize - preview.xsize ?
2132 level_xsize - preview.xsize : from_x);
2135 scroll_direction = MV_DOWN;
2141 from_y -= preview.step_offset;
2142 from_y = (from_y < 0 ? 0 : from_y);
2145 scroll_direction = MV_RIGHT;
2149 if (from_y < level_ysize - preview.ysize)
2151 from_y += preview.step_offset;
2152 from_y = (from_y > level_ysize - preview.ysize ?
2153 level_ysize - preview.ysize : from_y);
2156 scroll_direction = MV_LEFT;
2163 DrawPreviewLevelExt(from_x, from_y);
2166 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2167 /* redraw micro level label, if needed */
2168 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2169 !strEqual(level.author, ANONYMOUS_NAME) &&
2170 !strEqual(level.author, leveldir_current->name) &&
2171 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2173 int max_label_counter = 23;
2175 if (leveldir_current->imported_from != NULL &&
2176 strlen(leveldir_current->imported_from) > 0)
2177 max_label_counter += 14;
2178 if (leveldir_current->imported_by != NULL &&
2179 strlen(leveldir_current->imported_by) > 0)
2180 max_label_counter += 14;
2182 label_counter = (label_counter + 1) % max_label_counter;
2183 label_state = (label_counter >= 0 && label_counter <= 7 ?
2184 MICROLABEL_LEVEL_NAME :
2185 label_counter >= 9 && label_counter <= 12 ?
2186 MICROLABEL_LEVEL_AUTHOR_HEAD :
2187 label_counter >= 14 && label_counter <= 21 ?
2188 MICROLABEL_LEVEL_AUTHOR :
2189 label_counter >= 23 && label_counter <= 26 ?
2190 MICROLABEL_IMPORTED_FROM_HEAD :
2191 label_counter >= 28 && label_counter <= 35 ?
2192 MICROLABEL_IMPORTED_FROM :
2193 label_counter >= 37 && label_counter <= 40 ?
2194 MICROLABEL_IMPORTED_BY_HEAD :
2195 label_counter >= 42 && label_counter <= 49 ?
2196 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2198 if (leveldir_current->imported_from == NULL &&
2199 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2200 label_state == MICROLABEL_IMPORTED_FROM))
2201 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2202 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2204 DrawPreviewLevelLabelExt(label_state);
2207 game_status = last_game_status; /* restore current game status */
2210 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2211 int graphic, int sync_frame, int mask_mode)
2213 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2215 if (mask_mode == USE_MASKING)
2216 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2218 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2221 inline void DrawGraphicAnimation(int x, int y, int graphic)
2223 int lx = LEVELX(x), ly = LEVELY(y);
2225 if (!IN_SCR_FIELD(x, y))
2228 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2229 graphic, GfxFrame[lx][ly], NO_MASKING);
2230 MarkTileDirty(x, y);
2233 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2235 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2238 void DrawLevelElementAnimation(int x, int y, int element)
2240 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2242 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2245 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2247 int sx = SCREENX(x), sy = SCREENY(y);
2249 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2252 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2255 DrawGraphicAnimation(sx, sy, graphic);
2258 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2259 DrawLevelFieldCrumbledSand(x, y);
2261 if (GFX_CRUMBLED(Feld[x][y]))
2262 DrawLevelFieldCrumbledSand(x, y);
2266 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2268 int sx = SCREENX(x), sy = SCREENY(y);
2271 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2274 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2276 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2279 DrawGraphicAnimation(sx, sy, graphic);
2281 if (GFX_CRUMBLED(element))
2282 DrawLevelFieldCrumbledSand(x, y);
2285 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2287 if (player->use_murphy)
2289 /* this works only because currently only one player can be "murphy" ... */
2290 static int last_horizontal_dir = MV_LEFT;
2291 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2293 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2294 last_horizontal_dir = move_dir;
2296 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2298 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2300 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2306 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2309 static boolean equalGraphics(int graphic1, int graphic2)
2311 struct GraphicInfo *g1 = &graphic_info[graphic1];
2312 struct GraphicInfo *g2 = &graphic_info[graphic2];
2314 return (g1->bitmap == g2->bitmap &&
2315 g1->src_x == g2->src_x &&
2316 g1->src_y == g2->src_y &&
2317 g1->anim_frames == g2->anim_frames &&
2318 g1->anim_delay == g2->anim_delay &&
2319 g1->anim_mode == g2->anim_mode);
2322 void DrawAllPlayers()
2326 for (i = 0; i < MAX_PLAYERS; i++)
2327 if (stored_player[i].active)
2328 DrawPlayer(&stored_player[i]);
2331 void DrawPlayerField(int x, int y)
2333 if (!IS_PLAYER(x, y))
2336 DrawPlayer(PLAYERINFO(x, y));
2339 void DrawPlayer(struct PlayerInfo *player)
2341 int jx = player->jx;
2342 int jy = player->jy;
2343 int move_dir = player->MovDir;
2344 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2345 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2346 int last_jx = (player->is_moving ? jx - dx : jx);
2347 int last_jy = (player->is_moving ? jy - dy : jy);
2348 int next_jx = jx + dx;
2349 int next_jy = jy + dy;
2350 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2351 boolean player_is_opaque = FALSE;
2352 int sx = SCREENX(jx), sy = SCREENY(jy);
2353 int sxx = 0, syy = 0;
2354 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2356 int action = ACTION_DEFAULT;
2357 int last_player_graphic = getPlayerGraphic(player, move_dir);
2358 int last_player_frame = player->Frame;
2361 /* GfxElement[][] is set to the element the player is digging or collecting;
2362 remove also for off-screen player if the player is not moving anymore */
2363 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2364 GfxElement[jx][jy] = EL_UNDEFINED;
2366 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2370 if (!IN_LEV_FIELD(jx, jy))
2372 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2373 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2374 printf("DrawPlayerField(): This should never happen!\n");
2379 if (element == EL_EXPLOSION)
2382 action = (player->is_pushing ? ACTION_PUSHING :
2383 player->is_digging ? ACTION_DIGGING :
2384 player->is_collecting ? ACTION_COLLECTING :
2385 player->is_moving ? ACTION_MOVING :
2386 player->is_snapping ? ACTION_SNAPPING :
2387 player->is_dropping ? ACTION_DROPPING :
2388 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2390 if (player->is_waiting)
2391 move_dir = player->dir_waiting;
2393 InitPlayerGfxAnimation(player, action, move_dir);
2395 /* ----------------------------------------------------------------------- */
2396 /* draw things in the field the player is leaving, if needed */
2397 /* ----------------------------------------------------------------------- */
2399 if (player->is_moving)
2401 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2403 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2405 if (last_element == EL_DYNAMITE_ACTIVE ||
2406 last_element == EL_EM_DYNAMITE_ACTIVE ||
2407 last_element == EL_SP_DISK_RED_ACTIVE)
2408 DrawDynamite(last_jx, last_jy);
2410 DrawLevelFieldThruMask(last_jx, last_jy);
2412 else if (last_element == EL_DYNAMITE_ACTIVE ||
2413 last_element == EL_EM_DYNAMITE_ACTIVE ||
2414 last_element == EL_SP_DISK_RED_ACTIVE)
2415 DrawDynamite(last_jx, last_jy);
2417 /* !!! this is not enough to prevent flickering of players which are
2418 moving next to each others without a free tile between them -- this
2419 can only be solved by drawing all players layer by layer (first the
2420 background, then the foreground etc.) !!! => TODO */
2421 else if (!IS_PLAYER(last_jx, last_jy))
2422 DrawLevelField(last_jx, last_jy);
2425 DrawLevelField(last_jx, last_jy);
2428 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2429 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2432 if (!IN_SCR_FIELD(sx, sy))
2435 if (setup.direct_draw)
2436 SetDrawtoField(DRAW_BUFFERED);
2438 /* ----------------------------------------------------------------------- */
2439 /* draw things behind the player, if needed */
2440 /* ----------------------------------------------------------------------- */
2443 DrawLevelElement(jx, jy, Back[jx][jy]);
2444 else if (IS_ACTIVE_BOMB(element))
2445 DrawLevelElement(jx, jy, EL_EMPTY);
2448 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2450 int old_element = GfxElement[jx][jy];
2451 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2452 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2454 if (GFX_CRUMBLED(old_element))
2455 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2457 DrawGraphic(sx, sy, old_graphic, frame);
2459 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2460 player_is_opaque = TRUE;
2464 GfxElement[jx][jy] = EL_UNDEFINED;
2466 /* make sure that pushed elements are drawn with correct frame rate */
2468 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2470 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2471 GfxFrame[jx][jy] = player->StepFrame;
2473 if (player->is_pushing && player->is_moving)
2474 GfxFrame[jx][jy] = player->StepFrame;
2477 DrawLevelField(jx, jy);
2481 /* ----------------------------------------------------------------------- */
2482 /* draw player himself */
2483 /* ----------------------------------------------------------------------- */
2485 graphic = getPlayerGraphic(player, move_dir);
2487 /* in the case of changed player action or direction, prevent the current
2488 animation frame from being restarted for identical animations */
2489 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2490 player->Frame = last_player_frame;
2492 frame = getGraphicAnimationFrame(graphic, player->Frame);
2496 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2497 sxx = player->GfxPos;
2499 syy = player->GfxPos;
2502 if (!setup.soft_scrolling && ScreenMovPos)
2505 if (player_is_opaque)
2506 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2508 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2510 if (SHIELD_ON(player))
2512 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2513 IMG_SHIELD_NORMAL_ACTIVE);
2514 int frame = getGraphicAnimationFrame(graphic, -1);
2516 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2519 /* ----------------------------------------------------------------------- */
2520 /* draw things the player is pushing, if needed */
2521 /* ----------------------------------------------------------------------- */
2524 printf("::: %d, %d [%d, %d] [%d]\n",
2525 player->is_pushing, player_is_moving, player->GfxAction,
2526 player->is_moving, player_is_moving);
2530 if (player->is_pushing && player->is_moving)
2532 int px = SCREENX(jx), py = SCREENY(jy);
2533 int pxx = (TILEX - ABS(sxx)) * dx;
2534 int pyy = (TILEY - ABS(syy)) * dy;
2535 int gfx_frame = GfxFrame[jx][jy];
2541 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2543 element = Feld[next_jx][next_jy];
2544 gfx_frame = GfxFrame[next_jx][next_jy];
2547 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2550 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2551 frame = getGraphicAnimationFrame(graphic, sync_frame);
2553 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2556 /* draw background element under pushed element (like the Sokoban field) */
2557 if (Back[next_jx][next_jy])
2558 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2560 /* masked drawing is needed for EMC style (double) movement graphics */
2561 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2565 /* ----------------------------------------------------------------------- */
2566 /* draw things in front of player (active dynamite or dynabombs) */
2567 /* ----------------------------------------------------------------------- */
2569 if (IS_ACTIVE_BOMB(element))
2571 graphic = el2img(element);
2572 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2574 if (game.emulation == EMU_SUPAPLEX)
2575 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2577 DrawGraphicThruMask(sx, sy, graphic, frame);
2580 if (player_is_moving && last_element == EL_EXPLOSION)
2582 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2583 GfxElement[last_jx][last_jy] : EL_EMPTY);
2584 int graphic = el_act2img(element, ACTION_EXPLODING);
2585 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2586 int phase = ExplodePhase[last_jx][last_jy] - 1;
2587 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2590 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2593 /* ----------------------------------------------------------------------- */
2594 /* draw elements the player is just walking/passing through/under */
2595 /* ----------------------------------------------------------------------- */
2597 if (player_is_moving)
2599 /* handle the field the player is leaving ... */
2600 if (IS_ACCESSIBLE_INSIDE(last_element))
2601 DrawLevelField(last_jx, last_jy);
2602 else if (IS_ACCESSIBLE_UNDER(last_element))
2603 DrawLevelFieldThruMask(last_jx, last_jy);
2606 /* do not redraw accessible elements if the player is just pushing them */
2607 if (!player_is_moving || !player->is_pushing)
2609 /* ... and the field the player is entering */
2610 if (IS_ACCESSIBLE_INSIDE(element))
2611 DrawLevelField(jx, jy);
2612 else if (IS_ACCESSIBLE_UNDER(element))
2613 DrawLevelFieldThruMask(jx, jy);
2616 if (setup.direct_draw)
2618 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2619 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2620 int x_size = TILEX * (1 + ABS(jx - last_jx));
2621 int y_size = TILEY * (1 + ABS(jy - last_jy));
2623 BlitBitmap(drawto_field, window,
2624 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2625 SetDrawtoField(DRAW_DIRECT);
2628 MarkTileDirty(sx, sy);
2631 /* ------------------------------------------------------------------------- */
2633 void WaitForEventToContinue()
2635 boolean still_wait = TRUE;
2637 /* simulate releasing mouse button over last gadget, if still pressed */
2639 HandleGadgets(-1, -1, 0);
2641 button_status = MB_RELEASED;
2657 case EVENT_BUTTONPRESS:
2658 case EVENT_KEYPRESS:
2662 case EVENT_KEYRELEASE:
2663 ClearPlayerAction();
2667 HandleOtherEvents(&event);
2671 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2678 /* don't eat all CPU time */
2683 #define MAX_REQUEST_LINES 13
2684 #define MAX_REQUEST_LINE_FONT1_LEN 7
2685 #define MAX_REQUEST_LINE_FONT2_LEN 10
2687 boolean Request(char *text, unsigned int req_state)
2689 int mx, my, ty, result = -1;
2690 unsigned int old_door_state;
2691 int last_game_status = game_status; /* save current game status */
2692 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2693 int font_nr = FONT_TEXT_2;
2694 int max_word_len = 0;
2697 for (text_ptr = text; *text_ptr; text_ptr++)
2699 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2701 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2703 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2705 font_nr = FONT_TEXT_1;
2707 font_nr = FONT_LEVEL_NUMBER;
2714 if (game_status == GAME_MODE_PLAYING &&
2715 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2716 BlitScreenToBitmap_EM(backbuffer);
2718 /* disable deactivated drawing when quick-loading level tape recording */
2719 if (tape.playing && tape.deactivate_display)
2720 TapeDeactivateDisplayOff(TRUE);
2722 SetMouseCursor(CURSOR_DEFAULT);
2724 #if defined(NETWORK_AVALIABLE)
2725 /* pause network game while waiting for request to answer */
2726 if (options.network &&
2727 game_status == GAME_MODE_PLAYING &&
2728 req_state & REQUEST_WAIT_FOR_INPUT)
2729 SendToServer_PausePlaying();
2732 old_door_state = GetDoorState();
2734 /* simulate releasing mouse button over last gadget, if still pressed */
2736 HandleGadgets(-1, -1, 0);
2740 if (old_door_state & DOOR_OPEN_1)
2742 CloseDoor(DOOR_CLOSE_1);
2744 /* save old door content */
2745 BlitBitmap(bitmap_db_door, bitmap_db_door,
2746 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2747 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2751 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2754 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2756 /* clear door drawing field */
2757 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2759 /* force DOOR font inside door area */
2760 game_status = GAME_MODE_PSEUDO_DOOR;
2762 /* write text for request */
2763 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2765 char text_line[max_request_line_len + 1];
2771 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2774 if (!tc || tc == ' ')
2785 strncpy(text_line, text, tl);
2788 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2789 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2790 text_line, font_nr);
2792 text += tl + (tc == ' ' ? 1 : 0);
2795 game_status = last_game_status; /* restore current game status */
2797 if (req_state & REQ_ASK)
2799 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2800 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2802 else if (req_state & REQ_CONFIRM)
2804 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2806 else if (req_state & REQ_PLAYER)
2808 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2809 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2810 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2811 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2814 /* copy request gadgets to door backbuffer */
2815 BlitBitmap(drawto, bitmap_db_door,
2816 DX, DY, DXSIZE, DYSIZE,
2817 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2819 OpenDoor(DOOR_OPEN_1);
2821 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2823 if (game_status == GAME_MODE_PLAYING)
2825 SetPanelBackground();
2826 SetDrawBackgroundMask(REDRAW_DOOR_1);
2830 SetDrawBackgroundMask(REDRAW_FIELD);
2836 if (game_status != GAME_MODE_MAIN)
2839 button_status = MB_RELEASED;
2841 request_gadget_id = -1;
2843 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2855 case EVENT_BUTTONPRESS:
2856 case EVENT_BUTTONRELEASE:
2857 case EVENT_MOTIONNOTIFY:
2859 if (event.type == EVENT_MOTIONNOTIFY)
2861 if (!PointerInWindow(window))
2862 continue; /* window and pointer are on different screens */
2867 motion_status = TRUE;
2868 mx = ((MotionEvent *) &event)->x;
2869 my = ((MotionEvent *) &event)->y;
2873 motion_status = FALSE;
2874 mx = ((ButtonEvent *) &event)->x;
2875 my = ((ButtonEvent *) &event)->y;
2876 if (event.type == EVENT_BUTTONPRESS)
2877 button_status = ((ButtonEvent *) &event)->button;
2879 button_status = MB_RELEASED;
2882 /* this sets 'request_gadget_id' */
2883 HandleGadgets(mx, my, button_status);
2885 switch (request_gadget_id)
2887 case TOOL_CTRL_ID_YES:
2890 case TOOL_CTRL_ID_NO:
2893 case TOOL_CTRL_ID_CONFIRM:
2894 result = TRUE | FALSE;
2897 case TOOL_CTRL_ID_PLAYER_1:
2900 case TOOL_CTRL_ID_PLAYER_2:
2903 case TOOL_CTRL_ID_PLAYER_3:
2906 case TOOL_CTRL_ID_PLAYER_4:
2917 case EVENT_KEYPRESS:
2918 switch (GetEventKey((KeyEvent *)&event, TRUE))
2931 if (req_state & REQ_PLAYER)
2935 case EVENT_KEYRELEASE:
2936 ClearPlayerAction();
2940 HandleOtherEvents(&event);
2944 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2946 int joy = AnyJoystick();
2948 if (joy & JOY_BUTTON_1)
2950 else if (joy & JOY_BUTTON_2)
2956 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2958 HandleGameActions();
2965 if (!PendingEvent()) /* delay only if no pending events */
2974 if (!PendingEvent()) /* delay only if no pending events */
2977 /* don't eat all CPU time */
2984 if (game_status != GAME_MODE_MAIN)
2989 if (!(req_state & REQ_STAY_OPEN))
2991 CloseDoor(DOOR_CLOSE_1);
2993 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2994 (req_state & REQ_REOPEN))
2995 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3000 if (game_status == GAME_MODE_PLAYING)
3002 SetPanelBackground();
3003 SetDrawBackgroundMask(REDRAW_DOOR_1);
3007 SetDrawBackgroundMask(REDRAW_FIELD);
3010 #if defined(NETWORK_AVALIABLE)
3011 /* continue network game after request */
3012 if (options.network &&
3013 game_status == GAME_MODE_PLAYING &&
3014 req_state & REQUEST_WAIT_FOR_INPUT)
3015 SendToServer_ContinuePlaying();
3018 /* restore deactivated drawing when quick-loading level tape recording */
3019 if (tape.playing && tape.deactivate_display)
3020 TapeDeactivateDisplayOn();
3025 unsigned int OpenDoor(unsigned int door_state)
3027 if (door_state & DOOR_COPY_BACK)
3029 if (door_state & DOOR_OPEN_1)
3030 BlitBitmap(bitmap_db_door, bitmap_db_door,
3031 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3032 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3034 if (door_state & DOOR_OPEN_2)
3035 BlitBitmap(bitmap_db_door, bitmap_db_door,
3036 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3037 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3039 door_state &= ~DOOR_COPY_BACK;
3042 return MoveDoor(door_state);
3045 unsigned int CloseDoor(unsigned int door_state)
3047 unsigned int old_door_state = GetDoorState();
3049 if (!(door_state & DOOR_NO_COPY_BACK))
3051 if (old_door_state & DOOR_OPEN_1)
3052 BlitBitmap(backbuffer, bitmap_db_door,
3053 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3055 if (old_door_state & DOOR_OPEN_2)
3056 BlitBitmap(backbuffer, bitmap_db_door,
3057 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3059 door_state &= ~DOOR_NO_COPY_BACK;
3062 return MoveDoor(door_state);
3065 unsigned int GetDoorState()
3067 return MoveDoor(DOOR_GET_STATE);
3070 unsigned int SetDoorState(unsigned int door_state)
3072 return MoveDoor(door_state | DOOR_SET_STATE);
3075 unsigned int MoveDoor(unsigned int door_state)
3077 static int door1 = DOOR_OPEN_1;
3078 static int door2 = DOOR_CLOSE_2;
3079 unsigned long door_delay = 0;
3080 unsigned long door_delay_value;
3083 if (door_1.width < 0 || door_1.width > DXSIZE)
3084 door_1.width = DXSIZE;
3085 if (door_1.height < 0 || door_1.height > DYSIZE)
3086 door_1.height = DYSIZE;
3087 if (door_2.width < 0 || door_2.width > VXSIZE)
3088 door_2.width = VXSIZE;
3089 if (door_2.height < 0 || door_2.height > VYSIZE)
3090 door_2.height = VYSIZE;
3092 if (door_state == DOOR_GET_STATE)
3093 return (door1 | door2);
3095 if (door_state & DOOR_SET_STATE)
3097 if (door_state & DOOR_ACTION_1)
3098 door1 = door_state & DOOR_ACTION_1;
3099 if (door_state & DOOR_ACTION_2)
3100 door2 = door_state & DOOR_ACTION_2;
3102 return (door1 | door2);
3105 if (!(door_state & DOOR_FORCE_REDRAW))
3107 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3108 door_state &= ~DOOR_OPEN_1;
3109 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3110 door_state &= ~DOOR_CLOSE_1;
3111 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3112 door_state &= ~DOOR_OPEN_2;
3113 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3114 door_state &= ~DOOR_CLOSE_2;
3117 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3120 if (setup.quick_doors)
3122 stepsize = 20; /* must be chosen to always draw last frame */
3123 door_delay_value = 0;
3126 if (global.autoplay_leveldir)
3128 door_state |= DOOR_NO_DELAY;
3129 door_state &= ~DOOR_CLOSE_ALL;
3132 if (door_state & DOOR_ACTION)
3134 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3135 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3136 boolean door_1_done = (!handle_door_1);
3137 boolean door_2_done = (!handle_door_2);
3138 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3139 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3140 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3141 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3142 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3143 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3144 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3145 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3146 int door_skip = max_door_size - door_size;
3147 int end = door_size;
3148 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3151 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3153 /* opening door sound has priority over simultaneously closing door */
3154 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3155 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3156 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3157 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3160 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3163 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3164 GC gc = bitmap->stored_clip_gc;
3166 if (door_state & DOOR_ACTION_1)
3168 int a = MIN(x * door_1.step_offset, end);
3169 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3170 int i = p + door_skip;
3172 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3174 BlitBitmap(bitmap_db_door, drawto,
3175 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3176 DXSIZE, DYSIZE, DX, DY);
3180 BlitBitmap(bitmap_db_door, drawto,
3181 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3182 DXSIZE, DYSIZE - p / 2, DX, DY);
3184 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3187 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3189 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3190 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3191 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3192 int dst2_x = DX, dst2_y = DY;
3193 int width = i, height = DYSIZE;
3195 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3196 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3199 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3200 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3203 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3205 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3206 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3207 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3208 int dst2_x = DX, dst2_y = DY;
3209 int width = DXSIZE, height = i;
3211 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3212 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3215 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3216 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3219 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3221 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3223 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3224 BlitBitmapMasked(bitmap, drawto,
3225 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3226 DX + DXSIZE - i, DY + j);
3227 BlitBitmapMasked(bitmap, drawto,
3228 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3229 DX + DXSIZE - i, DY + 140 + j);
3230 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3231 DY - (DOOR_GFX_PAGEY1 + j));
3232 BlitBitmapMasked(bitmap, drawto,
3233 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3235 BlitBitmapMasked(bitmap, drawto,
3236 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3239 BlitBitmapMasked(bitmap, drawto,
3240 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3242 BlitBitmapMasked(bitmap, drawto,
3243 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3245 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3246 BlitBitmapMasked(bitmap, drawto,
3247 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3248 DX + DXSIZE - i, DY + 77 + j);
3249 BlitBitmapMasked(bitmap, drawto,
3250 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3251 DX + DXSIZE - i, DY + 203 + j);
3254 redraw_mask |= REDRAW_DOOR_1;
3255 door_1_done = (a == end);
3258 if (door_state & DOOR_ACTION_2)
3260 int a = MIN(x * door_2.step_offset, door_size);
3261 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3262 int i = p + door_skip;
3264 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3266 BlitBitmap(bitmap_db_door, drawto,
3267 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3268 VXSIZE, VYSIZE, VX, VY);
3270 else if (x <= VYSIZE)
3272 BlitBitmap(bitmap_db_door, drawto,
3273 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3274 VXSIZE, VYSIZE - p / 2, VX, VY);
3276 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3279 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3281 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3282 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3283 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3284 int dst2_x = VX, dst2_y = VY;
3285 int width = i, height = VYSIZE;
3287 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3288 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3291 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3292 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3295 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3297 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3298 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3299 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3300 int dst2_x = VX, dst2_y = VY;
3301 int width = VXSIZE, height = i;
3303 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3304 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3307 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3308 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3311 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3313 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3315 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3316 BlitBitmapMasked(bitmap, drawto,
3317 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3318 VX + VXSIZE - i, VY + j);
3319 SetClipOrigin(bitmap, gc,
3320 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3321 BlitBitmapMasked(bitmap, drawto,
3322 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3325 BlitBitmapMasked(bitmap, drawto,
3326 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3327 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3328 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3329 BlitBitmapMasked(bitmap, drawto,
3330 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3332 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3335 redraw_mask |= REDRAW_DOOR_2;
3336 door_2_done = (a == VXSIZE);
3339 if (!(door_state & DOOR_NO_DELAY))
3343 if (game_status == GAME_MODE_MAIN)
3346 WaitUntilDelayReached(&door_delay, door_delay_value);
3351 if (door_state & DOOR_ACTION_1)
3352 door1 = door_state & DOOR_ACTION_1;
3353 if (door_state & DOOR_ACTION_2)
3354 door2 = door_state & DOOR_ACTION_2;
3356 return (door1 | door2);
3359 void DrawSpecialEditorDoor()
3361 /* draw bigger toolbox window */
3362 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3363 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3365 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3366 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3369 redraw_mask |= REDRAW_ALL;
3372 void UndrawSpecialEditorDoor()
3374 /* draw normal tape recorder window */
3375 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3376 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3379 redraw_mask |= REDRAW_ALL;
3383 /* ---------- new tool button stuff ---------------------------------------- */
3385 /* graphic position values for tool buttons */
3386 #define TOOL_BUTTON_YES_XPOS 2
3387 #define TOOL_BUTTON_YES_YPOS 250
3388 #define TOOL_BUTTON_YES_GFX_YPOS 0
3389 #define TOOL_BUTTON_YES_XSIZE 46
3390 #define TOOL_BUTTON_YES_YSIZE 28
3391 #define TOOL_BUTTON_NO_XPOS 52
3392 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3393 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3394 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3395 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3396 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3397 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3398 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3399 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3400 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3401 #define TOOL_BUTTON_PLAYER_XSIZE 30
3402 #define TOOL_BUTTON_PLAYER_YSIZE 30
3403 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3404 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3405 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3406 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3407 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3408 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3409 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3410 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3411 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3412 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3413 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3414 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3415 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3416 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3417 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3418 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3419 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3420 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3421 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3422 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3431 } toolbutton_info[NUM_TOOL_BUTTONS] =
3434 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3435 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3436 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3441 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3442 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3443 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3448 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3449 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3450 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3451 TOOL_CTRL_ID_CONFIRM,
3455 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3456 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3457 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3458 TOOL_CTRL_ID_PLAYER_1,
3462 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3463 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3464 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3465 TOOL_CTRL_ID_PLAYER_2,
3469 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3470 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3471 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3472 TOOL_CTRL_ID_PLAYER_3,
3476 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3477 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3478 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3479 TOOL_CTRL_ID_PLAYER_4,
3484 void CreateToolButtons()
3488 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3490 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3491 Bitmap *deco_bitmap = None;
3492 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3493 struct GadgetInfo *gi;
3494 unsigned long event_mask;
3495 int gd_xoffset, gd_yoffset;
3496 int gd_x1, gd_x2, gd_y;
3499 event_mask = GD_EVENT_RELEASED;
3501 gd_xoffset = toolbutton_info[i].xpos;
3502 gd_yoffset = toolbutton_info[i].ypos;
3503 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3504 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3505 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3507 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3509 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3511 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3512 &deco_bitmap, &deco_x, &deco_y);
3513 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3514 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3517 gi = CreateGadget(GDI_CUSTOM_ID, id,
3518 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3519 GDI_X, DX + toolbutton_info[i].x,
3520 GDI_Y, DY + toolbutton_info[i].y,
3521 GDI_WIDTH, toolbutton_info[i].width,
3522 GDI_HEIGHT, toolbutton_info[i].height,
3523 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3524 GDI_STATE, GD_BUTTON_UNPRESSED,
3525 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3526 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3527 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3528 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3529 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3530 GDI_DECORATION_SHIFTING, 1, 1,
3531 GDI_DIRECT_DRAW, FALSE,
3532 GDI_EVENT_MASK, event_mask,
3533 GDI_CALLBACK_ACTION, HandleToolButtons,
3537 Error(ERR_EXIT, "cannot create gadget");
3539 tool_gadget[id] = gi;
3543 void FreeToolButtons()
3547 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3548 FreeGadget(tool_gadget[i]);
3551 static void UnmapToolButtons()
3555 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3556 UnmapGadget(tool_gadget[i]);
3559 static void HandleToolButtons(struct GadgetInfo *gi)
3561 request_gadget_id = gi->custom_id;
3564 static struct Mapping_EM_to_RND_object
3567 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3568 boolean is_backside; /* backside of moving element */
3574 em_object_mapping_list[] =
3577 Xblank, TRUE, FALSE,
3581 Yacid_splash_eB, FALSE, FALSE,
3582 EL_ACID_SPLASH_RIGHT, -1, -1
3585 Yacid_splash_wB, FALSE, FALSE,
3586 EL_ACID_SPLASH_LEFT, -1, -1
3589 #ifdef EM_ENGINE_BAD_ROLL
3591 Xstone_force_e, FALSE, FALSE,
3592 EL_ROCK, -1, MV_BIT_RIGHT
3595 Xstone_force_w, FALSE, FALSE,
3596 EL_ROCK, -1, MV_BIT_LEFT
3599 Xnut_force_e, FALSE, FALSE,
3600 EL_NUT, -1, MV_BIT_RIGHT
3603 Xnut_force_w, FALSE, FALSE,
3604 EL_NUT, -1, MV_BIT_LEFT
3607 Xspring_force_e, FALSE, FALSE,
3608 EL_SPRING, -1, MV_BIT_RIGHT
3611 Xspring_force_w, FALSE, FALSE,
3612 EL_SPRING, -1, MV_BIT_LEFT
3615 Xemerald_force_e, FALSE, FALSE,
3616 EL_EMERALD, -1, MV_BIT_RIGHT
3619 Xemerald_force_w, FALSE, FALSE,
3620 EL_EMERALD, -1, MV_BIT_LEFT
3623 Xdiamond_force_e, FALSE, FALSE,
3624 EL_DIAMOND, -1, MV_BIT_RIGHT
3627 Xdiamond_force_w, FALSE, FALSE,
3628 EL_DIAMOND, -1, MV_BIT_LEFT
3631 Xbomb_force_e, FALSE, FALSE,
3632 EL_BOMB, -1, MV_BIT_RIGHT
3635 Xbomb_force_w, FALSE, FALSE,
3636 EL_BOMB, -1, MV_BIT_LEFT
3638 #endif /* EM_ENGINE_BAD_ROLL */
3641 Xstone, TRUE, FALSE,
3645 Xstone_pause, FALSE, FALSE,
3649 Xstone_fall, FALSE, FALSE,
3653 Ystone_s, FALSE, FALSE,
3654 EL_ROCK, ACTION_FALLING, -1
3657 Ystone_sB, FALSE, TRUE,
3658 EL_ROCK, ACTION_FALLING, -1
3661 Ystone_e, FALSE, FALSE,
3662 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3665 Ystone_eB, FALSE, TRUE,
3666 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3669 Ystone_w, FALSE, FALSE,
3670 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3673 Ystone_wB, FALSE, TRUE,
3674 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3681 Xnut_pause, FALSE, FALSE,
3685 Xnut_fall, FALSE, FALSE,
3689 Ynut_s, FALSE, FALSE,
3690 EL_NUT, ACTION_FALLING, -1
3693 Ynut_sB, FALSE, TRUE,
3694 EL_NUT, ACTION_FALLING, -1
3697 Ynut_e, FALSE, FALSE,
3698 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3701 Ynut_eB, FALSE, TRUE,
3702 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3705 Ynut_w, FALSE, FALSE,
3706 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3709 Ynut_wB, FALSE, TRUE,
3710 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3713 Xbug_n, TRUE, FALSE,
3717 Xbug_e, TRUE, FALSE,
3718 EL_BUG_RIGHT, -1, -1
3721 Xbug_s, TRUE, FALSE,
3725 Xbug_w, TRUE, FALSE,
3729 Xbug_gon, FALSE, FALSE,
3733 Xbug_goe, FALSE, FALSE,
3734 EL_BUG_RIGHT, -1, -1
3737 Xbug_gos, FALSE, FALSE,
3741 Xbug_gow, FALSE, FALSE,
3745 Ybug_n, FALSE, FALSE,
3746 EL_BUG, ACTION_MOVING, MV_BIT_UP
3749 Ybug_nB, FALSE, TRUE,
3750 EL_BUG, ACTION_MOVING, MV_BIT_UP
3753 Ybug_e, FALSE, FALSE,
3754 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3757 Ybug_eB, FALSE, TRUE,
3758 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3761 Ybug_s, FALSE, FALSE,
3762 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3765 Ybug_sB, FALSE, TRUE,
3766 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3769 Ybug_w, FALSE, FALSE,
3770 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3773 Ybug_wB, FALSE, TRUE,
3774 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3777 Ybug_w_n, FALSE, FALSE,
3778 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3781 Ybug_n_e, FALSE, FALSE,
3782 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3785 Ybug_e_s, FALSE, FALSE,
3786 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3789 Ybug_s_w, FALSE, FALSE,
3790 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3793 Ybug_e_n, FALSE, FALSE,
3794 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3797 Ybug_s_e, FALSE, FALSE,
3798 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3801 Ybug_w_s, FALSE, FALSE,
3802 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3805 Ybug_n_w, FALSE, FALSE,
3806 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3809 Ybug_stone, FALSE, FALSE,
3810 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3813 Ybug_spring, FALSE, FALSE,
3814 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3817 Xtank_n, TRUE, FALSE,
3818 EL_SPACESHIP_UP, -1, -1
3821 Xtank_e, TRUE, FALSE,
3822 EL_SPACESHIP_RIGHT, -1, -1
3825 Xtank_s, TRUE, FALSE,
3826 EL_SPACESHIP_DOWN, -1, -1
3829 Xtank_w, TRUE, FALSE,
3830 EL_SPACESHIP_LEFT, -1, -1
3833 Xtank_gon, FALSE, FALSE,
3834 EL_SPACESHIP_UP, -1, -1
3837 Xtank_goe, FALSE, FALSE,
3838 EL_SPACESHIP_RIGHT, -1, -1
3841 Xtank_gos, FALSE, FALSE,
3842 EL_SPACESHIP_DOWN, -1, -1
3845 Xtank_gow, FALSE, FALSE,
3846 EL_SPACESHIP_LEFT, -1, -1
3849 Ytank_n, FALSE, FALSE,
3850 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3853 Ytank_nB, FALSE, TRUE,
3854 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3857 Ytank_e, FALSE, FALSE,
3858 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3861 Ytank_eB, FALSE, TRUE,
3862 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3865 Ytank_s, FALSE, FALSE,
3866 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3869 Ytank_sB, FALSE, TRUE,
3870 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3873 Ytank_w, FALSE, FALSE,
3874 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3877 Ytank_wB, FALSE, TRUE,
3878 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3881 Ytank_w_n, FALSE, FALSE,
3882 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3885 Ytank_n_e, FALSE, FALSE,
3886 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3889 Ytank_e_s, FALSE, FALSE,
3890 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3893 Ytank_s_w, FALSE, FALSE,
3894 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3897 Ytank_e_n, FALSE, FALSE,
3898 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3901 Ytank_s_e, FALSE, FALSE,
3902 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3905 Ytank_w_s, FALSE, FALSE,
3906 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3909 Ytank_n_w, FALSE, FALSE,
3910 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3913 Ytank_stone, FALSE, FALSE,
3914 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3917 Ytank_spring, FALSE, FALSE,
3918 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3921 Xandroid, TRUE, FALSE,
3922 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3925 Xandroid_1_n, FALSE, FALSE,
3926 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3929 Xandroid_2_n, FALSE, FALSE,
3930 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3933 Xandroid_1_e, FALSE, FALSE,
3934 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3937 Xandroid_2_e, FALSE, FALSE,
3938 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3941 Xandroid_1_w, FALSE, FALSE,
3942 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3945 Xandroid_2_w, FALSE, FALSE,
3946 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3949 Xandroid_1_s, FALSE, FALSE,
3950 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3953 Xandroid_2_s, FALSE, FALSE,
3954 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3957 Yandroid_n, FALSE, FALSE,
3958 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3961 Yandroid_nB, FALSE, TRUE,
3962 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3965 Yandroid_ne, FALSE, FALSE,
3966 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3969 Yandroid_neB, FALSE, TRUE,
3970 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3973 Yandroid_e, FALSE, FALSE,
3974 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3977 Yandroid_eB, FALSE, TRUE,
3978 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3981 Yandroid_se, FALSE, FALSE,
3982 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3985 Yandroid_seB, FALSE, TRUE,
3986 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3989 Yandroid_s, FALSE, FALSE,
3990 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3993 Yandroid_sB, FALSE, TRUE,
3994 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3997 Yandroid_sw, FALSE, FALSE,
3998 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4001 Yandroid_swB, FALSE, TRUE,
4002 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4005 Yandroid_w, FALSE, FALSE,
4006 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4009 Yandroid_wB, FALSE, TRUE,
4010 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4013 Yandroid_nw, FALSE, FALSE,
4014 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4017 Yandroid_nwB, FALSE, TRUE,
4018 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4021 Xspring, TRUE, FALSE,
4025 Xspring_pause, FALSE, FALSE,
4029 Xspring_e, FALSE, FALSE,
4033 Xspring_w, FALSE, FALSE,
4037 Xspring_fall, FALSE, FALSE,
4041 Yspring_s, FALSE, FALSE,
4042 EL_SPRING, ACTION_FALLING, -1
4045 Yspring_sB, FALSE, TRUE,
4046 EL_SPRING, ACTION_FALLING, -1
4049 Yspring_e, FALSE, FALSE,
4050 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4053 Yspring_eB, FALSE, TRUE,
4054 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4057 Yspring_w, FALSE, FALSE,
4058 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4061 Yspring_wB, FALSE, TRUE,
4062 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4065 Yspring_kill_e, FALSE, FALSE,
4066 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4069 Yspring_kill_eB, FALSE, TRUE,
4070 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4073 Yspring_kill_w, FALSE, FALSE,
4074 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4077 Yspring_kill_wB, FALSE, TRUE,
4078 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4081 Xeater_n, TRUE, FALSE,
4082 EL_YAMYAM_UP, -1, -1
4085 Xeater_e, TRUE, FALSE,
4086 EL_YAMYAM_RIGHT, -1, -1
4089 Xeater_w, TRUE, FALSE,
4090 EL_YAMYAM_LEFT, -1, -1
4093 Xeater_s, TRUE, FALSE,
4094 EL_YAMYAM_DOWN, -1, -1
4097 Yeater_n, FALSE, FALSE,
4098 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4101 Yeater_nB, FALSE, TRUE,
4102 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4105 Yeater_e, FALSE, FALSE,
4106 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4109 Yeater_eB, FALSE, TRUE,
4110 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4113 Yeater_s, FALSE, FALSE,
4114 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4117 Yeater_sB, FALSE, TRUE,
4118 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4121 Yeater_w, FALSE, FALSE,
4122 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4125 Yeater_wB, FALSE, TRUE,
4126 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4129 Yeater_stone, FALSE, FALSE,
4130 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4133 Yeater_spring, FALSE, FALSE,
4134 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4137 Xalien, TRUE, FALSE,
4141 Xalien_pause, FALSE, FALSE,
4145 Yalien_n, FALSE, FALSE,
4146 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4149 Yalien_nB, FALSE, TRUE,
4150 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4153 Yalien_e, FALSE, FALSE,
4154 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4157 Yalien_eB, FALSE, TRUE,
4158 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4161 Yalien_s, FALSE, FALSE,
4162 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4165 Yalien_sB, FALSE, TRUE,
4166 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4169 Yalien_w, FALSE, FALSE,
4170 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4173 Yalien_wB, FALSE, TRUE,
4174 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4177 Yalien_stone, FALSE, FALSE,
4178 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4181 Yalien_spring, FALSE, FALSE,
4182 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4185 Xemerald, TRUE, FALSE,
4189 Xemerald_pause, FALSE, FALSE,
4193 Xemerald_fall, FALSE, FALSE,
4197 Xemerald_shine, FALSE, FALSE,
4198 EL_EMERALD, ACTION_TWINKLING, -1
4201 Yemerald_s, FALSE, FALSE,
4202 EL_EMERALD, ACTION_FALLING, -1
4205 Yemerald_sB, FALSE, TRUE,
4206 EL_EMERALD, ACTION_FALLING, -1
4209 Yemerald_e, FALSE, FALSE,
4210 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4213 Yemerald_eB, FALSE, TRUE,
4214 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4217 Yemerald_w, FALSE, FALSE,
4218 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4221 Yemerald_wB, FALSE, TRUE,
4222 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4225 Yemerald_eat, FALSE, FALSE,
4226 EL_EMERALD, ACTION_COLLECTING, -1
4229 Yemerald_stone, FALSE, FALSE,
4230 EL_NUT, ACTION_BREAKING, -1
4233 Xdiamond, TRUE, FALSE,
4237 Xdiamond_pause, FALSE, FALSE,
4241 Xdiamond_fall, FALSE, FALSE,
4245 Xdiamond_shine, FALSE, FALSE,
4246 EL_DIAMOND, ACTION_TWINKLING, -1
4249 Ydiamond_s, FALSE, FALSE,
4250 EL_DIAMOND, ACTION_FALLING, -1
4253 Ydiamond_sB, FALSE, TRUE,
4254 EL_DIAMOND, ACTION_FALLING, -1
4257 Ydiamond_e, FALSE, FALSE,
4258 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4261 Ydiamond_eB, FALSE, TRUE,
4262 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4265 Ydiamond_w, FALSE, FALSE,
4266 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4269 Ydiamond_wB, FALSE, TRUE,
4270 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4273 Ydiamond_eat, FALSE, FALSE,
4274 EL_DIAMOND, ACTION_COLLECTING, -1
4277 Ydiamond_stone, FALSE, FALSE,
4278 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4281 Xdrip_fall, TRUE, FALSE,
4282 EL_AMOEBA_DROP, -1, -1
4285 Xdrip_stretch, FALSE, FALSE,
4286 EL_AMOEBA_DROP, ACTION_FALLING, -1
4289 Xdrip_stretchB, FALSE, TRUE,
4290 EL_AMOEBA_DROP, ACTION_FALLING, -1
4293 Xdrip_eat, FALSE, FALSE,
4294 EL_AMOEBA_DROP, ACTION_GROWING, -1
4297 Ydrip_s1, FALSE, FALSE,
4298 EL_AMOEBA_DROP, ACTION_FALLING, -1
4301 Ydrip_s1B, FALSE, TRUE,
4302 EL_AMOEBA_DROP, ACTION_FALLING, -1
4305 Ydrip_s2, FALSE, FALSE,
4306 EL_AMOEBA_DROP, ACTION_FALLING, -1
4309 Ydrip_s2B, FALSE, TRUE,
4310 EL_AMOEBA_DROP, ACTION_FALLING, -1
4317 Xbomb_pause, FALSE, FALSE,
4321 Xbomb_fall, FALSE, FALSE,
4325 Ybomb_s, FALSE, FALSE,
4326 EL_BOMB, ACTION_FALLING, -1
4329 Ybomb_sB, FALSE, TRUE,
4330 EL_BOMB, ACTION_FALLING, -1
4333 Ybomb_e, FALSE, FALSE,
4334 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4337 Ybomb_eB, FALSE, TRUE,
4338 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4341 Ybomb_w, FALSE, FALSE,
4342 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4345 Ybomb_wB, FALSE, TRUE,
4346 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4349 Ybomb_eat, FALSE, FALSE,
4350 EL_BOMB, ACTION_ACTIVATING, -1
4353 Xballoon, TRUE, FALSE,
4357 Yballoon_n, FALSE, FALSE,
4358 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4361 Yballoon_nB, FALSE, TRUE,
4362 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4365 Yballoon_e, FALSE, FALSE,
4366 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4369 Yballoon_eB, FALSE, TRUE,
4370 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4373 Yballoon_s, FALSE, FALSE,
4374 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4377 Yballoon_sB, FALSE, TRUE,
4378 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4381 Yballoon_w, FALSE, FALSE,
4382 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4385 Yballoon_wB, FALSE, TRUE,
4386 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4389 Xgrass, TRUE, FALSE,
4390 EL_EMC_GRASS, -1, -1
4393 Ygrass_nB, FALSE, FALSE,
4394 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4397 Ygrass_eB, FALSE, FALSE,
4398 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4401 Ygrass_sB, FALSE, FALSE,
4402 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4405 Ygrass_wB, FALSE, FALSE,
4406 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4413 Ydirt_nB, FALSE, FALSE,
4414 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4417 Ydirt_eB, FALSE, FALSE,
4418 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4421 Ydirt_sB, FALSE, FALSE,
4422 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4425 Ydirt_wB, FALSE, FALSE,
4426 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4429 Xacid_ne, TRUE, FALSE,
4430 EL_ACID_POOL_TOPRIGHT, -1, -1
4433 Xacid_se, TRUE, FALSE,
4434 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4437 Xacid_s, TRUE, FALSE,
4438 EL_ACID_POOL_BOTTOM, -1, -1
4441 Xacid_sw, TRUE, FALSE,
4442 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4445 Xacid_nw, TRUE, FALSE,
4446 EL_ACID_POOL_TOPLEFT, -1, -1
4449 Xacid_1, TRUE, FALSE,
4453 Xacid_2, FALSE, FALSE,
4457 Xacid_3, FALSE, FALSE,
4461 Xacid_4, FALSE, FALSE,
4465 Xacid_5, FALSE, FALSE,
4469 Xacid_6, FALSE, FALSE,
4473 Xacid_7, FALSE, FALSE,
4477 Xacid_8, FALSE, FALSE,
4481 Xball_1, TRUE, FALSE,
4482 EL_EMC_MAGIC_BALL, -1, -1
4485 Xball_1B, FALSE, FALSE,
4486 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4489 Xball_2, FALSE, FALSE,
4490 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4493 Xball_2B, FALSE, FALSE,
4494 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4497 Yball_eat, FALSE, FALSE,
4498 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4501 Ykey_1_eat, FALSE, FALSE,
4502 EL_EM_KEY_1, ACTION_COLLECTING, -1
4505 Ykey_2_eat, FALSE, FALSE,
4506 EL_EM_KEY_2, ACTION_COLLECTING, -1
4509 Ykey_3_eat, FALSE, FALSE,
4510 EL_EM_KEY_3, ACTION_COLLECTING, -1
4513 Ykey_4_eat, FALSE, FALSE,
4514 EL_EM_KEY_4, ACTION_COLLECTING, -1
4517 Ykey_5_eat, FALSE, FALSE,
4518 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4521 Ykey_6_eat, FALSE, FALSE,
4522 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4525 Ykey_7_eat, FALSE, FALSE,
4526 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4529 Ykey_8_eat, FALSE, FALSE,
4530 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4533 Ylenses_eat, FALSE, FALSE,
4534 EL_EMC_LENSES, ACTION_COLLECTING, -1
4537 Ymagnify_eat, FALSE, FALSE,
4538 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4541 Ygrass_eat, FALSE, FALSE,
4542 EL_EMC_GRASS, ACTION_SNAPPING, -1
4545 Ydirt_eat, FALSE, FALSE,
4546 EL_SAND, ACTION_SNAPPING, -1
4549 Xgrow_ns, TRUE, FALSE,
4550 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4553 Ygrow_ns_eat, FALSE, FALSE,
4554 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4557 Xgrow_ew, TRUE, FALSE,
4558 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4561 Ygrow_ew_eat, FALSE, FALSE,
4562 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4565 Xwonderwall, TRUE, FALSE,
4566 EL_MAGIC_WALL, -1, -1
4569 XwonderwallB, FALSE, FALSE,
4570 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4573 Xamoeba_1, TRUE, FALSE,
4574 EL_AMOEBA_DRY, ACTION_OTHER, -1
4577 Xamoeba_2, FALSE, FALSE,
4578 EL_AMOEBA_DRY, ACTION_OTHER, -1
4581 Xamoeba_3, FALSE, FALSE,
4582 EL_AMOEBA_DRY, ACTION_OTHER, -1
4585 Xamoeba_4, FALSE, FALSE,
4586 EL_AMOEBA_DRY, ACTION_OTHER, -1
4589 Xamoeba_5, TRUE, FALSE,
4590 EL_AMOEBA_WET, ACTION_OTHER, -1
4593 Xamoeba_6, FALSE, FALSE,
4594 EL_AMOEBA_WET, ACTION_OTHER, -1
4597 Xamoeba_7, FALSE, FALSE,
4598 EL_AMOEBA_WET, ACTION_OTHER, -1
4601 Xamoeba_8, FALSE, FALSE,
4602 EL_AMOEBA_WET, ACTION_OTHER, -1
4605 Xdoor_1, TRUE, FALSE,
4606 EL_EM_GATE_1, -1, -1
4609 Xdoor_2, TRUE, FALSE,
4610 EL_EM_GATE_2, -1, -1
4613 Xdoor_3, TRUE, FALSE,
4614 EL_EM_GATE_3, -1, -1
4617 Xdoor_4, TRUE, FALSE,
4618 EL_EM_GATE_4, -1, -1
4621 Xdoor_5, TRUE, FALSE,
4622 EL_EMC_GATE_5, -1, -1
4625 Xdoor_6, TRUE, FALSE,
4626 EL_EMC_GATE_6, -1, -1
4629 Xdoor_7, TRUE, FALSE,
4630 EL_EMC_GATE_7, -1, -1
4633 Xdoor_8, TRUE, FALSE,
4634 EL_EMC_GATE_8, -1, -1
4637 Xkey_1, TRUE, FALSE,
4641 Xkey_2, TRUE, FALSE,
4645 Xkey_3, TRUE, FALSE,
4649 Xkey_4, TRUE, FALSE,
4653 Xkey_5, TRUE, FALSE,
4654 EL_EMC_KEY_5, -1, -1
4657 Xkey_6, TRUE, FALSE,
4658 EL_EMC_KEY_6, -1, -1
4661 Xkey_7, TRUE, FALSE,
4662 EL_EMC_KEY_7, -1, -1
4665 Xkey_8, TRUE, FALSE,
4666 EL_EMC_KEY_8, -1, -1
4669 Xwind_n, TRUE, FALSE,
4670 EL_BALLOON_SWITCH_UP, -1, -1
4673 Xwind_e, TRUE, FALSE,
4674 EL_BALLOON_SWITCH_RIGHT, -1, -1
4677 Xwind_s, TRUE, FALSE,
4678 EL_BALLOON_SWITCH_DOWN, -1, -1
4681 Xwind_w, TRUE, FALSE,
4682 EL_BALLOON_SWITCH_LEFT, -1, -1
4685 Xwind_nesw, TRUE, FALSE,
4686 EL_BALLOON_SWITCH_ANY, -1, -1
4689 Xwind_stop, TRUE, FALSE,
4690 EL_BALLOON_SWITCH_NONE, -1, -1
4694 EL_EM_EXIT_CLOSED, -1, -1
4697 Xexit_1, TRUE, FALSE,
4698 EL_EM_EXIT_OPEN, -1, -1
4701 Xexit_2, FALSE, FALSE,
4702 EL_EM_EXIT_OPEN, -1, -1
4705 Xexit_3, FALSE, FALSE,
4706 EL_EM_EXIT_OPEN, -1, -1
4709 Xdynamite, TRUE, FALSE,
4710 EL_EM_DYNAMITE, -1, -1
4713 Ydynamite_eat, FALSE, FALSE,
4714 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4717 Xdynamite_1, TRUE, FALSE,
4718 EL_EM_DYNAMITE_ACTIVE, -1, -1
4721 Xdynamite_2, FALSE, FALSE,
4722 EL_EM_DYNAMITE_ACTIVE, -1, -1
4725 Xdynamite_3, FALSE, FALSE,
4726 EL_EM_DYNAMITE_ACTIVE, -1, -1
4729 Xdynamite_4, FALSE, FALSE,
4730 EL_EM_DYNAMITE_ACTIVE, -1, -1
4733 Xbumper, TRUE, FALSE,
4734 EL_EMC_SPRING_BUMPER, -1, -1
4737 XbumperB, FALSE, FALSE,
4738 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4741 Xwheel, TRUE, FALSE,
4742 EL_ROBOT_WHEEL, -1, -1
4745 XwheelB, FALSE, FALSE,
4746 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4749 Xswitch, TRUE, FALSE,
4750 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4753 XswitchB, FALSE, FALSE,
4754 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4758 EL_QUICKSAND_EMPTY, -1, -1
4761 Xsand_stone, TRUE, FALSE,
4762 EL_QUICKSAND_FULL, -1, -1
4765 Xsand_stonein_1, FALSE, TRUE,
4766 EL_ROCK, ACTION_FILLING, -1
4769 Xsand_stonein_2, FALSE, TRUE,
4770 EL_ROCK, ACTION_FILLING, -1
4773 Xsand_stonein_3, FALSE, TRUE,
4774 EL_ROCK, ACTION_FILLING, -1
4777 Xsand_stonein_4, FALSE, TRUE,
4778 EL_ROCK, ACTION_FILLING, -1
4781 Xsand_stonesand_1, FALSE, FALSE,
4782 EL_QUICKSAND_FULL, -1, -1
4785 Xsand_stonesand_2, FALSE, FALSE,
4786 EL_QUICKSAND_FULL, -1, -1
4789 Xsand_stonesand_3, FALSE, FALSE,
4790 EL_QUICKSAND_FULL, -1, -1
4793 Xsand_stonesand_4, FALSE, FALSE,
4794 EL_QUICKSAND_FULL, -1, -1
4797 Xsand_stoneout_1, FALSE, FALSE,
4798 EL_ROCK, ACTION_EMPTYING, -1
4801 Xsand_stoneout_2, FALSE, FALSE,
4802 EL_ROCK, ACTION_EMPTYING, -1
4805 Xsand_sandstone_1, FALSE, FALSE,
4806 EL_QUICKSAND_FULL, -1, -1
4809 Xsand_sandstone_2, FALSE, FALSE,
4810 EL_QUICKSAND_FULL, -1, -1
4813 Xsand_sandstone_3, FALSE, FALSE,
4814 EL_QUICKSAND_FULL, -1, -1
4817 Xsand_sandstone_4, FALSE, FALSE,
4818 EL_QUICKSAND_FULL, -1, -1
4821 Xplant, TRUE, FALSE,
4822 EL_EMC_PLANT, -1, -1
4825 Yplant, FALSE, FALSE,
4826 EL_EMC_PLANT, -1, -1
4829 Xlenses, TRUE, FALSE,
4830 EL_EMC_LENSES, -1, -1
4833 Xmagnify, TRUE, FALSE,
4834 EL_EMC_MAGNIFIER, -1, -1
4837 Xdripper, TRUE, FALSE,
4838 EL_EMC_DRIPPER, -1, -1
4841 XdripperB, FALSE, FALSE,
4842 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4845 Xfake_blank, TRUE, FALSE,
4846 EL_INVISIBLE_WALL, -1, -1
4849 Xfake_blankB, FALSE, FALSE,
4850 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4853 Xfake_grass, TRUE, FALSE,
4854 EL_EMC_FAKE_GRASS, -1, -1
4857 Xfake_grassB, FALSE, FALSE,
4858 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4861 Xfake_door_1, TRUE, FALSE,
4862 EL_EM_GATE_1_GRAY, -1, -1
4865 Xfake_door_2, TRUE, FALSE,
4866 EL_EM_GATE_2_GRAY, -1, -1
4869 Xfake_door_3, TRUE, FALSE,
4870 EL_EM_GATE_3_GRAY, -1, -1
4873 Xfake_door_4, TRUE, FALSE,
4874 EL_EM_GATE_4_GRAY, -1, -1
4877 Xfake_door_5, TRUE, FALSE,
4878 EL_EMC_GATE_5_GRAY, -1, -1
4881 Xfake_door_6, TRUE, FALSE,
4882 EL_EMC_GATE_6_GRAY, -1, -1
4885 Xfake_door_7, TRUE, FALSE,
4886 EL_EMC_GATE_7_GRAY, -1, -1
4889 Xfake_door_8, TRUE, FALSE,
4890 EL_EMC_GATE_8_GRAY, -1, -1
4893 Xfake_acid_1, TRUE, FALSE,
4894 EL_EMC_FAKE_ACID, -1, -1
4897 Xfake_acid_2, FALSE, FALSE,
4898 EL_EMC_FAKE_ACID, -1, -1
4901 Xfake_acid_3, FALSE, FALSE,
4902 EL_EMC_FAKE_ACID, -1, -1
4905 Xfake_acid_4, FALSE, FALSE,
4906 EL_EMC_FAKE_ACID, -1, -1
4909 Xfake_acid_5, FALSE, FALSE,
4910 EL_EMC_FAKE_ACID, -1, -1
4913 Xfake_acid_6, FALSE, FALSE,
4914 EL_EMC_FAKE_ACID, -1, -1
4917 Xfake_acid_7, FALSE, FALSE,
4918 EL_EMC_FAKE_ACID, -1, -1
4921 Xfake_acid_8, FALSE, FALSE,
4922 EL_EMC_FAKE_ACID, -1, -1
4925 Xsteel_1, TRUE, FALSE,
4926 EL_STEELWALL, -1, -1
4929 Xsteel_2, TRUE, FALSE,
4930 EL_EMC_STEELWALL_2, -1, -1
4933 Xsteel_3, TRUE, FALSE,
4934 EL_EMC_STEELWALL_3, -1, -1
4937 Xsteel_4, TRUE, FALSE,
4938 EL_EMC_STEELWALL_4, -1, -1
4941 Xwall_1, TRUE, FALSE,
4945 Xwall_2, TRUE, FALSE,
4946 EL_EMC_WALL_14, -1, -1
4949 Xwall_3, TRUE, FALSE,
4950 EL_EMC_WALL_15, -1, -1
4953 Xwall_4, TRUE, FALSE,
4954 EL_EMC_WALL_16, -1, -1
4957 Xround_wall_1, TRUE, FALSE,
4958 EL_WALL_SLIPPERY, -1, -1
4961 Xround_wall_2, TRUE, FALSE,
4962 EL_EMC_WALL_SLIPPERY_2, -1, -1
4965 Xround_wall_3, TRUE, FALSE,
4966 EL_EMC_WALL_SLIPPERY_3, -1, -1
4969 Xround_wall_4, TRUE, FALSE,
4970 EL_EMC_WALL_SLIPPERY_4, -1, -1
4973 Xdecor_1, TRUE, FALSE,
4974 EL_EMC_WALL_8, -1, -1
4977 Xdecor_2, TRUE, FALSE,
4978 EL_EMC_WALL_6, -1, -1
4981 Xdecor_3, TRUE, FALSE,
4982 EL_EMC_WALL_4, -1, -1
4985 Xdecor_4, TRUE, FALSE,
4986 EL_EMC_WALL_7, -1, -1
4989 Xdecor_5, TRUE, FALSE,
4990 EL_EMC_WALL_5, -1, -1
4993 Xdecor_6, TRUE, FALSE,
4994 EL_EMC_WALL_9, -1, -1
4997 Xdecor_7, TRUE, FALSE,
4998 EL_EMC_WALL_10, -1, -1
5001 Xdecor_8, TRUE, FALSE,
5002 EL_EMC_WALL_1, -1, -1
5005 Xdecor_9, TRUE, FALSE,
5006 EL_EMC_WALL_2, -1, -1
5009 Xdecor_10, TRUE, FALSE,
5010 EL_EMC_WALL_3, -1, -1
5013 Xdecor_11, TRUE, FALSE,
5014 EL_EMC_WALL_11, -1, -1
5017 Xdecor_12, TRUE, FALSE,
5018 EL_EMC_WALL_12, -1, -1
5021 Xalpha_0, TRUE, FALSE,
5022 EL_CHAR('0'), -1, -1
5025 Xalpha_1, TRUE, FALSE,
5026 EL_CHAR('1'), -1, -1
5029 Xalpha_2, TRUE, FALSE,
5030 EL_CHAR('2'), -1, -1
5033 Xalpha_3, TRUE, FALSE,
5034 EL_CHAR('3'), -1, -1
5037 Xalpha_4, TRUE, FALSE,
5038 EL_CHAR('4'), -1, -1
5041 Xalpha_5, TRUE, FALSE,
5042 EL_CHAR('5'), -1, -1
5045 Xalpha_6, TRUE, FALSE,
5046 EL_CHAR('6'), -1, -1
5049 Xalpha_7, TRUE, FALSE,
5050 EL_CHAR('7'), -1, -1
5053 Xalpha_8, TRUE, FALSE,
5054 EL_CHAR('8'), -1, -1
5057 Xalpha_9, TRUE, FALSE,
5058 EL_CHAR('9'), -1, -1
5061 Xalpha_excla, TRUE, FALSE,
5062 EL_CHAR('!'), -1, -1
5065 Xalpha_quote, TRUE, FALSE,
5066 EL_CHAR('"'), -1, -1
5069 Xalpha_comma, TRUE, FALSE,
5070 EL_CHAR(','), -1, -1
5073 Xalpha_minus, TRUE, FALSE,
5074 EL_CHAR('-'), -1, -1
5077 Xalpha_perio, TRUE, FALSE,
5078 EL_CHAR('.'), -1, -1
5081 Xalpha_colon, TRUE, FALSE,
5082 EL_CHAR(':'), -1, -1
5085 Xalpha_quest, TRUE, FALSE,
5086 EL_CHAR('?'), -1, -1
5089 Xalpha_a, TRUE, FALSE,
5090 EL_CHAR('A'), -1, -1
5093 Xalpha_b, TRUE, FALSE,
5094 EL_CHAR('B'), -1, -1
5097 Xalpha_c, TRUE, FALSE,
5098 EL_CHAR('C'), -1, -1
5101 Xalpha_d, TRUE, FALSE,
5102 EL_CHAR('D'), -1, -1
5105 Xalpha_e, TRUE, FALSE,
5106 EL_CHAR('E'), -1, -1
5109 Xalpha_f, TRUE, FALSE,
5110 EL_CHAR('F'), -1, -1
5113 Xalpha_g, TRUE, FALSE,
5114 EL_CHAR('G'), -1, -1
5117 Xalpha_h, TRUE, FALSE,
5118 EL_CHAR('H'), -1, -1
5121 Xalpha_i, TRUE, FALSE,
5122 EL_CHAR('I'), -1, -1
5125 Xalpha_j, TRUE, FALSE,
5126 EL_CHAR('J'), -1, -1
5129 Xalpha_k, TRUE, FALSE,
5130 EL_CHAR('K'), -1, -1
5133 Xalpha_l, TRUE, FALSE,
5134 EL_CHAR('L'), -1, -1
5137 Xalpha_m, TRUE, FALSE,
5138 EL_CHAR('M'), -1, -1
5141 Xalpha_n, TRUE, FALSE,
5142 EL_CHAR('N'), -1, -1
5145 Xalpha_o, TRUE, FALSE,
5146 EL_CHAR('O'), -1, -1
5149 Xalpha_p, TRUE, FALSE,
5150 EL_CHAR('P'), -1, -1
5153 Xalpha_q, TRUE, FALSE,
5154 EL_CHAR('Q'), -1, -1
5157 Xalpha_r, TRUE, FALSE,
5158 EL_CHAR('R'), -1, -1
5161 Xalpha_s, TRUE, FALSE,
5162 EL_CHAR('S'), -1, -1
5165 Xalpha_t, TRUE, FALSE,
5166 EL_CHAR('T'), -1, -1
5169 Xalpha_u, TRUE, FALSE,
5170 EL_CHAR('U'), -1, -1
5173 Xalpha_v, TRUE, FALSE,
5174 EL_CHAR('V'), -1, -1
5177 Xalpha_w, TRUE, FALSE,
5178 EL_CHAR('W'), -1, -1
5181 Xalpha_x, TRUE, FALSE,
5182 EL_CHAR('X'), -1, -1
5185 Xalpha_y, TRUE, FALSE,
5186 EL_CHAR('Y'), -1, -1
5189 Xalpha_z, TRUE, FALSE,
5190 EL_CHAR('Z'), -1, -1
5193 Xalpha_arrow_e, TRUE, FALSE,
5194 EL_CHAR('>'), -1, -1
5197 Xalpha_arrow_w, TRUE, FALSE,
5198 EL_CHAR('<'), -1, -1
5201 Xalpha_copyr, TRUE, FALSE,
5202 EL_CHAR('©'), -1, -1
5206 Xboom_bug, FALSE, FALSE,
5207 EL_BUG, ACTION_EXPLODING, -1
5210 Xboom_bomb, FALSE, FALSE,
5211 EL_BOMB, ACTION_EXPLODING, -1
5214 Xboom_android, FALSE, FALSE,
5215 EL_EMC_ANDROID, ACTION_OTHER, -1
5218 Xboom_1, FALSE, FALSE,
5219 EL_DEFAULT, ACTION_EXPLODING, -1
5222 Xboom_2, FALSE, FALSE,
5223 EL_DEFAULT, ACTION_EXPLODING, -1
5226 Znormal, FALSE, FALSE,
5230 Zdynamite, FALSE, FALSE,
5234 Zplayer, FALSE, FALSE,
5238 ZBORDER, FALSE, FALSE,
5248 static struct Mapping_EM_to_RND_player
5257 em_player_mapping_list[] =
5261 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5265 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5269 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5273 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5277 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5281 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5285 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5289 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5293 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5297 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5301 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5305 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5309 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5313 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5317 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5321 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5325 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5329 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5333 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5337 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5341 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5345 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5349 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5353 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5357 EL_PLAYER_1, ACTION_DEFAULT, -1,
5361 EL_PLAYER_2, ACTION_DEFAULT, -1,
5365 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5369 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5373 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5377 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5381 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5385 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5389 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5393 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5397 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5401 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5405 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5409 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5413 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5417 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5421 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5425 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5429 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5433 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5437 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5441 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5445 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5449 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5453 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5457 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5461 EL_PLAYER_3, ACTION_DEFAULT, -1,
5465 EL_PLAYER_4, ACTION_DEFAULT, -1,
5474 int map_element_RND_to_EM(int element_rnd)
5476 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5477 static boolean mapping_initialized = FALSE;
5479 if (!mapping_initialized)
5483 /* return "Xalpha_quest" for all undefined elements in mapping array */
5484 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5485 mapping_RND_to_EM[i] = Xalpha_quest;
5487 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5488 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5489 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5490 em_object_mapping_list[i].element_em;
5492 mapping_initialized = TRUE;
5495 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5496 return mapping_RND_to_EM[element_rnd];
5498 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5503 int map_element_EM_to_RND(int element_em)
5505 static unsigned short mapping_EM_to_RND[TILE_MAX];
5506 static boolean mapping_initialized = FALSE;
5508 if (!mapping_initialized)
5512 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5513 for (i = 0; i < TILE_MAX; i++)
5514 mapping_EM_to_RND[i] = EL_UNKNOWN;
5516 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5517 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5518 em_object_mapping_list[i].element_rnd;
5520 mapping_initialized = TRUE;
5523 if (element_em >= 0 && element_em < TILE_MAX)
5524 return mapping_EM_to_RND[element_em];
5526 Error(ERR_WARN, "invalid EM level element %d", element_em);
5531 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5533 struct LevelInfo_EM *level_em = level->native_em_level;
5534 struct LEVEL *lev = level_em->lev;
5537 for (i = 0; i < TILE_MAX; i++)
5538 lev->android_array[i] = Xblank;
5540 for (i = 0; i < level->num_android_clone_elements; i++)
5542 int element_rnd = level->android_clone_element[i];
5543 int element_em = map_element_RND_to_EM(element_rnd);
5545 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5546 if (em_object_mapping_list[j].element_rnd == element_rnd)
5547 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5551 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5553 struct LevelInfo_EM *level_em = level->native_em_level;
5554 struct LEVEL *lev = level_em->lev;
5557 level->num_android_clone_elements = 0;
5559 for (i = 0; i < TILE_MAX; i++)
5561 int element_em = lev->android_array[i];
5563 boolean element_found = FALSE;
5565 if (element_em == Xblank)
5568 element_rnd = map_element_EM_to_RND(element_em);
5570 for (j = 0; j < level->num_android_clone_elements; j++)
5571 if (level->android_clone_element[j] == element_rnd)
5572 element_found = TRUE;
5576 level->android_clone_element[level->num_android_clone_elements++] =
5579 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5584 if (level->num_android_clone_elements == 0)
5586 level->num_android_clone_elements = 1;
5587 level->android_clone_element[0] = EL_EMPTY;
5591 int map_direction_RND_to_EM(int direction)
5593 return (direction == MV_UP ? 0 :
5594 direction == MV_RIGHT ? 1 :
5595 direction == MV_DOWN ? 2 :
5596 direction == MV_LEFT ? 3 :
5600 int map_direction_EM_to_RND(int direction)
5602 return (direction == 0 ? MV_UP :
5603 direction == 1 ? MV_RIGHT :
5604 direction == 2 ? MV_DOWN :
5605 direction == 3 ? MV_LEFT :
5609 int get_next_element(int element)
5613 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5614 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5615 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5616 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5617 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5618 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5619 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5620 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5621 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5622 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5623 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5625 default: return element;
5630 int el_act_dir2img(int element, int action, int direction)
5632 element = GFX_ELEMENT(element);
5634 if (direction == MV_NONE)
5635 return element_info[element].graphic[action];
5637 direction = MV_DIR_TO_BIT(direction);
5639 return element_info[element].direction_graphic[action][direction];
5642 int el_act_dir2img(int element, int action, int direction)
5644 element = GFX_ELEMENT(element);
5645 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5647 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5648 return element_info[element].direction_graphic[action][direction];
5653 static int el_act_dir2crm(int element, int action, int direction)
5655 element = GFX_ELEMENT(element);
5657 if (direction == MV_NONE)
5658 return element_info[element].crumbled[action];
5660 direction = MV_DIR_TO_BIT(direction);
5662 return element_info[element].direction_crumbled[action][direction];
5665 static int el_act_dir2crm(int element, int action, int direction)
5667 element = GFX_ELEMENT(element);
5668 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5670 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5671 return element_info[element].direction_crumbled[action][direction];
5675 int el_act2img(int element, int action)
5677 element = GFX_ELEMENT(element);
5679 return element_info[element].graphic[action];
5682 int el_act2crm(int element, int action)
5684 element = GFX_ELEMENT(element);
5686 return element_info[element].crumbled[action];
5689 int el_dir2img(int element, int direction)
5691 element = GFX_ELEMENT(element);
5693 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5696 int el2baseimg(int element)
5698 return element_info[element].graphic[ACTION_DEFAULT];
5701 int el2img(int element)
5703 element = GFX_ELEMENT(element);
5705 return element_info[element].graphic[ACTION_DEFAULT];
5708 int el2edimg(int element)
5710 element = GFX_ELEMENT(element);
5712 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5715 int el2preimg(int element)
5717 element = GFX_ELEMENT(element);
5719 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5722 int font2baseimg(int font_nr)
5724 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5727 int getBeltNrFromBeltElement(int element)
5729 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5730 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5731 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5734 int getBeltNrFromBeltActiveElement(int element)
5736 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5737 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5738 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5741 int getBeltNrFromBeltSwitchElement(int element)
5743 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5744 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5745 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5748 int getBeltDirNrFromBeltElement(int element)
5750 static int belt_base_element[4] =
5752 EL_CONVEYOR_BELT_1_LEFT,
5753 EL_CONVEYOR_BELT_2_LEFT,
5754 EL_CONVEYOR_BELT_3_LEFT,
5755 EL_CONVEYOR_BELT_4_LEFT
5758 int belt_nr = getBeltNrFromBeltElement(element);
5759 int belt_dir_nr = element - belt_base_element[belt_nr];
5761 return (belt_dir_nr % 3);
5764 int getBeltDirNrFromBeltSwitchElement(int element)
5766 static int belt_base_element[4] =
5768 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5769 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5770 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5771 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5774 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5775 int belt_dir_nr = element - belt_base_element[belt_nr];
5777 return (belt_dir_nr % 3);
5780 int getBeltDirFromBeltElement(int element)
5782 static int belt_move_dir[3] =
5789 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5791 return belt_move_dir[belt_dir_nr];
5794 int getBeltDirFromBeltSwitchElement(int element)
5796 static int belt_move_dir[3] =
5803 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5805 return belt_move_dir[belt_dir_nr];
5808 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5810 static int belt_base_element[4] =
5812 EL_CONVEYOR_BELT_1_LEFT,
5813 EL_CONVEYOR_BELT_2_LEFT,
5814 EL_CONVEYOR_BELT_3_LEFT,
5815 EL_CONVEYOR_BELT_4_LEFT
5817 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5819 return belt_base_element[belt_nr] + belt_dir_nr;
5822 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5824 static int belt_base_element[4] =
5826 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5827 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5828 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5829 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5831 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5833 return belt_base_element[belt_nr] + belt_dir_nr;
5836 int getNumActivePlayers_EM()
5838 int num_players = 0;
5844 for (i = 0; i < MAX_PLAYERS; i++)
5845 if (tape.player_participates[i])
5851 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5853 int game_frame_delay_value;
5855 game_frame_delay_value =
5856 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5857 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5860 if (tape.playing && tape.warp_forward && !tape.pausing)
5861 game_frame_delay_value = 0;
5863 return game_frame_delay_value;
5866 unsigned int InitRND(long seed)
5868 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5869 return InitEngineRandom_EM(seed);
5871 return InitEngineRandom_RND(seed);
5875 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5876 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5879 void ResetGfxAnimation_EM(int x, int y, int tile)
5884 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5885 Bitmap **src_bitmap, int *src_x, int *src_y,
5888 int element = object_mapping[tile].element_rnd;
5889 int action = object_mapping[tile].action;
5890 int direction = object_mapping[tile].direction;
5891 boolean is_backside = object_mapping[tile].is_backside;
5892 boolean action_removing = (action == ACTION_DIGGING ||
5893 action == ACTION_SNAPPING ||
5894 action == ACTION_COLLECTING);
5895 int effective_element = (frame_em > 0 ? element :
5896 is_backside ? EL_EMPTY :
5897 action_removing ? EL_EMPTY :
5899 int graphic = (direction == MV_NONE ?
5900 el_act2img(effective_element, action) :
5901 el_act_dir2img(effective_element, action, direction));
5902 struct GraphicInfo *g = &graphic_info[graphic];
5905 if (graphic_info[graphic].anim_global_sync)
5906 sync_frame = FrameCounter;
5908 sync_frame = 7 - frame_em;
5910 SetRandomAnimationValue(x, y);
5912 int frame = getAnimationFrame(g->anim_frames,
5915 g->anim_start_frame,
5918 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5921 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
5922 Bitmap **src_bitmap, int *src_x, int *src_y)
5924 int element = player_mapping[player_nr][anim].element_rnd;
5925 int action = player_mapping[player_nr][anim].action;
5926 int direction = player_mapping[player_nr][anim].direction;
5927 int graphic = (direction == MV_NONE ?
5928 el_act2img(element, action) :
5929 el_act_dir2img(element, action, direction));
5930 struct GraphicInfo *g = &graphic_info[graphic];
5933 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
5935 stored_player[player_nr].StepFrame = 7 - frame_em;
5937 sync_frame = stored_player[player_nr].Frame;
5940 printf("::: %d: %d, %d [%d]\n",
5942 stored_player[player_nr].Frame,
5943 stored_player[player_nr].StepFrame,
5947 int frame = getAnimationFrame(g->anim_frames,
5950 g->anim_start_frame,
5953 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5956 void InitGraphicInfo_EM(void)
5959 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5960 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5965 int num_em_gfx_errors = 0;
5967 if (graphic_info_em_object[0][0].bitmap == NULL)
5969 /* EM graphics not yet initialized in em_open_all() */
5974 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5977 /* always start with reliable default values */
5978 for (i = 0; i < TILE_MAX; i++)
5980 object_mapping[i].element_rnd = EL_UNKNOWN;
5981 object_mapping[i].is_backside = FALSE;
5982 object_mapping[i].action = ACTION_DEFAULT;
5983 object_mapping[i].direction = MV_NONE;
5986 /* always start with reliable default values */
5987 for (p = 0; p < MAX_PLAYERS; p++)
5989 for (i = 0; i < SPR_MAX; i++)
5991 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5992 player_mapping[p][i].action = ACTION_DEFAULT;
5993 player_mapping[p][i].direction = MV_NONE;
5997 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5999 int e = em_object_mapping_list[i].element_em;
6001 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6002 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6004 if (em_object_mapping_list[i].action != -1)
6005 object_mapping[e].action = em_object_mapping_list[i].action;
6007 if (em_object_mapping_list[i].direction != -1)
6008 object_mapping[e].direction =
6009 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6012 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6014 int a = em_player_mapping_list[i].action_em;
6015 int p = em_player_mapping_list[i].player_nr;
6017 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6019 if (em_player_mapping_list[i].action != -1)
6020 player_mapping[p][a].action = em_player_mapping_list[i].action;
6022 if (em_player_mapping_list[i].direction != -1)
6023 player_mapping[p][a].direction =
6024 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6027 for (i = 0; i < TILE_MAX; i++)
6029 int element = object_mapping[i].element_rnd;
6030 int action = object_mapping[i].action;
6031 int direction = object_mapping[i].direction;
6032 boolean is_backside = object_mapping[i].is_backside;
6033 boolean action_removing = (action == ACTION_DIGGING ||
6034 action == ACTION_SNAPPING ||
6035 action == ACTION_COLLECTING);
6036 boolean action_exploding = ((action == ACTION_EXPLODING ||
6037 action == ACTION_SMASHED_BY_ROCK ||
6038 action == ACTION_SMASHED_BY_SPRING) &&
6039 element != EL_DIAMOND);
6040 boolean action_active = (action == ACTION_ACTIVE);
6041 boolean action_other = (action == ACTION_OTHER);
6043 for (j = 0; j < 8; j++)
6045 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6046 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6048 i == Xdrip_stretch ? element :
6049 i == Xdrip_stretchB ? element :
6050 i == Ydrip_s1 ? element :
6051 i == Ydrip_s1B ? element :
6052 i == Xball_1B ? element :
6053 i == Xball_2 ? element :
6054 i == Xball_2B ? element :
6055 i == Yball_eat ? element :
6056 i == Ykey_1_eat ? element :
6057 i == Ykey_2_eat ? element :
6058 i == Ykey_3_eat ? element :
6059 i == Ykey_4_eat ? element :
6060 i == Ykey_5_eat ? element :
6061 i == Ykey_6_eat ? element :
6062 i == Ykey_7_eat ? element :
6063 i == Ykey_8_eat ? element :
6064 i == Ylenses_eat ? element :
6065 i == Ymagnify_eat ? element :
6066 i == Ygrass_eat ? element :
6067 i == Ydirt_eat ? element :
6068 i == Yemerald_stone ? EL_EMERALD :
6069 i == Ydiamond_stone ? EL_ROCK :
6070 i == Xsand_stonein_1 ? element :
6071 i == Xsand_stonein_2 ? element :
6072 i == Xsand_stonein_3 ? element :
6073 i == Xsand_stonein_4 ? element :
6074 is_backside ? EL_EMPTY :
6075 action_removing ? EL_EMPTY :
6077 int effective_action = (j < 7 ? action :
6078 i == Xdrip_stretch ? action :
6079 i == Xdrip_stretchB ? action :
6080 i == Ydrip_s1 ? action :
6081 i == Ydrip_s1B ? action :
6082 i == Xball_1B ? action :
6083 i == Xball_2 ? action :
6084 i == Xball_2B ? action :
6085 i == Yball_eat ? action :
6086 i == Ykey_1_eat ? action :
6087 i == Ykey_2_eat ? action :
6088 i == Ykey_3_eat ? action :
6089 i == Ykey_4_eat ? action :
6090 i == Ykey_5_eat ? action :
6091 i == Ykey_6_eat ? action :
6092 i == Ykey_7_eat ? action :
6093 i == Ykey_8_eat ? action :
6094 i == Ylenses_eat ? action :
6095 i == Ymagnify_eat ? action :
6096 i == Ygrass_eat ? action :
6097 i == Ydirt_eat ? action :
6098 i == Xsand_stonein_1 ? action :
6099 i == Xsand_stonein_2 ? action :
6100 i == Xsand_stonein_3 ? action :
6101 i == Xsand_stonein_4 ? action :
6102 i == Xsand_stoneout_1 ? action :
6103 i == Xsand_stoneout_2 ? action :
6104 i == Xboom_android ? ACTION_EXPLODING :
6105 action_exploding ? ACTION_EXPLODING :
6106 action_active ? action :
6107 action_other ? action :
6109 int graphic = (el_act_dir2img(effective_element, effective_action,
6111 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6113 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6114 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6115 boolean has_action_graphics = (graphic != base_graphic);
6116 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6117 struct GraphicInfo *g = &graphic_info[graphic];
6118 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6121 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6122 boolean special_animation = (action != ACTION_DEFAULT &&
6123 g->anim_frames == 3 &&
6124 g->anim_delay == 2 &&
6125 g->anim_mode & ANIM_LINEAR);
6126 int sync_frame = (i == Xdrip_stretch ? 7 :
6127 i == Xdrip_stretchB ? 7 :
6128 i == Ydrip_s2 ? j + 8 :
6129 i == Ydrip_s2B ? j + 8 :
6138 i == Xfake_acid_1 ? 0 :
6139 i == Xfake_acid_2 ? 10 :
6140 i == Xfake_acid_3 ? 20 :
6141 i == Xfake_acid_4 ? 30 :
6142 i == Xfake_acid_5 ? 40 :
6143 i == Xfake_acid_6 ? 50 :
6144 i == Xfake_acid_7 ? 60 :
6145 i == Xfake_acid_8 ? 70 :
6147 i == Xball_2B ? j + 8 :
6148 i == Yball_eat ? j + 1 :
6149 i == Ykey_1_eat ? j + 1 :
6150 i == Ykey_2_eat ? j + 1 :
6151 i == Ykey_3_eat ? j + 1 :
6152 i == Ykey_4_eat ? j + 1 :
6153 i == Ykey_5_eat ? j + 1 :
6154 i == Ykey_6_eat ? j + 1 :
6155 i == Ykey_7_eat ? j + 1 :
6156 i == Ykey_8_eat ? j + 1 :
6157 i == Ylenses_eat ? j + 1 :
6158 i == Ymagnify_eat ? j + 1 :
6159 i == Ygrass_eat ? j + 1 :
6160 i == Ydirt_eat ? j + 1 :
6161 i == Xamoeba_1 ? 0 :
6162 i == Xamoeba_2 ? 1 :
6163 i == Xamoeba_3 ? 2 :
6164 i == Xamoeba_4 ? 3 :
6165 i == Xamoeba_5 ? 0 :
6166 i == Xamoeba_6 ? 1 :
6167 i == Xamoeba_7 ? 2 :
6168 i == Xamoeba_8 ? 3 :
6169 i == Xexit_2 ? j + 8 :
6170 i == Xexit_3 ? j + 16 :
6171 i == Xdynamite_1 ? 0 :
6172 i == Xdynamite_2 ? 8 :
6173 i == Xdynamite_3 ? 16 :
6174 i == Xdynamite_4 ? 24 :
6175 i == Xsand_stonein_1 ? j + 1 :
6176 i == Xsand_stonein_2 ? j + 9 :
6177 i == Xsand_stonein_3 ? j + 17 :
6178 i == Xsand_stonein_4 ? j + 25 :
6179 i == Xsand_stoneout_1 && j == 0 ? 0 :
6180 i == Xsand_stoneout_1 && j == 1 ? 0 :
6181 i == Xsand_stoneout_1 && j == 2 ? 1 :
6182 i == Xsand_stoneout_1 && j == 3 ? 2 :
6183 i == Xsand_stoneout_1 && j == 4 ? 2 :
6184 i == Xsand_stoneout_1 && j == 5 ? 3 :
6185 i == Xsand_stoneout_1 && j == 6 ? 4 :
6186 i == Xsand_stoneout_1 && j == 7 ? 4 :
6187 i == Xsand_stoneout_2 && j == 0 ? 5 :
6188 i == Xsand_stoneout_2 && j == 1 ? 6 :
6189 i == Xsand_stoneout_2 && j == 2 ? 7 :
6190 i == Xsand_stoneout_2 && j == 3 ? 8 :
6191 i == Xsand_stoneout_2 && j == 4 ? 9 :
6192 i == Xsand_stoneout_2 && j == 5 ? 11 :
6193 i == Xsand_stoneout_2 && j == 6 ? 13 :
6194 i == Xsand_stoneout_2 && j == 7 ? 15 :
6195 i == Xboom_bug && j == 1 ? 2 :
6196 i == Xboom_bug && j == 2 ? 2 :
6197 i == Xboom_bug && j == 3 ? 4 :
6198 i == Xboom_bug && j == 4 ? 4 :
6199 i == Xboom_bug && j == 5 ? 2 :
6200 i == Xboom_bug && j == 6 ? 2 :
6201 i == Xboom_bug && j == 7 ? 0 :
6202 i == Xboom_bomb && j == 1 ? 2 :
6203 i == Xboom_bomb && j == 2 ? 2 :
6204 i == Xboom_bomb && j == 3 ? 4 :
6205 i == Xboom_bomb && j == 4 ? 4 :
6206 i == Xboom_bomb && j == 5 ? 2 :
6207 i == Xboom_bomb && j == 6 ? 2 :
6208 i == Xboom_bomb && j == 7 ? 0 :
6209 i == Xboom_android && j == 7 ? 6 :
6210 i == Xboom_1 && j == 1 ? 2 :
6211 i == Xboom_1 && j == 2 ? 2 :
6212 i == Xboom_1 && j == 3 ? 4 :
6213 i == Xboom_1 && j == 4 ? 4 :
6214 i == Xboom_1 && j == 5 ? 6 :
6215 i == Xboom_1 && j == 6 ? 6 :
6216 i == Xboom_1 && j == 7 ? 8 :
6217 i == Xboom_2 && j == 0 ? 8 :
6218 i == Xboom_2 && j == 1 ? 8 :
6219 i == Xboom_2 && j == 2 ? 10 :
6220 i == Xboom_2 && j == 3 ? 10 :
6221 i == Xboom_2 && j == 4 ? 10 :
6222 i == Xboom_2 && j == 5 ? 12 :
6223 i == Xboom_2 && j == 6 ? 12 :
6224 i == Xboom_2 && j == 7 ? 12 :
6225 special_animation && j == 4 ? 3 :
6226 effective_action != action ? 0 :
6230 Bitmap *debug_bitmap = g_em->bitmap;
6231 int debug_src_x = g_em->src_x;
6232 int debug_src_y = g_em->src_y;
6235 int frame = getAnimationFrame(g->anim_frames,
6238 g->anim_start_frame,
6241 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6242 g->double_movement && is_backside);
6244 g_em->bitmap = src_bitmap;
6245 g_em->src_x = src_x;
6246 g_em->src_y = src_y;
6247 g_em->src_offset_x = 0;
6248 g_em->src_offset_y = 0;
6249 g_em->dst_offset_x = 0;
6250 g_em->dst_offset_y = 0;
6251 g_em->width = TILEX;
6252 g_em->height = TILEY;
6254 g_em->crumbled_bitmap = NULL;
6255 g_em->crumbled_src_x = 0;
6256 g_em->crumbled_src_y = 0;
6257 g_em->crumbled_border_size = 0;
6259 g_em->has_crumbled_graphics = FALSE;
6260 g_em->preserve_background = FALSE;
6263 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6264 printf("::: empty crumbled: %d [%s], %d, %d\n",
6265 effective_element, element_info[effective_element].token_name,
6266 effective_action, direction);
6269 /* if element can be crumbled, but certain action graphics are just empty
6270 space (like snapping sand with the original R'n'D graphics), do not
6271 treat these empty space graphics as crumbled graphics in EMC engine */
6272 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6274 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6276 g_em->has_crumbled_graphics = TRUE;
6277 g_em->crumbled_bitmap = src_bitmap;
6278 g_em->crumbled_src_x = src_x;
6279 g_em->crumbled_src_y = src_y;
6280 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6284 if (element == EL_ROCK &&
6285 effective_action == ACTION_FILLING)
6286 printf("::: has_action_graphics == %d\n", has_action_graphics);
6289 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6290 effective_action == ACTION_MOVING ||
6291 effective_action == ACTION_PUSHING ||
6292 effective_action == ACTION_EATING)) ||
6293 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6294 effective_action == ACTION_EMPTYING)))
6297 (effective_action == ACTION_FALLING ||
6298 effective_action == ACTION_FILLING ||
6299 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6300 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6301 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6302 int num_steps = (i == Ydrip_s1 ? 16 :
6303 i == Ydrip_s1B ? 16 :
6304 i == Ydrip_s2 ? 16 :
6305 i == Ydrip_s2B ? 16 :
6306 i == Xsand_stonein_1 ? 32 :
6307 i == Xsand_stonein_2 ? 32 :
6308 i == Xsand_stonein_3 ? 32 :
6309 i == Xsand_stonein_4 ? 32 :
6310 i == Xsand_stoneout_1 ? 16 :
6311 i == Xsand_stoneout_2 ? 16 : 8);
6312 int cx = ABS(dx) * (TILEX / num_steps);
6313 int cy = ABS(dy) * (TILEY / num_steps);
6314 int step_frame = (i == Ydrip_s2 ? j + 8 :
6315 i == Ydrip_s2B ? j + 8 :
6316 i == Xsand_stonein_2 ? j + 8 :
6317 i == Xsand_stonein_3 ? j + 16 :
6318 i == Xsand_stonein_4 ? j + 24 :
6319 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6320 int step = (is_backside ? step_frame : num_steps - step_frame);
6322 if (is_backside) /* tile where movement starts */
6324 if (dx < 0 || dy < 0)
6326 g_em->src_offset_x = cx * step;
6327 g_em->src_offset_y = cy * step;
6331 g_em->dst_offset_x = cx * step;
6332 g_em->dst_offset_y = cy * step;
6335 else /* tile where movement ends */
6337 if (dx < 0 || dy < 0)
6339 g_em->dst_offset_x = cx * step;
6340 g_em->dst_offset_y = cy * step;
6344 g_em->src_offset_x = cx * step;
6345 g_em->src_offset_y = cy * step;
6349 g_em->width = TILEX - cx * step;
6350 g_em->height = TILEY - cy * step;
6353 /* create unique graphic identifier to decide if tile must be redrawn */
6354 /* bit 31 - 16 (16 bit): EM style graphic
6355 bit 15 - 12 ( 4 bit): EM style frame
6356 bit 11 - 6 ( 6 bit): graphic width
6357 bit 5 - 0 ( 6 bit): graphic height */
6358 g_em->unique_identifier =
6359 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6363 /* skip check for EMC elements not contained in original EMC artwork */
6364 if (element == EL_EMC_FAKE_ACID)
6367 if (g_em->bitmap != debug_bitmap ||
6368 g_em->src_x != debug_src_x ||
6369 g_em->src_y != debug_src_y ||
6370 g_em->src_offset_x != 0 ||
6371 g_em->src_offset_y != 0 ||
6372 g_em->dst_offset_x != 0 ||
6373 g_em->dst_offset_y != 0 ||
6374 g_em->width != TILEX ||
6375 g_em->height != TILEY)
6377 static int last_i = -1;
6385 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6386 i, element, element_info[element].token_name,
6387 element_action_info[effective_action].suffix, direction);
6389 if (element != effective_element)
6390 printf(" [%d ('%s')]",
6392 element_info[effective_element].token_name);
6396 if (g_em->bitmap != debug_bitmap)
6397 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6398 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6400 if (g_em->src_x != debug_src_x ||
6401 g_em->src_y != debug_src_y)
6402 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6403 j, (is_backside ? 'B' : 'F'),
6404 g_em->src_x, g_em->src_y,
6405 g_em->src_x / 32, g_em->src_y / 32,
6406 debug_src_x, debug_src_y,
6407 debug_src_x / 32, debug_src_y / 32);
6409 if (g_em->src_offset_x != 0 ||
6410 g_em->src_offset_y != 0 ||
6411 g_em->dst_offset_x != 0 ||
6412 g_em->dst_offset_y != 0)
6413 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6415 g_em->src_offset_x, g_em->src_offset_y,
6416 g_em->dst_offset_x, g_em->dst_offset_y);
6418 if (g_em->width != TILEX ||
6419 g_em->height != TILEY)
6420 printf(" %d (%d): size %d,%d should be %d,%d\n",
6422 g_em->width, g_em->height, TILEX, TILEY);
6424 num_em_gfx_errors++;
6431 for (i = 0; i < TILE_MAX; i++)
6433 for (j = 0; j < 8; j++)
6435 int element = object_mapping[i].element_rnd;
6436 int action = object_mapping[i].action;
6437 int direction = object_mapping[i].direction;
6438 boolean is_backside = object_mapping[i].is_backside;
6439 int graphic_action = el_act_dir2img(element, action, direction);
6440 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6442 if ((action == ACTION_SMASHED_BY_ROCK ||
6443 action == ACTION_SMASHED_BY_SPRING ||
6444 action == ACTION_EATING) &&
6445 graphic_action == graphic_default)
6447 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6448 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6449 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6450 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6453 /* no separate animation for "smashed by rock" -- use rock instead */
6454 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6455 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6457 g_em->bitmap = g_xx->bitmap;
6458 g_em->src_x = g_xx->src_x;
6459 g_em->src_y = g_xx->src_y;
6460 g_em->src_offset_x = g_xx->src_offset_x;
6461 g_em->src_offset_y = g_xx->src_offset_y;
6462 g_em->dst_offset_x = g_xx->dst_offset_x;
6463 g_em->dst_offset_y = g_xx->dst_offset_y;
6464 g_em->width = g_xx->width;
6465 g_em->height = g_xx->height;
6466 g_em->unique_identifier = g_xx->unique_identifier;
6469 g_em->preserve_background = TRUE;
6474 for (p = 0; p < MAX_PLAYERS; p++)
6476 for (i = 0; i < SPR_MAX; i++)
6478 int element = player_mapping[p][i].element_rnd;
6479 int action = player_mapping[p][i].action;
6480 int direction = player_mapping[p][i].direction;
6482 for (j = 0; j < 8; j++)
6484 int effective_element = element;
6485 int effective_action = action;
6486 int graphic = (direction == MV_NONE ?
6487 el_act2img(effective_element, effective_action) :
6488 el_act_dir2img(effective_element, effective_action,
6490 struct GraphicInfo *g = &graphic_info[graphic];
6491 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6497 Bitmap *debug_bitmap = g_em->bitmap;
6498 int debug_src_x = g_em->src_x;
6499 int debug_src_y = g_em->src_y;
6502 int frame = getAnimationFrame(g->anim_frames,
6505 g->anim_start_frame,
6508 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6510 g_em->bitmap = src_bitmap;
6511 g_em->src_x = src_x;
6512 g_em->src_y = src_y;
6513 g_em->src_offset_x = 0;
6514 g_em->src_offset_y = 0;
6515 g_em->dst_offset_x = 0;
6516 g_em->dst_offset_y = 0;
6517 g_em->width = TILEX;
6518 g_em->height = TILEY;
6522 /* skip check for EMC elements not contained in original EMC artwork */
6523 if (element == EL_PLAYER_3 ||
6524 element == EL_PLAYER_4)
6527 if (g_em->bitmap != debug_bitmap ||
6528 g_em->src_x != debug_src_x ||
6529 g_em->src_y != debug_src_y)
6531 static int last_i = -1;
6539 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6540 p, i, element, element_info[element].token_name,
6541 element_action_info[effective_action].suffix, direction);
6543 if (element != effective_element)
6544 printf(" [%d ('%s')]",
6546 element_info[effective_element].token_name);
6550 if (g_em->bitmap != debug_bitmap)
6551 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6552 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6554 if (g_em->src_x != debug_src_x ||
6555 g_em->src_y != debug_src_y)
6556 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6558 g_em->src_x, g_em->src_y,
6559 g_em->src_x / 32, g_em->src_y / 32,
6560 debug_src_x, debug_src_y,
6561 debug_src_x / 32, debug_src_y / 32);
6563 num_em_gfx_errors++;
6573 printf("::: [%d errors found]\n", num_em_gfx_errors);
6579 void PlayMenuSoundExt(int sound)
6581 if (sound == SND_UNDEFINED)
6584 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6585 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6588 if (IS_LOOP_SOUND(sound))
6589 PlaySoundLoop(sound);
6594 void PlayMenuSound()
6596 PlayMenuSoundExt(menu.sound[game_status]);
6599 void PlayMenuSoundStereo(int sound, int stereo_position)
6601 if (sound == SND_UNDEFINED)
6604 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6605 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6608 if (IS_LOOP_SOUND(sound))
6609 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6611 PlaySoundStereo(sound, stereo_position);
6614 void PlayMenuSoundIfLoopExt(int sound)
6616 if (sound == SND_UNDEFINED)
6619 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6620 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6623 if (IS_LOOP_SOUND(sound))
6624 PlaySoundLoop(sound);
6627 void PlayMenuSoundIfLoop()
6629 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6632 void PlayMenuMusicExt(int music)
6634 if (music == MUS_UNDEFINED)
6637 if (!setup.sound_music)
6643 void PlayMenuMusic()
6645 PlayMenuMusicExt(menu.music[game_status]);
6648 void PlaySoundActivating()
6651 PlaySound(SND_MENU_ITEM_ACTIVATING);
6655 void PlaySoundSelecting()
6658 PlaySound(SND_MENU_ITEM_SELECTING);
6662 void ToggleFullscreenIfNeeded()
6664 boolean change_fullscreen = (setup.fullscreen !=
6665 video.fullscreen_enabled);
6666 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6667 !strEqual(setup.fullscreen_mode,
6668 video.fullscreen_mode_current));
6670 if (!video.fullscreen_available)
6674 if (change_fullscreen || change_fullscreen_mode)
6676 if (setup.fullscreen != video.fullscreen_enabled ||
6677 setup.fullscreen_mode != video.fullscreen_mode_current)
6680 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6682 /* save backbuffer content which gets lost when toggling fullscreen mode */
6683 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6686 if (change_fullscreen_mode)
6688 if (setup.fullscreen && video.fullscreen_enabled)
6691 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6693 /* (this is now set in sdl.c) */
6695 video.fullscreen_mode_current = setup.fullscreen_mode;
6697 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6700 /* toggle fullscreen */
6701 ChangeVideoModeIfNeeded(setup.fullscreen);
6703 setup.fullscreen = video.fullscreen_enabled;
6705 /* restore backbuffer content from temporary backbuffer backup bitmap */
6706 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6708 FreeBitmap(tmp_backbuffer);
6711 /* update visible window/screen */
6712 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6714 redraw_mask = REDRAW_ALL;