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 (fading.fade_mode == FADE_MODE_NONE)
565 if (fade_mask & REDRAW_FIELD)
570 height = FULL_SYSIZE;
572 fade_delay = fading.fade_delay;
573 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
575 draw_border_function = DrawMaskedBorder_FIELD;
577 else /* REDRAW_ALL */
584 fade_delay = fading.fade_delay;
585 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
589 if (!setup.fade_screens || fade_delay == 0)
591 if (!setup.fade_screens || fade_delay == 0 || fading.anim_mode == ANIM_NONE)
594 if (fade_mode == FADE_MODE_FADE_OUT)
595 ClearRectangle(backbuffer, x, y, width, height);
602 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
603 draw_border_function);
605 redraw_mask &= ~fade_mask;
608 void FadeIn(int fade_mask)
611 // printf("::: now fading in...\n");
613 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
614 FadeExt(fade_mask, fading.fade_mode);
616 FadeExt(fade_mask, FADE_MODE_FADE_IN);
619 if (fading.fade_mode == FADE_MODE_CROSSFADE)
620 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
622 FadeExt(fade_mask, FADE_MODE_FADE_IN);
624 FadeExt(fade_mask, FADE_MODE_FADE_IN);
629 void FadeOut(int fade_mask)
632 // printf("::: fading.fade_mode == %d\n", fading.fade_mode);
634 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
635 FadeCrossSaveBackbuffer();
637 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
640 if (fading.fade_mode == FADE_MODE_CROSSFADE)
641 FadeCrossSaveBackbuffer();
643 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
645 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
650 void FadeCross(int fade_mask)
652 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
655 void FadeCrossSaveBackbuffer()
657 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
660 void FadeSetEnterMenu()
662 fading = menu.enter_menu;
665 void FadeSetLeaveMenu()
667 fading = menu.leave_menu;
670 void FadeSetStartItem()
672 fading = menu.start_item;
675 void FadeSetFromType(int type)
677 if (type & TYPE_ENTER_SCREEN)
679 else if (type & TYPE_ENTER)
681 else if (type & TYPE_LEAVE)
685 void FadeSetDisabled()
687 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
689 fading = fading_none;
692 void FadeSkipNextFadeIn()
694 FadeExt(0, FADE_MODE_SKIP_FADE_IN);
697 void FadeSkipNextFadeOut()
699 FadeExt(0, FADE_MODE_SKIP_FADE_OUT);
702 void SetWindowBackgroundImageIfDefined(int graphic)
704 if (graphic_info[graphic].bitmap)
705 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
708 void SetMainBackgroundImageIfDefined(int graphic)
710 if (graphic_info[graphic].bitmap)
711 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
714 void SetDoorBackgroundImageIfDefined(int graphic)
716 if (graphic_info[graphic].bitmap)
717 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
720 void SetWindowBackgroundImage(int graphic)
722 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
723 graphic_info[graphic].bitmap ?
724 graphic_info[graphic].bitmap :
725 graphic_info[IMG_BACKGROUND].bitmap);
728 void SetMainBackgroundImage(int graphic)
730 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
731 graphic_info[graphic].bitmap ?
732 graphic_info[graphic].bitmap :
733 graphic_info[IMG_BACKGROUND].bitmap);
736 void SetDoorBackgroundImage(int graphic)
738 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
739 graphic_info[graphic].bitmap ?
740 graphic_info[graphic].bitmap :
741 graphic_info[IMG_BACKGROUND].bitmap);
744 void SetPanelBackground()
746 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
747 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
749 SetDoorBackgroundBitmap(bitmap_db_panel);
752 void DrawBackground(int x, int y, int width, int height)
754 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
755 /* (when entering hall of fame after playing) */
757 ClearRectangleOnBackground(drawto, x, y, width, height);
759 ClearRectangleOnBackground(backbuffer, x, y, width, height);
762 redraw_mask |= REDRAW_FIELD;
765 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
767 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
769 if (font->bitmap == NULL)
772 DrawBackground(x, y, width, height);
775 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
777 struct GraphicInfo *g = &graphic_info[graphic];
779 if (g->bitmap == NULL)
782 DrawBackground(x, y, width, height);
787 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
788 /* (when entering hall of fame after playing) */
789 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
791 /* !!! maybe this should be done before clearing the background !!! */
792 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
794 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
795 SetDrawtoField(DRAW_BUFFERED);
798 SetDrawtoField(DRAW_BACKBUFFER);
800 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
802 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
803 SetDrawtoField(DRAW_DIRECT);
807 void MarkTileDirty(int x, int y)
809 int xx = redraw_x1 + x;
810 int yy = redraw_y1 + y;
815 redraw[xx][yy] = TRUE;
816 redraw_mask |= REDRAW_TILES;
819 void SetBorderElement()
823 BorderElement = EL_EMPTY;
825 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
827 for (x = 0; x < lev_fieldx; x++)
829 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
830 BorderElement = EL_STEELWALL;
832 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
838 void FloodFillLevel(int from_x, int from_y, int fill_element,
839 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
840 int max_fieldx, int max_fieldy)
844 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
845 static int safety = 0;
847 /* check if starting field still has the desired content */
848 if (field[from_x][from_y] == fill_element)
853 if (safety > max_fieldx * max_fieldy)
854 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
856 old_element = field[from_x][from_y];
857 field[from_x][from_y] = fill_element;
859 for (i = 0; i < 4; i++)
861 x = from_x + check[i][0];
862 y = from_y + check[i][1];
864 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
865 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
871 void SetRandomAnimationValue(int x, int y)
873 gfx.anim_random_frame = GfxRandom[x][y];
876 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
878 /* animation synchronized with global frame counter, not move position */
879 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
880 sync_frame = FrameCounter;
882 return getAnimationFrame(graphic_info[graphic].anim_frames,
883 graphic_info[graphic].anim_delay,
884 graphic_info[graphic].anim_mode,
885 graphic_info[graphic].anim_start_frame,
889 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
890 int *x, int *y, boolean get_backside)
892 struct GraphicInfo *g = &graphic_info[graphic];
893 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
894 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
898 if (g->offset_y == 0) /* frames are ordered horizontally */
900 int max_width = g->anim_frames_per_line * g->width;
901 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
903 *x = pos % max_width;
904 *y = src_y % g->height + pos / max_width * g->height;
906 else if (g->offset_x == 0) /* frames are ordered vertically */
908 int max_height = g->anim_frames_per_line * g->height;
909 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
911 *x = src_x % g->width + pos / max_height * g->width;
912 *y = pos % max_height;
914 else /* frames are ordered diagonally */
916 *x = src_x + frame * g->offset_x;
917 *y = src_y + frame * g->offset_y;
921 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
923 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
926 void DrawGraphic(int x, int y, int graphic, int frame)
929 if (!IN_SCR_FIELD(x, y))
931 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
932 printf("DrawGraphic(): This should never happen!\n");
937 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
941 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
947 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
948 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
951 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
954 if (!IN_SCR_FIELD(x, y))
956 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
957 printf("DrawGraphicThruMask(): This should never happen!\n");
962 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
967 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
973 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
975 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
976 dst_x - src_x, dst_y - src_y);
977 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
980 void DrawMiniGraphic(int x, int y, int graphic)
982 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
983 MarkTileDirty(x / 2, y / 2);
986 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
988 struct GraphicInfo *g = &graphic_info[graphic];
990 int mini_starty = g->bitmap->height * 2 / 3;
993 *x = mini_startx + g->src_x / 2;
994 *y = mini_starty + g->src_y / 2;
997 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1002 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1003 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1006 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1007 int graphic, int frame,
1008 int cut_mode, int mask_mode)
1013 int width = TILEX, height = TILEY;
1016 if (dx || dy) /* shifted graphic */
1018 if (x < BX1) /* object enters playfield from the left */
1025 else if (x > BX2) /* object enters playfield from the right */
1031 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1037 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1039 else if (dx) /* general horizontal movement */
1040 MarkTileDirty(x + SIGN(dx), y);
1042 if (y < BY1) /* object enters playfield from the top */
1044 if (cut_mode==CUT_BELOW) /* object completely above top border */
1052 else if (y > BY2) /* object enters playfield from the bottom */
1058 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1064 else if (dy > 0 && cut_mode == CUT_ABOVE)
1066 if (y == BY2) /* object completely above bottom border */
1072 MarkTileDirty(x, y + 1);
1073 } /* object leaves playfield to the bottom */
1074 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1076 else if (dy) /* general vertical movement */
1077 MarkTileDirty(x, y + SIGN(dy));
1081 if (!IN_SCR_FIELD(x, y))
1083 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1084 printf("DrawGraphicShifted(): This should never happen!\n");
1089 if (width > 0 && height > 0)
1091 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1096 dst_x = FX + x * TILEX + dx;
1097 dst_y = FY + y * TILEY + dy;
1099 if (mask_mode == USE_MASKING)
1101 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1102 dst_x - src_x, dst_y - src_y);
1103 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1107 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1110 MarkTileDirty(x, y);
1114 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1115 int graphic, int frame,
1116 int cut_mode, int mask_mode)
1121 int width = TILEX, height = TILEY;
1124 int x2 = x + SIGN(dx);
1125 int y2 = y + SIGN(dy);
1126 int anim_frames = graphic_info[graphic].anim_frames;
1127 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1128 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1129 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1131 /* re-calculate animation frame for two-tile movement animation */
1132 frame = getGraphicAnimationFrame(graphic, sync_frame);
1134 /* check if movement start graphic inside screen area and should be drawn */
1135 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1137 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1139 dst_x = FX + x1 * TILEX;
1140 dst_y = FY + y1 * TILEY;
1142 if (mask_mode == USE_MASKING)
1144 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1145 dst_x - src_x, dst_y - src_y);
1146 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1150 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1153 MarkTileDirty(x1, y1);
1156 /* check if movement end graphic inside screen area and should be drawn */
1157 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1159 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1161 dst_x = FX + x2 * TILEX;
1162 dst_y = FY + y2 * TILEY;
1164 if (mask_mode == USE_MASKING)
1166 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1167 dst_x - src_x, dst_y - src_y);
1168 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1172 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1175 MarkTileDirty(x2, y2);
1179 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1180 int graphic, int frame,
1181 int cut_mode, int mask_mode)
1185 DrawGraphic(x, y, graphic, frame);
1190 if (graphic_info[graphic].double_movement) /* EM style movement images */
1191 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1193 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1196 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1197 int frame, int cut_mode)
1199 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1202 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1203 int cut_mode, int mask_mode)
1205 int lx = LEVELX(x), ly = LEVELY(y);
1209 if (IN_LEV_FIELD(lx, ly))
1211 SetRandomAnimationValue(lx, ly);
1213 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1214 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1216 /* do not use double (EM style) movement graphic when not moving */
1217 if (graphic_info[graphic].double_movement && !dx && !dy)
1219 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1220 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1223 else /* border element */
1225 graphic = el2img(element);
1226 frame = getGraphicAnimationFrame(graphic, -1);
1229 if (element == EL_EXPANDABLE_WALL)
1231 boolean left_stopped = FALSE, right_stopped = FALSE;
1233 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1234 left_stopped = TRUE;
1235 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1236 right_stopped = TRUE;
1238 if (left_stopped && right_stopped)
1240 else if (left_stopped)
1242 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1243 frame = graphic_info[graphic].anim_frames - 1;
1245 else if (right_stopped)
1247 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1248 frame = graphic_info[graphic].anim_frames - 1;
1253 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1254 else if (mask_mode == USE_MASKING)
1255 DrawGraphicThruMask(x, y, graphic, frame);
1257 DrawGraphic(x, y, graphic, frame);
1260 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1261 int cut_mode, int mask_mode)
1263 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1264 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1265 cut_mode, mask_mode);
1268 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1271 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1274 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1277 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1280 void DrawLevelElementThruMask(int x, int y, int element)
1282 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1285 void DrawLevelFieldThruMask(int x, int y)
1287 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1290 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1294 int sx = SCREENX(x), sy = SCREENY(y);
1296 int width, height, cx, cy, i;
1297 int crumbled_border_size = graphic_info[graphic].border_size;
1298 static int xy[4][2] =
1306 if (!IN_LEV_FIELD(x, y))
1309 element = TILE_GFX_ELEMENT(x, y);
1311 /* crumble field itself */
1312 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1314 if (!IN_SCR_FIELD(sx, sy))
1317 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1319 for (i = 0; i < 4; i++)
1321 int xx = x + xy[i][0];
1322 int yy = y + xy[i][1];
1324 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1327 /* check if neighbour field is of same type */
1328 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1331 if (i == 1 || i == 2)
1333 width = crumbled_border_size;
1335 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1341 height = crumbled_border_size;
1343 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1346 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1347 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1350 MarkTileDirty(sx, sy);
1352 else /* crumble neighbour fields */
1354 for (i = 0; i < 4; i++)
1356 int xx = x + xy[i][0];
1357 int yy = y + xy[i][1];
1358 int sxx = sx + xy[i][0];
1359 int syy = sy + xy[i][1];
1361 if (!IN_LEV_FIELD(xx, yy) ||
1362 !IN_SCR_FIELD(sxx, syy) ||
1366 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1369 element = TILE_GFX_ELEMENT(xx, yy);
1371 if (!GFX_CRUMBLED(element))
1374 graphic = el_act2crm(element, ACTION_DEFAULT);
1375 crumbled_border_size = graphic_info[graphic].border_size;
1377 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1379 if (i == 1 || i == 2)
1381 width = crumbled_border_size;
1383 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1389 height = crumbled_border_size;
1391 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1394 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1395 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1397 MarkTileDirty(sxx, syy);
1402 void DrawLevelFieldCrumbledSand(int x, int y)
1406 if (!IN_LEV_FIELD(x, y))
1410 /* !!! CHECK THIS !!! */
1413 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1414 GFX_CRUMBLED(GfxElement[x][y]))
1417 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1418 GfxElement[x][y] != EL_UNDEFINED &&
1419 GFX_CRUMBLED(GfxElement[x][y]))
1421 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1428 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1430 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1433 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1436 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1439 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1440 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1441 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1442 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1443 int sx = SCREENX(x), sy = SCREENY(y);
1445 DrawGraphic(sx, sy, graphic1, frame1);
1446 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1449 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1451 int sx = SCREENX(x), sy = SCREENY(y);
1452 static int xy[4][2] =
1461 for (i = 0; i < 4; i++)
1463 int xx = x + xy[i][0];
1464 int yy = y + xy[i][1];
1465 int sxx = sx + xy[i][0];
1466 int syy = sy + xy[i][1];
1468 if (!IN_LEV_FIELD(xx, yy) ||
1469 !IN_SCR_FIELD(sxx, syy) ||
1470 !GFX_CRUMBLED(Feld[xx][yy]) ||
1474 DrawLevelField(xx, yy);
1478 static int getBorderElement(int x, int y)
1482 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1483 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1484 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1485 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1486 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1487 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1488 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1490 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1491 int steel_position = (x == -1 && y == -1 ? 0 :
1492 x == lev_fieldx && y == -1 ? 1 :
1493 x == -1 && y == lev_fieldy ? 2 :
1494 x == lev_fieldx && y == lev_fieldy ? 3 :
1495 x == -1 || x == lev_fieldx ? 4 :
1496 y == -1 || y == lev_fieldy ? 5 : 6);
1498 return border[steel_position][steel_type];
1501 void DrawScreenElement(int x, int y, int element)
1503 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1504 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1507 void DrawLevelElement(int x, int y, int element)
1509 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1510 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1513 void DrawScreenField(int x, int y)
1515 int lx = LEVELX(x), ly = LEVELY(y);
1516 int element, content;
1518 if (!IN_LEV_FIELD(lx, ly))
1520 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1523 element = getBorderElement(lx, ly);
1525 DrawScreenElement(x, y, element);
1529 element = Feld[lx][ly];
1530 content = Store[lx][ly];
1532 if (IS_MOVING(lx, ly))
1534 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1535 boolean cut_mode = NO_CUTTING;
1537 if (element == EL_QUICKSAND_EMPTYING ||
1538 element == EL_QUICKSAND_FAST_EMPTYING ||
1539 element == EL_MAGIC_WALL_EMPTYING ||
1540 element == EL_BD_MAGIC_WALL_EMPTYING ||
1541 element == EL_DC_MAGIC_WALL_EMPTYING ||
1542 element == EL_AMOEBA_DROPPING)
1543 cut_mode = CUT_ABOVE;
1544 else if (element == EL_QUICKSAND_FILLING ||
1545 element == EL_QUICKSAND_FAST_FILLING ||
1546 element == EL_MAGIC_WALL_FILLING ||
1547 element == EL_BD_MAGIC_WALL_FILLING ||
1548 element == EL_DC_MAGIC_WALL_FILLING)
1549 cut_mode = CUT_BELOW;
1551 if (cut_mode == CUT_ABOVE)
1552 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1554 DrawScreenElement(x, y, EL_EMPTY);
1557 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1558 else if (cut_mode == NO_CUTTING)
1559 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1561 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1563 if (content == EL_ACID)
1565 int dir = MovDir[lx][ly];
1566 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1567 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1569 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1572 else if (IS_BLOCKED(lx, ly))
1577 boolean cut_mode = NO_CUTTING;
1578 int element_old, content_old;
1580 Blocked2Moving(lx, ly, &oldx, &oldy);
1583 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1584 MovDir[oldx][oldy] == MV_RIGHT);
1586 element_old = Feld[oldx][oldy];
1587 content_old = Store[oldx][oldy];
1589 if (element_old == EL_QUICKSAND_EMPTYING ||
1590 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1591 element_old == EL_MAGIC_WALL_EMPTYING ||
1592 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1593 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1594 element_old == EL_AMOEBA_DROPPING)
1595 cut_mode = CUT_ABOVE;
1597 DrawScreenElement(x, y, EL_EMPTY);
1600 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1602 else if (cut_mode == NO_CUTTING)
1603 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1606 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1609 else if (IS_DRAWABLE(element))
1610 DrawScreenElement(x, y, element);
1612 DrawScreenElement(x, y, EL_EMPTY);
1615 void DrawLevelField(int x, int y)
1617 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1618 DrawScreenField(SCREENX(x), SCREENY(y));
1619 else if (IS_MOVING(x, y))
1623 Moving2Blocked(x, y, &newx, &newy);
1624 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1625 DrawScreenField(SCREENX(newx), SCREENY(newy));
1627 else if (IS_BLOCKED(x, y))
1631 Blocked2Moving(x, y, &oldx, &oldy);
1632 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1633 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1637 void DrawMiniElement(int x, int y, int element)
1641 graphic = el2edimg(element);
1642 DrawMiniGraphic(x, y, graphic);
1645 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1647 int x = sx + scroll_x, y = sy + scroll_y;
1649 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1650 DrawMiniElement(sx, sy, EL_EMPTY);
1651 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1652 DrawMiniElement(sx, sy, Feld[x][y]);
1654 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1657 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1658 int x, int y, int xsize, int ysize, int font_nr)
1660 int font_width = getFontWidth(font_nr);
1661 int font_height = getFontHeight(font_nr);
1662 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1665 int dst_x = SX + startx + x * font_width;
1666 int dst_y = SY + starty + y * font_height;
1667 int width = graphic_info[graphic].width;
1668 int height = graphic_info[graphic].height;
1669 int inner_width = MAX(width - 2 * font_width, font_width);
1670 int inner_height = MAX(height - 2 * font_height, font_height);
1671 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1672 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1673 boolean draw_masked = graphic_info[graphic].draw_masked;
1675 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1677 if (src_bitmap == NULL || width < font_width || height < font_height)
1679 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1683 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1684 inner_sx + (x - 1) * font_width % inner_width);
1685 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1686 inner_sy + (y - 1) * font_height % inner_height);
1690 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1691 dst_x - src_x, dst_y - src_y);
1692 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1696 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1700 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1702 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1703 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1704 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1705 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1706 boolean no_delay = (tape.warp_forward);
1707 unsigned long anim_delay = 0;
1708 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1709 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1710 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1711 int font_width = getFontWidth(font_nr);
1712 int font_height = getFontHeight(font_nr);
1713 int max_xsize = level.envelope[envelope_nr].xsize;
1714 int max_ysize = level.envelope[envelope_nr].ysize;
1715 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1716 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1717 int xend = max_xsize;
1718 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1719 int xstep = (xstart < xend ? 1 : 0);
1720 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1723 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1725 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1726 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1727 int sx = (SXSIZE - xsize * font_width) / 2;
1728 int sy = (SYSIZE - ysize * font_height) / 2;
1731 SetDrawtoField(DRAW_BUFFERED);
1733 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1735 SetDrawtoField(DRAW_BACKBUFFER);
1737 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1738 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1741 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1742 level.envelope[envelope_nr].text, font_nr, max_xsize,
1743 xsize - 2, ysize - 2, mask_mode,
1744 level.envelope[envelope_nr].autowrap,
1745 level.envelope[envelope_nr].centered, FALSE);
1747 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1748 level.envelope[envelope_nr].text, font_nr, max_xsize,
1749 xsize - 2, ysize - 2, mask_mode);
1752 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1755 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1759 void ShowEnvelope(int envelope_nr)
1761 int element = EL_ENVELOPE_1 + envelope_nr;
1762 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1763 int sound_opening = element_info[element].sound[ACTION_OPENING];
1764 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1765 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1766 boolean no_delay = (tape.warp_forward);
1767 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1768 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1769 int anim_mode = graphic_info[graphic].anim_mode;
1770 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1771 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1773 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1775 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1777 if (anim_mode == ANIM_DEFAULT)
1778 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1780 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1783 Delay(wait_delay_value);
1785 WaitForEventToContinue();
1787 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1789 if (anim_mode != ANIM_NONE)
1790 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1792 if (anim_mode == ANIM_DEFAULT)
1793 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1795 game.envelope_active = FALSE;
1797 SetDrawtoField(DRAW_BUFFERED);
1799 redraw_mask |= REDRAW_FIELD;
1803 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1808 int width_mult, width_div;
1809 int height_mult, height_div;
1817 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1818 5 - log_2(tilesize));
1819 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1820 int width_mult = offset_calc[offset_calc_pos].width_mult;
1821 int width_div = offset_calc[offset_calc_pos].width_div;
1822 int height_mult = offset_calc[offset_calc_pos].height_mult;
1823 int height_div = offset_calc[offset_calc_pos].height_div;
1824 int mini_startx = src_bitmap->width * width_mult / width_div;
1825 int mini_starty = src_bitmap->height * height_mult / height_div;
1826 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1827 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1829 *bitmap = src_bitmap;
1834 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1838 int graphic = el2preimg(element);
1840 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1841 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1848 SetDrawBackgroundMask(REDRAW_NONE);
1851 for (x = BX1; x <= BX2; x++)
1852 for (y = BY1; y <= BY2; y++)
1853 DrawScreenField(x, y);
1855 redraw_mask |= REDRAW_FIELD;
1858 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1862 for (x = 0; x < size_x; x++)
1863 for (y = 0; y < size_y; y++)
1864 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1866 redraw_mask |= REDRAW_FIELD;
1869 static void DrawPreviewLevelExt(int from_x, int from_y)
1871 boolean show_level_border = (BorderElement != EL_EMPTY);
1872 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1873 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1874 int tile_size = preview.tile_size;
1875 int preview_width = preview.xsize * tile_size;
1876 int preview_height = preview.ysize * tile_size;
1877 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1878 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1879 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1880 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1883 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1885 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1886 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1888 for (x = 0; x < real_preview_xsize; x++)
1890 for (y = 0; y < real_preview_ysize; y++)
1892 int lx = from_x + x + (show_level_border ? -1 : 0);
1893 int ly = from_y + y + (show_level_border ? -1 : 0);
1894 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1895 getBorderElement(lx, ly));
1897 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1898 element, tile_size);
1902 redraw_mask |= REDRAW_MICROLEVEL;
1905 #define MICROLABEL_EMPTY 0
1906 #define MICROLABEL_LEVEL_NAME 1
1907 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1908 #define MICROLABEL_LEVEL_AUTHOR 3
1909 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1910 #define MICROLABEL_IMPORTED_FROM 5
1911 #define MICROLABEL_IMPORTED_BY_HEAD 6
1912 #define MICROLABEL_IMPORTED_BY 7
1914 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
1916 int max_text_width = SXSIZE;
1917 int font_width = getFontWidth(font_nr);
1919 if (pos->align == ALIGN_CENTER)
1920 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1921 else if (pos->align == ALIGN_RIGHT)
1922 max_text_width = pos->x;
1924 max_text_width = SXSIZE - pos->x;
1926 return max_text_width / font_width;
1929 static void DrawPreviewLevelLabelExt(int mode)
1931 struct TextPosInfo *pos = &menu.main.text.level_info_2;
1932 char label_text[MAX_OUTPUT_LINESIZE + 1];
1933 int max_len_label_text;
1935 int font_nr = pos->font;
1938 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1939 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1940 mode == MICROLABEL_IMPORTED_BY_HEAD)
1941 font_nr = pos->font_alt;
1943 int font_nr = FONT_TEXT_2;
1946 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1947 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1948 mode == MICROLABEL_IMPORTED_BY_HEAD)
1949 font_nr = FONT_TEXT_3;
1953 max_len_label_text = getMaxTextLength(pos, font_nr);
1955 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1959 if (pos->chars != -1)
1960 max_len_label_text = pos->chars;
1963 for (i = 0; i < max_len_label_text; i++)
1964 label_text[i] = ' ';
1965 label_text[max_len_label_text] = '\0';
1967 if (strlen(label_text) > 0)
1970 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1972 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1973 int lypos = MICROLABEL2_YPOS;
1975 DrawText(lxpos, lypos, label_text, font_nr);
1980 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1981 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1982 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1983 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1984 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1985 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1986 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1987 max_len_label_text);
1988 label_text[max_len_label_text] = '\0';
1990 if (strlen(label_text) > 0)
1993 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1995 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1996 int lypos = MICROLABEL2_YPOS;
1998 DrawText(lxpos, lypos, label_text, font_nr);
2002 redraw_mask |= REDRAW_MICROLEVEL;
2005 void DrawPreviewLevel(boolean restart)
2007 static unsigned long scroll_delay = 0;
2008 static unsigned long label_delay = 0;
2009 static int from_x, from_y, scroll_direction;
2010 static int label_state, label_counter;
2011 unsigned long scroll_delay_value = preview.step_delay;
2012 boolean show_level_border = (BorderElement != EL_EMPTY);
2013 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2014 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2015 int last_game_status = game_status; /* save current game status */
2018 /* force PREVIEW font on preview level */
2019 game_status = GAME_MODE_PSEUDO_PREVIEW;
2027 if (preview.anim_mode == ANIM_CENTERED)
2029 if (level_xsize > preview.xsize)
2030 from_x = (level_xsize - preview.xsize) / 2;
2031 if (level_ysize > preview.ysize)
2032 from_y = (level_ysize - preview.ysize) / 2;
2035 from_x += preview.xoffset;
2036 from_y += preview.yoffset;
2038 scroll_direction = MV_RIGHT;
2042 DrawPreviewLevelExt(from_x, from_y);
2043 DrawPreviewLevelLabelExt(label_state);
2045 /* initialize delay counters */
2046 DelayReached(&scroll_delay, 0);
2047 DelayReached(&label_delay, 0);
2049 if (leveldir_current->name)
2051 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2052 char label_text[MAX_OUTPUT_LINESIZE + 1];
2054 int font_nr = pos->font;
2056 int font_nr = FONT_TEXT_1;
2059 int max_len_label_text = getMaxTextLength(pos, font_nr);
2061 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2069 if (pos->chars != -1)
2070 max_len_label_text = pos->chars;
2073 strncpy(label_text, leveldir_current->name, max_len_label_text);
2074 label_text[max_len_label_text] = '\0';
2077 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2079 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2080 lypos = SY + MICROLABEL1_YPOS;
2082 DrawText(lxpos, lypos, label_text, font_nr);
2086 game_status = last_game_status; /* restore current game status */
2091 /* scroll preview level, if needed */
2092 if (preview.anim_mode != ANIM_NONE &&
2093 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2094 DelayReached(&scroll_delay, scroll_delay_value))
2096 switch (scroll_direction)
2101 from_x -= preview.step_offset;
2102 from_x = (from_x < 0 ? 0 : from_x);
2105 scroll_direction = MV_UP;
2109 if (from_x < level_xsize - preview.xsize)
2111 from_x += preview.step_offset;
2112 from_x = (from_x > level_xsize - preview.xsize ?
2113 level_xsize - preview.xsize : from_x);
2116 scroll_direction = MV_DOWN;
2122 from_y -= preview.step_offset;
2123 from_y = (from_y < 0 ? 0 : from_y);
2126 scroll_direction = MV_RIGHT;
2130 if (from_y < level_ysize - preview.ysize)
2132 from_y += preview.step_offset;
2133 from_y = (from_y > level_ysize - preview.ysize ?
2134 level_ysize - preview.ysize : from_y);
2137 scroll_direction = MV_LEFT;
2144 DrawPreviewLevelExt(from_x, from_y);
2147 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2148 /* redraw micro level label, if needed */
2149 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2150 !strEqual(level.author, ANONYMOUS_NAME) &&
2151 !strEqual(level.author, leveldir_current->name) &&
2152 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2154 int max_label_counter = 23;
2156 if (leveldir_current->imported_from != NULL &&
2157 strlen(leveldir_current->imported_from) > 0)
2158 max_label_counter += 14;
2159 if (leveldir_current->imported_by != NULL &&
2160 strlen(leveldir_current->imported_by) > 0)
2161 max_label_counter += 14;
2163 label_counter = (label_counter + 1) % max_label_counter;
2164 label_state = (label_counter >= 0 && label_counter <= 7 ?
2165 MICROLABEL_LEVEL_NAME :
2166 label_counter >= 9 && label_counter <= 12 ?
2167 MICROLABEL_LEVEL_AUTHOR_HEAD :
2168 label_counter >= 14 && label_counter <= 21 ?
2169 MICROLABEL_LEVEL_AUTHOR :
2170 label_counter >= 23 && label_counter <= 26 ?
2171 MICROLABEL_IMPORTED_FROM_HEAD :
2172 label_counter >= 28 && label_counter <= 35 ?
2173 MICROLABEL_IMPORTED_FROM :
2174 label_counter >= 37 && label_counter <= 40 ?
2175 MICROLABEL_IMPORTED_BY_HEAD :
2176 label_counter >= 42 && label_counter <= 49 ?
2177 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2179 if (leveldir_current->imported_from == NULL &&
2180 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2181 label_state == MICROLABEL_IMPORTED_FROM))
2182 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2183 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2185 DrawPreviewLevelLabelExt(label_state);
2188 game_status = last_game_status; /* restore current game status */
2191 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2192 int graphic, int sync_frame, int mask_mode)
2194 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2196 if (mask_mode == USE_MASKING)
2197 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2199 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2202 inline void DrawGraphicAnimation(int x, int y, int graphic)
2204 int lx = LEVELX(x), ly = LEVELY(y);
2206 if (!IN_SCR_FIELD(x, y))
2209 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2210 graphic, GfxFrame[lx][ly], NO_MASKING);
2211 MarkTileDirty(x, y);
2214 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2216 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2219 void DrawLevelElementAnimation(int x, int y, int element)
2221 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2223 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2226 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2228 int sx = SCREENX(x), sy = SCREENY(y);
2230 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2233 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2236 DrawGraphicAnimation(sx, sy, graphic);
2239 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2240 DrawLevelFieldCrumbledSand(x, y);
2242 if (GFX_CRUMBLED(Feld[x][y]))
2243 DrawLevelFieldCrumbledSand(x, y);
2247 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2249 int sx = SCREENX(x), sy = SCREENY(y);
2252 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2255 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2257 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2260 DrawGraphicAnimation(sx, sy, graphic);
2262 if (GFX_CRUMBLED(element))
2263 DrawLevelFieldCrumbledSand(x, y);
2266 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2268 if (player->use_murphy)
2270 /* this works only because currently only one player can be "murphy" ... */
2271 static int last_horizontal_dir = MV_LEFT;
2272 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2274 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2275 last_horizontal_dir = move_dir;
2277 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2279 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2281 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2287 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2290 static boolean equalGraphics(int graphic1, int graphic2)
2292 struct GraphicInfo *g1 = &graphic_info[graphic1];
2293 struct GraphicInfo *g2 = &graphic_info[graphic2];
2295 return (g1->bitmap == g2->bitmap &&
2296 g1->src_x == g2->src_x &&
2297 g1->src_y == g2->src_y &&
2298 g1->anim_frames == g2->anim_frames &&
2299 g1->anim_delay == g2->anim_delay &&
2300 g1->anim_mode == g2->anim_mode);
2303 void DrawAllPlayers()
2307 for (i = 0; i < MAX_PLAYERS; i++)
2308 if (stored_player[i].active)
2309 DrawPlayer(&stored_player[i]);
2312 void DrawPlayerField(int x, int y)
2314 if (!IS_PLAYER(x, y))
2317 DrawPlayer(PLAYERINFO(x, y));
2320 void DrawPlayer(struct PlayerInfo *player)
2322 int jx = player->jx;
2323 int jy = player->jy;
2324 int move_dir = player->MovDir;
2325 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2326 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2327 int last_jx = (player->is_moving ? jx - dx : jx);
2328 int last_jy = (player->is_moving ? jy - dy : jy);
2329 int next_jx = jx + dx;
2330 int next_jy = jy + dy;
2331 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2332 boolean player_is_opaque = FALSE;
2333 int sx = SCREENX(jx), sy = SCREENY(jy);
2334 int sxx = 0, syy = 0;
2335 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2337 int action = ACTION_DEFAULT;
2338 int last_player_graphic = getPlayerGraphic(player, move_dir);
2339 int last_player_frame = player->Frame;
2342 /* GfxElement[][] is set to the element the player is digging or collecting;
2343 remove also for off-screen player if the player is not moving anymore */
2344 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2345 GfxElement[jx][jy] = EL_UNDEFINED;
2347 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2351 if (!IN_LEV_FIELD(jx, jy))
2353 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2354 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2355 printf("DrawPlayerField(): This should never happen!\n");
2360 if (element == EL_EXPLOSION)
2363 action = (player->is_pushing ? ACTION_PUSHING :
2364 player->is_digging ? ACTION_DIGGING :
2365 player->is_collecting ? ACTION_COLLECTING :
2366 player->is_moving ? ACTION_MOVING :
2367 player->is_snapping ? ACTION_SNAPPING :
2368 player->is_dropping ? ACTION_DROPPING :
2369 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2371 if (player->is_waiting)
2372 move_dir = player->dir_waiting;
2374 InitPlayerGfxAnimation(player, action, move_dir);
2376 /* ----------------------------------------------------------------------- */
2377 /* draw things in the field the player is leaving, if needed */
2378 /* ----------------------------------------------------------------------- */
2380 if (player->is_moving)
2382 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2384 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2386 if (last_element == EL_DYNAMITE_ACTIVE ||
2387 last_element == EL_EM_DYNAMITE_ACTIVE ||
2388 last_element == EL_SP_DISK_RED_ACTIVE)
2389 DrawDynamite(last_jx, last_jy);
2391 DrawLevelFieldThruMask(last_jx, last_jy);
2393 else if (last_element == EL_DYNAMITE_ACTIVE ||
2394 last_element == EL_EM_DYNAMITE_ACTIVE ||
2395 last_element == EL_SP_DISK_RED_ACTIVE)
2396 DrawDynamite(last_jx, last_jy);
2398 /* !!! this is not enough to prevent flickering of players which are
2399 moving next to each others without a free tile between them -- this
2400 can only be solved by drawing all players layer by layer (first the
2401 background, then the foreground etc.) !!! => TODO */
2402 else if (!IS_PLAYER(last_jx, last_jy))
2403 DrawLevelField(last_jx, last_jy);
2406 DrawLevelField(last_jx, last_jy);
2409 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2410 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2413 if (!IN_SCR_FIELD(sx, sy))
2416 if (setup.direct_draw)
2417 SetDrawtoField(DRAW_BUFFERED);
2419 /* ----------------------------------------------------------------------- */
2420 /* draw things behind the player, if needed */
2421 /* ----------------------------------------------------------------------- */
2424 DrawLevelElement(jx, jy, Back[jx][jy]);
2425 else if (IS_ACTIVE_BOMB(element))
2426 DrawLevelElement(jx, jy, EL_EMPTY);
2429 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2431 int old_element = GfxElement[jx][jy];
2432 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2433 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2435 if (GFX_CRUMBLED(old_element))
2436 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2438 DrawGraphic(sx, sy, old_graphic, frame);
2440 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2441 player_is_opaque = TRUE;
2445 GfxElement[jx][jy] = EL_UNDEFINED;
2447 /* make sure that pushed elements are drawn with correct frame rate */
2449 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2451 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2452 GfxFrame[jx][jy] = player->StepFrame;
2454 if (player->is_pushing && player->is_moving)
2455 GfxFrame[jx][jy] = player->StepFrame;
2458 DrawLevelField(jx, jy);
2462 /* ----------------------------------------------------------------------- */
2463 /* draw player himself */
2464 /* ----------------------------------------------------------------------- */
2466 graphic = getPlayerGraphic(player, move_dir);
2468 /* in the case of changed player action or direction, prevent the current
2469 animation frame from being restarted for identical animations */
2470 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2471 player->Frame = last_player_frame;
2473 frame = getGraphicAnimationFrame(graphic, player->Frame);
2477 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2478 sxx = player->GfxPos;
2480 syy = player->GfxPos;
2483 if (!setup.soft_scrolling && ScreenMovPos)
2486 if (player_is_opaque)
2487 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2489 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2491 if (SHIELD_ON(player))
2493 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2494 IMG_SHIELD_NORMAL_ACTIVE);
2495 int frame = getGraphicAnimationFrame(graphic, -1);
2497 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2500 /* ----------------------------------------------------------------------- */
2501 /* draw things the player is pushing, if needed */
2502 /* ----------------------------------------------------------------------- */
2505 printf("::: %d, %d [%d, %d] [%d]\n",
2506 player->is_pushing, player_is_moving, player->GfxAction,
2507 player->is_moving, player_is_moving);
2511 if (player->is_pushing && player->is_moving)
2513 int px = SCREENX(jx), py = SCREENY(jy);
2514 int pxx = (TILEX - ABS(sxx)) * dx;
2515 int pyy = (TILEY - ABS(syy)) * dy;
2516 int gfx_frame = GfxFrame[jx][jy];
2522 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2524 element = Feld[next_jx][next_jy];
2525 gfx_frame = GfxFrame[next_jx][next_jy];
2528 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2531 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2532 frame = getGraphicAnimationFrame(graphic, sync_frame);
2534 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2537 /* draw background element under pushed element (like the Sokoban field) */
2538 if (Back[next_jx][next_jy])
2539 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2541 /* masked drawing is needed for EMC style (double) movement graphics */
2542 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2546 /* ----------------------------------------------------------------------- */
2547 /* draw things in front of player (active dynamite or dynabombs) */
2548 /* ----------------------------------------------------------------------- */
2550 if (IS_ACTIVE_BOMB(element))
2552 graphic = el2img(element);
2553 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2555 if (game.emulation == EMU_SUPAPLEX)
2556 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2558 DrawGraphicThruMask(sx, sy, graphic, frame);
2561 if (player_is_moving && last_element == EL_EXPLOSION)
2563 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2564 GfxElement[last_jx][last_jy] : EL_EMPTY);
2565 int graphic = el_act2img(element, ACTION_EXPLODING);
2566 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2567 int phase = ExplodePhase[last_jx][last_jy] - 1;
2568 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2571 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2574 /* ----------------------------------------------------------------------- */
2575 /* draw elements the player is just walking/passing through/under */
2576 /* ----------------------------------------------------------------------- */
2578 if (player_is_moving)
2580 /* handle the field the player is leaving ... */
2581 if (IS_ACCESSIBLE_INSIDE(last_element))
2582 DrawLevelField(last_jx, last_jy);
2583 else if (IS_ACCESSIBLE_UNDER(last_element))
2584 DrawLevelFieldThruMask(last_jx, last_jy);
2587 /* do not redraw accessible elements if the player is just pushing them */
2588 if (!player_is_moving || !player->is_pushing)
2590 /* ... and the field the player is entering */
2591 if (IS_ACCESSIBLE_INSIDE(element))
2592 DrawLevelField(jx, jy);
2593 else if (IS_ACCESSIBLE_UNDER(element))
2594 DrawLevelFieldThruMask(jx, jy);
2597 if (setup.direct_draw)
2599 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2600 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2601 int x_size = TILEX * (1 + ABS(jx - last_jx));
2602 int y_size = TILEY * (1 + ABS(jy - last_jy));
2604 BlitBitmap(drawto_field, window,
2605 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2606 SetDrawtoField(DRAW_DIRECT);
2609 MarkTileDirty(sx, sy);
2612 /* ------------------------------------------------------------------------- */
2614 void WaitForEventToContinue()
2616 boolean still_wait = TRUE;
2618 /* simulate releasing mouse button over last gadget, if still pressed */
2620 HandleGadgets(-1, -1, 0);
2622 button_status = MB_RELEASED;
2638 case EVENT_BUTTONPRESS:
2639 case EVENT_KEYPRESS:
2643 case EVENT_KEYRELEASE:
2644 ClearPlayerAction();
2648 HandleOtherEvents(&event);
2652 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2659 /* don't eat all CPU time */
2664 #define MAX_REQUEST_LINES 13
2665 #define MAX_REQUEST_LINE_FONT1_LEN 7
2666 #define MAX_REQUEST_LINE_FONT2_LEN 10
2668 boolean Request(char *text, unsigned int req_state)
2670 int mx, my, ty, result = -1;
2671 unsigned int old_door_state;
2672 int last_game_status = game_status; /* save current game status */
2673 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2674 int font_nr = FONT_TEXT_2;
2675 int max_word_len = 0;
2678 for (text_ptr = text; *text_ptr; text_ptr++)
2680 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2682 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2684 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2686 font_nr = FONT_TEXT_1;
2688 font_nr = FONT_LEVEL_NUMBER;
2695 if (game_status == GAME_MODE_PLAYING &&
2696 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2697 BlitScreenToBitmap_EM(backbuffer);
2699 /* disable deactivated drawing when quick-loading level tape recording */
2700 if (tape.playing && tape.deactivate_display)
2701 TapeDeactivateDisplayOff(TRUE);
2703 SetMouseCursor(CURSOR_DEFAULT);
2705 #if defined(NETWORK_AVALIABLE)
2706 /* pause network game while waiting for request to answer */
2707 if (options.network &&
2708 game_status == GAME_MODE_PLAYING &&
2709 req_state & REQUEST_WAIT_FOR_INPUT)
2710 SendToServer_PausePlaying();
2713 old_door_state = GetDoorState();
2715 /* simulate releasing mouse button over last gadget, if still pressed */
2717 HandleGadgets(-1, -1, 0);
2721 if (old_door_state & DOOR_OPEN_1)
2723 CloseDoor(DOOR_CLOSE_1);
2725 /* save old door content */
2726 BlitBitmap(bitmap_db_door, bitmap_db_door,
2727 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2728 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2732 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2735 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2737 /* clear door drawing field */
2738 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2740 /* force DOOR font inside door area */
2741 game_status = GAME_MODE_PSEUDO_DOOR;
2743 /* write text for request */
2744 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2746 char text_line[max_request_line_len + 1];
2752 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2755 if (!tc || tc == ' ')
2766 strncpy(text_line, text, tl);
2769 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2770 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2771 text_line, font_nr);
2773 text += tl + (tc == ' ' ? 1 : 0);
2776 game_status = last_game_status; /* restore current game status */
2778 if (req_state & REQ_ASK)
2780 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2781 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2783 else if (req_state & REQ_CONFIRM)
2785 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2787 else if (req_state & REQ_PLAYER)
2789 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2790 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2791 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2792 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2795 /* copy request gadgets to door backbuffer */
2796 BlitBitmap(drawto, bitmap_db_door,
2797 DX, DY, DXSIZE, DYSIZE,
2798 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2800 OpenDoor(DOOR_OPEN_1);
2802 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2804 if (game_status == GAME_MODE_PLAYING)
2806 SetPanelBackground();
2807 SetDrawBackgroundMask(REDRAW_DOOR_1);
2811 SetDrawBackgroundMask(REDRAW_FIELD);
2817 if (game_status != GAME_MODE_MAIN)
2820 button_status = MB_RELEASED;
2822 request_gadget_id = -1;
2824 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2836 case EVENT_BUTTONPRESS:
2837 case EVENT_BUTTONRELEASE:
2838 case EVENT_MOTIONNOTIFY:
2840 if (event.type == EVENT_MOTIONNOTIFY)
2842 if (!PointerInWindow(window))
2843 continue; /* window and pointer are on different screens */
2848 motion_status = TRUE;
2849 mx = ((MotionEvent *) &event)->x;
2850 my = ((MotionEvent *) &event)->y;
2854 motion_status = FALSE;
2855 mx = ((ButtonEvent *) &event)->x;
2856 my = ((ButtonEvent *) &event)->y;
2857 if (event.type == EVENT_BUTTONPRESS)
2858 button_status = ((ButtonEvent *) &event)->button;
2860 button_status = MB_RELEASED;
2863 /* this sets 'request_gadget_id' */
2864 HandleGadgets(mx, my, button_status);
2866 switch (request_gadget_id)
2868 case TOOL_CTRL_ID_YES:
2871 case TOOL_CTRL_ID_NO:
2874 case TOOL_CTRL_ID_CONFIRM:
2875 result = TRUE | FALSE;
2878 case TOOL_CTRL_ID_PLAYER_1:
2881 case TOOL_CTRL_ID_PLAYER_2:
2884 case TOOL_CTRL_ID_PLAYER_3:
2887 case TOOL_CTRL_ID_PLAYER_4:
2898 case EVENT_KEYPRESS:
2899 switch (GetEventKey((KeyEvent *)&event, TRUE))
2912 if (req_state & REQ_PLAYER)
2916 case EVENT_KEYRELEASE:
2917 ClearPlayerAction();
2921 HandleOtherEvents(&event);
2925 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2927 int joy = AnyJoystick();
2929 if (joy & JOY_BUTTON_1)
2931 else if (joy & JOY_BUTTON_2)
2937 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2939 HandleGameActions();
2946 if (!PendingEvent()) /* delay only if no pending events */
2955 if (!PendingEvent()) /* delay only if no pending events */
2958 /* don't eat all CPU time */
2965 if (game_status != GAME_MODE_MAIN)
2970 if (!(req_state & REQ_STAY_OPEN))
2972 CloseDoor(DOOR_CLOSE_1);
2974 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2975 (req_state & REQ_REOPEN))
2976 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2981 if (game_status == GAME_MODE_PLAYING)
2983 SetPanelBackground();
2984 SetDrawBackgroundMask(REDRAW_DOOR_1);
2988 SetDrawBackgroundMask(REDRAW_FIELD);
2991 #if defined(NETWORK_AVALIABLE)
2992 /* continue network game after request */
2993 if (options.network &&
2994 game_status == GAME_MODE_PLAYING &&
2995 req_state & REQUEST_WAIT_FOR_INPUT)
2996 SendToServer_ContinuePlaying();
2999 /* restore deactivated drawing when quick-loading level tape recording */
3000 if (tape.playing && tape.deactivate_display)
3001 TapeDeactivateDisplayOn();
3006 unsigned int OpenDoor(unsigned int door_state)
3008 if (door_state & DOOR_COPY_BACK)
3010 if (door_state & DOOR_OPEN_1)
3011 BlitBitmap(bitmap_db_door, bitmap_db_door,
3012 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3013 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3015 if (door_state & DOOR_OPEN_2)
3016 BlitBitmap(bitmap_db_door, bitmap_db_door,
3017 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3018 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3020 door_state &= ~DOOR_COPY_BACK;
3023 return MoveDoor(door_state);
3026 unsigned int CloseDoor(unsigned int door_state)
3028 unsigned int old_door_state = GetDoorState();
3030 if (!(door_state & DOOR_NO_COPY_BACK))
3032 if (old_door_state & DOOR_OPEN_1)
3033 BlitBitmap(backbuffer, bitmap_db_door,
3034 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3036 if (old_door_state & DOOR_OPEN_2)
3037 BlitBitmap(backbuffer, bitmap_db_door,
3038 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3040 door_state &= ~DOOR_NO_COPY_BACK;
3043 return MoveDoor(door_state);
3046 unsigned int GetDoorState()
3048 return MoveDoor(DOOR_GET_STATE);
3051 unsigned int SetDoorState(unsigned int door_state)
3053 return MoveDoor(door_state | DOOR_SET_STATE);
3056 unsigned int MoveDoor(unsigned int door_state)
3058 static int door1 = DOOR_OPEN_1;
3059 static int door2 = DOOR_CLOSE_2;
3060 unsigned long door_delay = 0;
3061 unsigned long door_delay_value;
3064 if (door_1.width < 0 || door_1.width > DXSIZE)
3065 door_1.width = DXSIZE;
3066 if (door_1.height < 0 || door_1.height > DYSIZE)
3067 door_1.height = DYSIZE;
3068 if (door_2.width < 0 || door_2.width > VXSIZE)
3069 door_2.width = VXSIZE;
3070 if (door_2.height < 0 || door_2.height > VYSIZE)
3071 door_2.height = VYSIZE;
3073 if (door_state == DOOR_GET_STATE)
3074 return (door1 | door2);
3076 if (door_state & DOOR_SET_STATE)
3078 if (door_state & DOOR_ACTION_1)
3079 door1 = door_state & DOOR_ACTION_1;
3080 if (door_state & DOOR_ACTION_2)
3081 door2 = door_state & DOOR_ACTION_2;
3083 return (door1 | door2);
3086 if (!(door_state & DOOR_FORCE_REDRAW))
3088 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3089 door_state &= ~DOOR_OPEN_1;
3090 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3091 door_state &= ~DOOR_CLOSE_1;
3092 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3093 door_state &= ~DOOR_OPEN_2;
3094 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3095 door_state &= ~DOOR_CLOSE_2;
3098 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3101 if (setup.quick_doors)
3103 stepsize = 20; /* must be chosen to always draw last frame */
3104 door_delay_value = 0;
3107 if (global.autoplay_leveldir)
3109 door_state |= DOOR_NO_DELAY;
3110 door_state &= ~DOOR_CLOSE_ALL;
3113 if (door_state & DOOR_ACTION)
3115 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3116 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3117 boolean door_1_done = (!handle_door_1);
3118 boolean door_2_done = (!handle_door_2);
3119 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3120 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3121 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3122 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3123 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3124 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3125 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3126 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3127 int door_skip = max_door_size - door_size;
3128 int end = door_size;
3129 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3132 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3134 /* opening door sound has priority over simultaneously closing door */
3135 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3136 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3137 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3138 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3141 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3144 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3145 GC gc = bitmap->stored_clip_gc;
3147 if (door_state & DOOR_ACTION_1)
3149 int a = MIN(x * door_1.step_offset, end);
3150 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3151 int i = p + door_skip;
3153 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3155 BlitBitmap(bitmap_db_door, drawto,
3156 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3157 DXSIZE, DYSIZE, DX, DY);
3161 BlitBitmap(bitmap_db_door, drawto,
3162 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3163 DXSIZE, DYSIZE - p / 2, DX, DY);
3165 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3168 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3170 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3171 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3172 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3173 int dst2_x = DX, dst2_y = DY;
3174 int width = i, height = DYSIZE;
3176 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3177 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3180 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3181 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3184 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3186 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3187 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3188 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3189 int dst2_x = DX, dst2_y = DY;
3190 int width = DXSIZE, height = i;
3192 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3193 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3196 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3197 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3200 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3202 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3204 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3205 BlitBitmapMasked(bitmap, drawto,
3206 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3207 DX + DXSIZE - i, DY + j);
3208 BlitBitmapMasked(bitmap, drawto,
3209 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3210 DX + DXSIZE - i, DY + 140 + j);
3211 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3212 DY - (DOOR_GFX_PAGEY1 + j));
3213 BlitBitmapMasked(bitmap, drawto,
3214 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3216 BlitBitmapMasked(bitmap, drawto,
3217 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3220 BlitBitmapMasked(bitmap, drawto,
3221 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3223 BlitBitmapMasked(bitmap, drawto,
3224 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3226 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3227 BlitBitmapMasked(bitmap, drawto,
3228 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3229 DX + DXSIZE - i, DY + 77 + j);
3230 BlitBitmapMasked(bitmap, drawto,
3231 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3232 DX + DXSIZE - i, DY + 203 + j);
3235 redraw_mask |= REDRAW_DOOR_1;
3236 door_1_done = (a == end);
3239 if (door_state & DOOR_ACTION_2)
3241 int a = MIN(x * door_2.step_offset, door_size);
3242 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3243 int i = p + door_skip;
3245 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3247 BlitBitmap(bitmap_db_door, drawto,
3248 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3249 VXSIZE, VYSIZE, VX, VY);
3251 else if (x <= VYSIZE)
3253 BlitBitmap(bitmap_db_door, drawto,
3254 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3255 VXSIZE, VYSIZE - p / 2, VX, VY);
3257 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3260 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3262 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3263 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3264 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3265 int dst2_x = VX, dst2_y = VY;
3266 int width = i, height = VYSIZE;
3268 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3269 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3272 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3273 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3276 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3278 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3279 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3280 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3281 int dst2_x = VX, dst2_y = VY;
3282 int width = VXSIZE, height = i;
3284 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3285 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3288 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3289 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3292 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3294 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3296 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3297 BlitBitmapMasked(bitmap, drawto,
3298 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3299 VX + VXSIZE - i, VY + j);
3300 SetClipOrigin(bitmap, gc,
3301 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3302 BlitBitmapMasked(bitmap, drawto,
3303 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3306 BlitBitmapMasked(bitmap, drawto,
3307 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3308 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3309 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3310 BlitBitmapMasked(bitmap, drawto,
3311 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3313 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3316 redraw_mask |= REDRAW_DOOR_2;
3317 door_2_done = (a == VXSIZE);
3320 if (!(door_state & DOOR_NO_DELAY))
3324 if (game_status == GAME_MODE_MAIN)
3327 WaitUntilDelayReached(&door_delay, door_delay_value);
3332 if (door_state & DOOR_ACTION_1)
3333 door1 = door_state & DOOR_ACTION_1;
3334 if (door_state & DOOR_ACTION_2)
3335 door2 = door_state & DOOR_ACTION_2;
3337 return (door1 | door2);
3340 void DrawSpecialEditorDoor()
3342 /* draw bigger toolbox window */
3343 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3344 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3346 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3347 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3350 redraw_mask |= REDRAW_ALL;
3353 void UndrawSpecialEditorDoor()
3355 /* draw normal tape recorder window */
3356 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3357 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3360 redraw_mask |= REDRAW_ALL;
3364 /* ---------- new tool button stuff ---------------------------------------- */
3366 /* graphic position values for tool buttons */
3367 #define TOOL_BUTTON_YES_XPOS 2
3368 #define TOOL_BUTTON_YES_YPOS 250
3369 #define TOOL_BUTTON_YES_GFX_YPOS 0
3370 #define TOOL_BUTTON_YES_XSIZE 46
3371 #define TOOL_BUTTON_YES_YSIZE 28
3372 #define TOOL_BUTTON_NO_XPOS 52
3373 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3374 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3375 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3376 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3377 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3378 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3379 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3380 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3381 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3382 #define TOOL_BUTTON_PLAYER_XSIZE 30
3383 #define TOOL_BUTTON_PLAYER_YSIZE 30
3384 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3385 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3386 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3387 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3388 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3389 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3390 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3391 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3392 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3393 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3394 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3395 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3396 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3397 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3398 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3399 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3400 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3401 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3402 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3403 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3412 } toolbutton_info[NUM_TOOL_BUTTONS] =
3415 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3416 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3417 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3422 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3423 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3424 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3429 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3430 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3431 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3432 TOOL_CTRL_ID_CONFIRM,
3436 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3437 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3438 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3439 TOOL_CTRL_ID_PLAYER_1,
3443 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3444 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3445 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3446 TOOL_CTRL_ID_PLAYER_2,
3450 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3451 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3452 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3453 TOOL_CTRL_ID_PLAYER_3,
3457 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3458 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3459 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3460 TOOL_CTRL_ID_PLAYER_4,
3465 void CreateToolButtons()
3469 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3471 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3472 Bitmap *deco_bitmap = None;
3473 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3474 struct GadgetInfo *gi;
3475 unsigned long event_mask;
3476 int gd_xoffset, gd_yoffset;
3477 int gd_x1, gd_x2, gd_y;
3480 event_mask = GD_EVENT_RELEASED;
3482 gd_xoffset = toolbutton_info[i].xpos;
3483 gd_yoffset = toolbutton_info[i].ypos;
3484 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3485 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3486 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3488 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3490 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3492 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3493 &deco_bitmap, &deco_x, &deco_y);
3494 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3495 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3498 gi = CreateGadget(GDI_CUSTOM_ID, id,
3499 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3500 GDI_X, DX + toolbutton_info[i].x,
3501 GDI_Y, DY + toolbutton_info[i].y,
3502 GDI_WIDTH, toolbutton_info[i].width,
3503 GDI_HEIGHT, toolbutton_info[i].height,
3504 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3505 GDI_STATE, GD_BUTTON_UNPRESSED,
3506 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3507 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3508 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3509 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3510 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3511 GDI_DECORATION_SHIFTING, 1, 1,
3512 GDI_DIRECT_DRAW, FALSE,
3513 GDI_EVENT_MASK, event_mask,
3514 GDI_CALLBACK_ACTION, HandleToolButtons,
3518 Error(ERR_EXIT, "cannot create gadget");
3520 tool_gadget[id] = gi;
3524 void FreeToolButtons()
3528 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3529 FreeGadget(tool_gadget[i]);
3532 static void UnmapToolButtons()
3536 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3537 UnmapGadget(tool_gadget[i]);
3540 static void HandleToolButtons(struct GadgetInfo *gi)
3542 request_gadget_id = gi->custom_id;
3545 static struct Mapping_EM_to_RND_object
3548 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3549 boolean is_backside; /* backside of moving element */
3555 em_object_mapping_list[] =
3558 Xblank, TRUE, FALSE,
3562 Yacid_splash_eB, FALSE, FALSE,
3563 EL_ACID_SPLASH_RIGHT, -1, -1
3566 Yacid_splash_wB, FALSE, FALSE,
3567 EL_ACID_SPLASH_LEFT, -1, -1
3570 #ifdef EM_ENGINE_BAD_ROLL
3572 Xstone_force_e, FALSE, FALSE,
3573 EL_ROCK, -1, MV_BIT_RIGHT
3576 Xstone_force_w, FALSE, FALSE,
3577 EL_ROCK, -1, MV_BIT_LEFT
3580 Xnut_force_e, FALSE, FALSE,
3581 EL_NUT, -1, MV_BIT_RIGHT
3584 Xnut_force_w, FALSE, FALSE,
3585 EL_NUT, -1, MV_BIT_LEFT
3588 Xspring_force_e, FALSE, FALSE,
3589 EL_SPRING, -1, MV_BIT_RIGHT
3592 Xspring_force_w, FALSE, FALSE,
3593 EL_SPRING, -1, MV_BIT_LEFT
3596 Xemerald_force_e, FALSE, FALSE,
3597 EL_EMERALD, -1, MV_BIT_RIGHT
3600 Xemerald_force_w, FALSE, FALSE,
3601 EL_EMERALD, -1, MV_BIT_LEFT
3604 Xdiamond_force_e, FALSE, FALSE,
3605 EL_DIAMOND, -1, MV_BIT_RIGHT
3608 Xdiamond_force_w, FALSE, FALSE,
3609 EL_DIAMOND, -1, MV_BIT_LEFT
3612 Xbomb_force_e, FALSE, FALSE,
3613 EL_BOMB, -1, MV_BIT_RIGHT
3616 Xbomb_force_w, FALSE, FALSE,
3617 EL_BOMB, -1, MV_BIT_LEFT
3619 #endif /* EM_ENGINE_BAD_ROLL */
3622 Xstone, TRUE, FALSE,
3626 Xstone_pause, FALSE, FALSE,
3630 Xstone_fall, FALSE, FALSE,
3634 Ystone_s, FALSE, FALSE,
3635 EL_ROCK, ACTION_FALLING, -1
3638 Ystone_sB, FALSE, TRUE,
3639 EL_ROCK, ACTION_FALLING, -1
3642 Ystone_e, FALSE, FALSE,
3643 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3646 Ystone_eB, FALSE, TRUE,
3647 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3650 Ystone_w, FALSE, FALSE,
3651 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3654 Ystone_wB, FALSE, TRUE,
3655 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3662 Xnut_pause, FALSE, FALSE,
3666 Xnut_fall, FALSE, FALSE,
3670 Ynut_s, FALSE, FALSE,
3671 EL_NUT, ACTION_FALLING, -1
3674 Ynut_sB, FALSE, TRUE,
3675 EL_NUT, ACTION_FALLING, -1
3678 Ynut_e, FALSE, FALSE,
3679 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3682 Ynut_eB, FALSE, TRUE,
3683 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3686 Ynut_w, FALSE, FALSE,
3687 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3690 Ynut_wB, FALSE, TRUE,
3691 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3694 Xbug_n, TRUE, FALSE,
3698 Xbug_e, TRUE, FALSE,
3699 EL_BUG_RIGHT, -1, -1
3702 Xbug_s, TRUE, FALSE,
3706 Xbug_w, TRUE, FALSE,
3710 Xbug_gon, FALSE, FALSE,
3714 Xbug_goe, FALSE, FALSE,
3715 EL_BUG_RIGHT, -1, -1
3718 Xbug_gos, FALSE, FALSE,
3722 Xbug_gow, FALSE, FALSE,
3726 Ybug_n, FALSE, FALSE,
3727 EL_BUG, ACTION_MOVING, MV_BIT_UP
3730 Ybug_nB, FALSE, TRUE,
3731 EL_BUG, ACTION_MOVING, MV_BIT_UP
3734 Ybug_e, FALSE, FALSE,
3735 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3738 Ybug_eB, FALSE, TRUE,
3739 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3742 Ybug_s, FALSE, FALSE,
3743 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3746 Ybug_sB, FALSE, TRUE,
3747 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3750 Ybug_w, FALSE, FALSE,
3751 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3754 Ybug_wB, FALSE, TRUE,
3755 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3758 Ybug_w_n, FALSE, FALSE,
3759 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3762 Ybug_n_e, FALSE, FALSE,
3763 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3766 Ybug_e_s, FALSE, FALSE,
3767 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3770 Ybug_s_w, FALSE, FALSE,
3771 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3774 Ybug_e_n, FALSE, FALSE,
3775 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3778 Ybug_s_e, FALSE, FALSE,
3779 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3782 Ybug_w_s, FALSE, FALSE,
3783 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3786 Ybug_n_w, FALSE, FALSE,
3787 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3790 Ybug_stone, FALSE, FALSE,
3791 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3794 Ybug_spring, FALSE, FALSE,
3795 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3798 Xtank_n, TRUE, FALSE,
3799 EL_SPACESHIP_UP, -1, -1
3802 Xtank_e, TRUE, FALSE,
3803 EL_SPACESHIP_RIGHT, -1, -1
3806 Xtank_s, TRUE, FALSE,
3807 EL_SPACESHIP_DOWN, -1, -1
3810 Xtank_w, TRUE, FALSE,
3811 EL_SPACESHIP_LEFT, -1, -1
3814 Xtank_gon, FALSE, FALSE,
3815 EL_SPACESHIP_UP, -1, -1
3818 Xtank_goe, FALSE, FALSE,
3819 EL_SPACESHIP_RIGHT, -1, -1
3822 Xtank_gos, FALSE, FALSE,
3823 EL_SPACESHIP_DOWN, -1, -1
3826 Xtank_gow, FALSE, FALSE,
3827 EL_SPACESHIP_LEFT, -1, -1
3830 Ytank_n, FALSE, FALSE,
3831 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3834 Ytank_nB, FALSE, TRUE,
3835 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3838 Ytank_e, FALSE, FALSE,
3839 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3842 Ytank_eB, FALSE, TRUE,
3843 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3846 Ytank_s, FALSE, FALSE,
3847 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3850 Ytank_sB, FALSE, TRUE,
3851 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3854 Ytank_w, FALSE, FALSE,
3855 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3858 Ytank_wB, FALSE, TRUE,
3859 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3862 Ytank_w_n, FALSE, FALSE,
3863 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3866 Ytank_n_e, FALSE, FALSE,
3867 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3870 Ytank_e_s, FALSE, FALSE,
3871 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3874 Ytank_s_w, FALSE, FALSE,
3875 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3878 Ytank_e_n, FALSE, FALSE,
3879 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3882 Ytank_s_e, FALSE, FALSE,
3883 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3886 Ytank_w_s, FALSE, FALSE,
3887 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3890 Ytank_n_w, FALSE, FALSE,
3891 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3894 Ytank_stone, FALSE, FALSE,
3895 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3898 Ytank_spring, FALSE, FALSE,
3899 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3902 Xandroid, TRUE, FALSE,
3903 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3906 Xandroid_1_n, FALSE, FALSE,
3907 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3910 Xandroid_2_n, FALSE, FALSE,
3911 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3914 Xandroid_1_e, FALSE, FALSE,
3915 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3918 Xandroid_2_e, FALSE, FALSE,
3919 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3922 Xandroid_1_w, FALSE, FALSE,
3923 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3926 Xandroid_2_w, FALSE, FALSE,
3927 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3930 Xandroid_1_s, FALSE, FALSE,
3931 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3934 Xandroid_2_s, FALSE, FALSE,
3935 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3938 Yandroid_n, FALSE, FALSE,
3939 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3942 Yandroid_nB, FALSE, TRUE,
3943 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3946 Yandroid_ne, FALSE, FALSE,
3947 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3950 Yandroid_neB, FALSE, TRUE,
3951 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3954 Yandroid_e, FALSE, FALSE,
3955 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3958 Yandroid_eB, FALSE, TRUE,
3959 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3962 Yandroid_se, FALSE, FALSE,
3963 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3966 Yandroid_seB, FALSE, TRUE,
3967 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3970 Yandroid_s, FALSE, FALSE,
3971 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3974 Yandroid_sB, FALSE, TRUE,
3975 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3978 Yandroid_sw, FALSE, FALSE,
3979 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3982 Yandroid_swB, FALSE, TRUE,
3983 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3986 Yandroid_w, FALSE, FALSE,
3987 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3990 Yandroid_wB, FALSE, TRUE,
3991 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3994 Yandroid_nw, FALSE, FALSE,
3995 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3998 Yandroid_nwB, FALSE, TRUE,
3999 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4002 Xspring, TRUE, FALSE,
4006 Xspring_pause, FALSE, FALSE,
4010 Xspring_e, FALSE, FALSE,
4014 Xspring_w, FALSE, FALSE,
4018 Xspring_fall, FALSE, FALSE,
4022 Yspring_s, FALSE, FALSE,
4023 EL_SPRING, ACTION_FALLING, -1
4026 Yspring_sB, FALSE, TRUE,
4027 EL_SPRING, ACTION_FALLING, -1
4030 Yspring_e, FALSE, FALSE,
4031 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4034 Yspring_eB, FALSE, TRUE,
4035 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4038 Yspring_w, FALSE, FALSE,
4039 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4042 Yspring_wB, FALSE, TRUE,
4043 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4046 Yspring_kill_e, FALSE, FALSE,
4047 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4050 Yspring_kill_eB, FALSE, TRUE,
4051 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4054 Yspring_kill_w, FALSE, FALSE,
4055 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4058 Yspring_kill_wB, FALSE, TRUE,
4059 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4062 Xeater_n, TRUE, FALSE,
4063 EL_YAMYAM_UP, -1, -1
4066 Xeater_e, TRUE, FALSE,
4067 EL_YAMYAM_RIGHT, -1, -1
4070 Xeater_w, TRUE, FALSE,
4071 EL_YAMYAM_LEFT, -1, -1
4074 Xeater_s, TRUE, FALSE,
4075 EL_YAMYAM_DOWN, -1, -1
4078 Yeater_n, FALSE, FALSE,
4079 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4082 Yeater_nB, FALSE, TRUE,
4083 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4086 Yeater_e, FALSE, FALSE,
4087 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4090 Yeater_eB, FALSE, TRUE,
4091 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4094 Yeater_s, FALSE, FALSE,
4095 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4098 Yeater_sB, FALSE, TRUE,
4099 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4102 Yeater_w, FALSE, FALSE,
4103 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4106 Yeater_wB, FALSE, TRUE,
4107 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4110 Yeater_stone, FALSE, FALSE,
4111 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4114 Yeater_spring, FALSE, FALSE,
4115 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4118 Xalien, TRUE, FALSE,
4122 Xalien_pause, FALSE, FALSE,
4126 Yalien_n, FALSE, FALSE,
4127 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4130 Yalien_nB, FALSE, TRUE,
4131 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4134 Yalien_e, FALSE, FALSE,
4135 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4138 Yalien_eB, FALSE, TRUE,
4139 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4142 Yalien_s, FALSE, FALSE,
4143 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4146 Yalien_sB, FALSE, TRUE,
4147 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4150 Yalien_w, FALSE, FALSE,
4151 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4154 Yalien_wB, FALSE, TRUE,
4155 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4158 Yalien_stone, FALSE, FALSE,
4159 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4162 Yalien_spring, FALSE, FALSE,
4163 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4166 Xemerald, TRUE, FALSE,
4170 Xemerald_pause, FALSE, FALSE,
4174 Xemerald_fall, FALSE, FALSE,
4178 Xemerald_shine, FALSE, FALSE,
4179 EL_EMERALD, ACTION_TWINKLING, -1
4182 Yemerald_s, FALSE, FALSE,
4183 EL_EMERALD, ACTION_FALLING, -1
4186 Yemerald_sB, FALSE, TRUE,
4187 EL_EMERALD, ACTION_FALLING, -1
4190 Yemerald_e, FALSE, FALSE,
4191 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4194 Yemerald_eB, FALSE, TRUE,
4195 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4198 Yemerald_w, FALSE, FALSE,
4199 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4202 Yemerald_wB, FALSE, TRUE,
4203 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4206 Yemerald_eat, FALSE, FALSE,
4207 EL_EMERALD, ACTION_COLLECTING, -1
4210 Yemerald_stone, FALSE, FALSE,
4211 EL_NUT, ACTION_BREAKING, -1
4214 Xdiamond, TRUE, FALSE,
4218 Xdiamond_pause, FALSE, FALSE,
4222 Xdiamond_fall, FALSE, FALSE,
4226 Xdiamond_shine, FALSE, FALSE,
4227 EL_DIAMOND, ACTION_TWINKLING, -1
4230 Ydiamond_s, FALSE, FALSE,
4231 EL_DIAMOND, ACTION_FALLING, -1
4234 Ydiamond_sB, FALSE, TRUE,
4235 EL_DIAMOND, ACTION_FALLING, -1
4238 Ydiamond_e, FALSE, FALSE,
4239 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4242 Ydiamond_eB, FALSE, TRUE,
4243 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4246 Ydiamond_w, FALSE, FALSE,
4247 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4250 Ydiamond_wB, FALSE, TRUE,
4251 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4254 Ydiamond_eat, FALSE, FALSE,
4255 EL_DIAMOND, ACTION_COLLECTING, -1
4258 Ydiamond_stone, FALSE, FALSE,
4259 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4262 Xdrip_fall, TRUE, FALSE,
4263 EL_AMOEBA_DROP, -1, -1
4266 Xdrip_stretch, FALSE, FALSE,
4267 EL_AMOEBA_DROP, ACTION_FALLING, -1
4270 Xdrip_stretchB, FALSE, TRUE,
4271 EL_AMOEBA_DROP, ACTION_FALLING, -1
4274 Xdrip_eat, FALSE, FALSE,
4275 EL_AMOEBA_DROP, ACTION_GROWING, -1
4278 Ydrip_s1, FALSE, FALSE,
4279 EL_AMOEBA_DROP, ACTION_FALLING, -1
4282 Ydrip_s1B, FALSE, TRUE,
4283 EL_AMOEBA_DROP, ACTION_FALLING, -1
4286 Ydrip_s2, FALSE, FALSE,
4287 EL_AMOEBA_DROP, ACTION_FALLING, -1
4290 Ydrip_s2B, FALSE, TRUE,
4291 EL_AMOEBA_DROP, ACTION_FALLING, -1
4298 Xbomb_pause, FALSE, FALSE,
4302 Xbomb_fall, FALSE, FALSE,
4306 Ybomb_s, FALSE, FALSE,
4307 EL_BOMB, ACTION_FALLING, -1
4310 Ybomb_sB, FALSE, TRUE,
4311 EL_BOMB, ACTION_FALLING, -1
4314 Ybomb_e, FALSE, FALSE,
4315 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4318 Ybomb_eB, FALSE, TRUE,
4319 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4322 Ybomb_w, FALSE, FALSE,
4323 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4326 Ybomb_wB, FALSE, TRUE,
4327 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4330 Ybomb_eat, FALSE, FALSE,
4331 EL_BOMB, ACTION_ACTIVATING, -1
4334 Xballoon, TRUE, FALSE,
4338 Yballoon_n, FALSE, FALSE,
4339 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4342 Yballoon_nB, FALSE, TRUE,
4343 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4346 Yballoon_e, FALSE, FALSE,
4347 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4350 Yballoon_eB, FALSE, TRUE,
4351 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4354 Yballoon_s, FALSE, FALSE,
4355 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4358 Yballoon_sB, FALSE, TRUE,
4359 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4362 Yballoon_w, FALSE, FALSE,
4363 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4366 Yballoon_wB, FALSE, TRUE,
4367 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4370 Xgrass, TRUE, FALSE,
4371 EL_EMC_GRASS, -1, -1
4374 Ygrass_nB, FALSE, FALSE,
4375 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4378 Ygrass_eB, FALSE, FALSE,
4379 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4382 Ygrass_sB, FALSE, FALSE,
4383 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4386 Ygrass_wB, FALSE, FALSE,
4387 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4394 Ydirt_nB, FALSE, FALSE,
4395 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4398 Ydirt_eB, FALSE, FALSE,
4399 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4402 Ydirt_sB, FALSE, FALSE,
4403 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4406 Ydirt_wB, FALSE, FALSE,
4407 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4410 Xacid_ne, TRUE, FALSE,
4411 EL_ACID_POOL_TOPRIGHT, -1, -1
4414 Xacid_se, TRUE, FALSE,
4415 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4418 Xacid_s, TRUE, FALSE,
4419 EL_ACID_POOL_BOTTOM, -1, -1
4422 Xacid_sw, TRUE, FALSE,
4423 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4426 Xacid_nw, TRUE, FALSE,
4427 EL_ACID_POOL_TOPLEFT, -1, -1
4430 Xacid_1, TRUE, FALSE,
4434 Xacid_2, FALSE, FALSE,
4438 Xacid_3, FALSE, FALSE,
4442 Xacid_4, FALSE, FALSE,
4446 Xacid_5, FALSE, FALSE,
4450 Xacid_6, FALSE, FALSE,
4454 Xacid_7, FALSE, FALSE,
4458 Xacid_8, FALSE, FALSE,
4462 Xball_1, TRUE, FALSE,
4463 EL_EMC_MAGIC_BALL, -1, -1
4466 Xball_1B, FALSE, FALSE,
4467 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4470 Xball_2, FALSE, FALSE,
4471 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4474 Xball_2B, FALSE, FALSE,
4475 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4478 Yball_eat, FALSE, FALSE,
4479 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4482 Ykey_1_eat, FALSE, FALSE,
4483 EL_EM_KEY_1, ACTION_COLLECTING, -1
4486 Ykey_2_eat, FALSE, FALSE,
4487 EL_EM_KEY_2, ACTION_COLLECTING, -1
4490 Ykey_3_eat, FALSE, FALSE,
4491 EL_EM_KEY_3, ACTION_COLLECTING, -1
4494 Ykey_4_eat, FALSE, FALSE,
4495 EL_EM_KEY_4, ACTION_COLLECTING, -1
4498 Ykey_5_eat, FALSE, FALSE,
4499 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4502 Ykey_6_eat, FALSE, FALSE,
4503 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4506 Ykey_7_eat, FALSE, FALSE,
4507 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4510 Ykey_8_eat, FALSE, FALSE,
4511 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4514 Ylenses_eat, FALSE, FALSE,
4515 EL_EMC_LENSES, ACTION_COLLECTING, -1
4518 Ymagnify_eat, FALSE, FALSE,
4519 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4522 Ygrass_eat, FALSE, FALSE,
4523 EL_EMC_GRASS, ACTION_SNAPPING, -1
4526 Ydirt_eat, FALSE, FALSE,
4527 EL_SAND, ACTION_SNAPPING, -1
4530 Xgrow_ns, TRUE, FALSE,
4531 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4534 Ygrow_ns_eat, FALSE, FALSE,
4535 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4538 Xgrow_ew, TRUE, FALSE,
4539 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4542 Ygrow_ew_eat, FALSE, FALSE,
4543 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4546 Xwonderwall, TRUE, FALSE,
4547 EL_MAGIC_WALL, -1, -1
4550 XwonderwallB, FALSE, FALSE,
4551 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4554 Xamoeba_1, TRUE, FALSE,
4555 EL_AMOEBA_DRY, ACTION_OTHER, -1
4558 Xamoeba_2, FALSE, FALSE,
4559 EL_AMOEBA_DRY, ACTION_OTHER, -1
4562 Xamoeba_3, FALSE, FALSE,
4563 EL_AMOEBA_DRY, ACTION_OTHER, -1
4566 Xamoeba_4, FALSE, FALSE,
4567 EL_AMOEBA_DRY, ACTION_OTHER, -1
4570 Xamoeba_5, TRUE, FALSE,
4571 EL_AMOEBA_WET, ACTION_OTHER, -1
4574 Xamoeba_6, FALSE, FALSE,
4575 EL_AMOEBA_WET, ACTION_OTHER, -1
4578 Xamoeba_7, FALSE, FALSE,
4579 EL_AMOEBA_WET, ACTION_OTHER, -1
4582 Xamoeba_8, FALSE, FALSE,
4583 EL_AMOEBA_WET, ACTION_OTHER, -1
4586 Xdoor_1, TRUE, FALSE,
4587 EL_EM_GATE_1, -1, -1
4590 Xdoor_2, TRUE, FALSE,
4591 EL_EM_GATE_2, -1, -1
4594 Xdoor_3, TRUE, FALSE,
4595 EL_EM_GATE_3, -1, -1
4598 Xdoor_4, TRUE, FALSE,
4599 EL_EM_GATE_4, -1, -1
4602 Xdoor_5, TRUE, FALSE,
4603 EL_EMC_GATE_5, -1, -1
4606 Xdoor_6, TRUE, FALSE,
4607 EL_EMC_GATE_6, -1, -1
4610 Xdoor_7, TRUE, FALSE,
4611 EL_EMC_GATE_7, -1, -1
4614 Xdoor_8, TRUE, FALSE,
4615 EL_EMC_GATE_8, -1, -1
4618 Xkey_1, TRUE, FALSE,
4622 Xkey_2, TRUE, FALSE,
4626 Xkey_3, TRUE, FALSE,
4630 Xkey_4, TRUE, FALSE,
4634 Xkey_5, TRUE, FALSE,
4635 EL_EMC_KEY_5, -1, -1
4638 Xkey_6, TRUE, FALSE,
4639 EL_EMC_KEY_6, -1, -1
4642 Xkey_7, TRUE, FALSE,
4643 EL_EMC_KEY_7, -1, -1
4646 Xkey_8, TRUE, FALSE,
4647 EL_EMC_KEY_8, -1, -1
4650 Xwind_n, TRUE, FALSE,
4651 EL_BALLOON_SWITCH_UP, -1, -1
4654 Xwind_e, TRUE, FALSE,
4655 EL_BALLOON_SWITCH_RIGHT, -1, -1
4658 Xwind_s, TRUE, FALSE,
4659 EL_BALLOON_SWITCH_DOWN, -1, -1
4662 Xwind_w, TRUE, FALSE,
4663 EL_BALLOON_SWITCH_LEFT, -1, -1
4666 Xwind_nesw, TRUE, FALSE,
4667 EL_BALLOON_SWITCH_ANY, -1, -1
4670 Xwind_stop, TRUE, FALSE,
4671 EL_BALLOON_SWITCH_NONE, -1, -1
4675 EL_EM_EXIT_CLOSED, -1, -1
4678 Xexit_1, TRUE, FALSE,
4679 EL_EM_EXIT_OPEN, -1, -1
4682 Xexit_2, FALSE, FALSE,
4683 EL_EM_EXIT_OPEN, -1, -1
4686 Xexit_3, FALSE, FALSE,
4687 EL_EM_EXIT_OPEN, -1, -1
4690 Xdynamite, TRUE, FALSE,
4691 EL_EM_DYNAMITE, -1, -1
4694 Ydynamite_eat, FALSE, FALSE,
4695 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4698 Xdynamite_1, TRUE, FALSE,
4699 EL_EM_DYNAMITE_ACTIVE, -1, -1
4702 Xdynamite_2, FALSE, FALSE,
4703 EL_EM_DYNAMITE_ACTIVE, -1, -1
4706 Xdynamite_3, FALSE, FALSE,
4707 EL_EM_DYNAMITE_ACTIVE, -1, -1
4710 Xdynamite_4, FALSE, FALSE,
4711 EL_EM_DYNAMITE_ACTIVE, -1, -1
4714 Xbumper, TRUE, FALSE,
4715 EL_EMC_SPRING_BUMPER, -1, -1
4718 XbumperB, FALSE, FALSE,
4719 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4722 Xwheel, TRUE, FALSE,
4723 EL_ROBOT_WHEEL, -1, -1
4726 XwheelB, FALSE, FALSE,
4727 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4730 Xswitch, TRUE, FALSE,
4731 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4734 XswitchB, FALSE, FALSE,
4735 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4739 EL_QUICKSAND_EMPTY, -1, -1
4742 Xsand_stone, TRUE, FALSE,
4743 EL_QUICKSAND_FULL, -1, -1
4746 Xsand_stonein_1, FALSE, TRUE,
4747 EL_ROCK, ACTION_FILLING, -1
4750 Xsand_stonein_2, FALSE, TRUE,
4751 EL_ROCK, ACTION_FILLING, -1
4754 Xsand_stonein_3, FALSE, TRUE,
4755 EL_ROCK, ACTION_FILLING, -1
4758 Xsand_stonein_4, FALSE, TRUE,
4759 EL_ROCK, ACTION_FILLING, -1
4762 Xsand_stonesand_1, FALSE, FALSE,
4763 EL_QUICKSAND_FULL, -1, -1
4766 Xsand_stonesand_2, FALSE, FALSE,
4767 EL_QUICKSAND_FULL, -1, -1
4770 Xsand_stonesand_3, FALSE, FALSE,
4771 EL_QUICKSAND_FULL, -1, -1
4774 Xsand_stonesand_4, FALSE, FALSE,
4775 EL_QUICKSAND_FULL, -1, -1
4778 Xsand_stoneout_1, FALSE, FALSE,
4779 EL_ROCK, ACTION_EMPTYING, -1
4782 Xsand_stoneout_2, FALSE, FALSE,
4783 EL_ROCK, ACTION_EMPTYING, -1
4786 Xsand_sandstone_1, FALSE, FALSE,
4787 EL_QUICKSAND_FULL, -1, -1
4790 Xsand_sandstone_2, FALSE, FALSE,
4791 EL_QUICKSAND_FULL, -1, -1
4794 Xsand_sandstone_3, FALSE, FALSE,
4795 EL_QUICKSAND_FULL, -1, -1
4798 Xsand_sandstone_4, FALSE, FALSE,
4799 EL_QUICKSAND_FULL, -1, -1
4802 Xplant, TRUE, FALSE,
4803 EL_EMC_PLANT, -1, -1
4806 Yplant, FALSE, FALSE,
4807 EL_EMC_PLANT, -1, -1
4810 Xlenses, TRUE, FALSE,
4811 EL_EMC_LENSES, -1, -1
4814 Xmagnify, TRUE, FALSE,
4815 EL_EMC_MAGNIFIER, -1, -1
4818 Xdripper, TRUE, FALSE,
4819 EL_EMC_DRIPPER, -1, -1
4822 XdripperB, FALSE, FALSE,
4823 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4826 Xfake_blank, TRUE, FALSE,
4827 EL_INVISIBLE_WALL, -1, -1
4830 Xfake_blankB, FALSE, FALSE,
4831 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4834 Xfake_grass, TRUE, FALSE,
4835 EL_EMC_FAKE_GRASS, -1, -1
4838 Xfake_grassB, FALSE, FALSE,
4839 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4842 Xfake_door_1, TRUE, FALSE,
4843 EL_EM_GATE_1_GRAY, -1, -1
4846 Xfake_door_2, TRUE, FALSE,
4847 EL_EM_GATE_2_GRAY, -1, -1
4850 Xfake_door_3, TRUE, FALSE,
4851 EL_EM_GATE_3_GRAY, -1, -1
4854 Xfake_door_4, TRUE, FALSE,
4855 EL_EM_GATE_4_GRAY, -1, -1
4858 Xfake_door_5, TRUE, FALSE,
4859 EL_EMC_GATE_5_GRAY, -1, -1
4862 Xfake_door_6, TRUE, FALSE,
4863 EL_EMC_GATE_6_GRAY, -1, -1
4866 Xfake_door_7, TRUE, FALSE,
4867 EL_EMC_GATE_7_GRAY, -1, -1
4870 Xfake_door_8, TRUE, FALSE,
4871 EL_EMC_GATE_8_GRAY, -1, -1
4874 Xfake_acid_1, TRUE, FALSE,
4875 EL_EMC_FAKE_ACID, -1, -1
4878 Xfake_acid_2, FALSE, FALSE,
4879 EL_EMC_FAKE_ACID, -1, -1
4882 Xfake_acid_3, FALSE, FALSE,
4883 EL_EMC_FAKE_ACID, -1, -1
4886 Xfake_acid_4, FALSE, FALSE,
4887 EL_EMC_FAKE_ACID, -1, -1
4890 Xfake_acid_5, FALSE, FALSE,
4891 EL_EMC_FAKE_ACID, -1, -1
4894 Xfake_acid_6, FALSE, FALSE,
4895 EL_EMC_FAKE_ACID, -1, -1
4898 Xfake_acid_7, FALSE, FALSE,
4899 EL_EMC_FAKE_ACID, -1, -1
4902 Xfake_acid_8, FALSE, FALSE,
4903 EL_EMC_FAKE_ACID, -1, -1
4906 Xsteel_1, TRUE, FALSE,
4907 EL_STEELWALL, -1, -1
4910 Xsteel_2, TRUE, FALSE,
4911 EL_EMC_STEELWALL_2, -1, -1
4914 Xsteel_3, TRUE, FALSE,
4915 EL_EMC_STEELWALL_3, -1, -1
4918 Xsteel_4, TRUE, FALSE,
4919 EL_EMC_STEELWALL_4, -1, -1
4922 Xwall_1, TRUE, FALSE,
4926 Xwall_2, TRUE, FALSE,
4927 EL_EMC_WALL_14, -1, -1
4930 Xwall_3, TRUE, FALSE,
4931 EL_EMC_WALL_15, -1, -1
4934 Xwall_4, TRUE, FALSE,
4935 EL_EMC_WALL_16, -1, -1
4938 Xround_wall_1, TRUE, FALSE,
4939 EL_WALL_SLIPPERY, -1, -1
4942 Xround_wall_2, TRUE, FALSE,
4943 EL_EMC_WALL_SLIPPERY_2, -1, -1
4946 Xround_wall_3, TRUE, FALSE,
4947 EL_EMC_WALL_SLIPPERY_3, -1, -1
4950 Xround_wall_4, TRUE, FALSE,
4951 EL_EMC_WALL_SLIPPERY_4, -1, -1
4954 Xdecor_1, TRUE, FALSE,
4955 EL_EMC_WALL_8, -1, -1
4958 Xdecor_2, TRUE, FALSE,
4959 EL_EMC_WALL_6, -1, -1
4962 Xdecor_3, TRUE, FALSE,
4963 EL_EMC_WALL_4, -1, -1
4966 Xdecor_4, TRUE, FALSE,
4967 EL_EMC_WALL_7, -1, -1
4970 Xdecor_5, TRUE, FALSE,
4971 EL_EMC_WALL_5, -1, -1
4974 Xdecor_6, TRUE, FALSE,
4975 EL_EMC_WALL_9, -1, -1
4978 Xdecor_7, TRUE, FALSE,
4979 EL_EMC_WALL_10, -1, -1
4982 Xdecor_8, TRUE, FALSE,
4983 EL_EMC_WALL_1, -1, -1
4986 Xdecor_9, TRUE, FALSE,
4987 EL_EMC_WALL_2, -1, -1
4990 Xdecor_10, TRUE, FALSE,
4991 EL_EMC_WALL_3, -1, -1
4994 Xdecor_11, TRUE, FALSE,
4995 EL_EMC_WALL_11, -1, -1
4998 Xdecor_12, TRUE, FALSE,
4999 EL_EMC_WALL_12, -1, -1
5002 Xalpha_0, TRUE, FALSE,
5003 EL_CHAR('0'), -1, -1
5006 Xalpha_1, TRUE, FALSE,
5007 EL_CHAR('1'), -1, -1
5010 Xalpha_2, TRUE, FALSE,
5011 EL_CHAR('2'), -1, -1
5014 Xalpha_3, TRUE, FALSE,
5015 EL_CHAR('3'), -1, -1
5018 Xalpha_4, TRUE, FALSE,
5019 EL_CHAR('4'), -1, -1
5022 Xalpha_5, TRUE, FALSE,
5023 EL_CHAR('5'), -1, -1
5026 Xalpha_6, TRUE, FALSE,
5027 EL_CHAR('6'), -1, -1
5030 Xalpha_7, TRUE, FALSE,
5031 EL_CHAR('7'), -1, -1
5034 Xalpha_8, TRUE, FALSE,
5035 EL_CHAR('8'), -1, -1
5038 Xalpha_9, TRUE, FALSE,
5039 EL_CHAR('9'), -1, -1
5042 Xalpha_excla, TRUE, FALSE,
5043 EL_CHAR('!'), -1, -1
5046 Xalpha_quote, TRUE, FALSE,
5047 EL_CHAR('"'), -1, -1
5050 Xalpha_comma, TRUE, FALSE,
5051 EL_CHAR(','), -1, -1
5054 Xalpha_minus, TRUE, FALSE,
5055 EL_CHAR('-'), -1, -1
5058 Xalpha_perio, TRUE, FALSE,
5059 EL_CHAR('.'), -1, -1
5062 Xalpha_colon, TRUE, FALSE,
5063 EL_CHAR(':'), -1, -1
5066 Xalpha_quest, TRUE, FALSE,
5067 EL_CHAR('?'), -1, -1
5070 Xalpha_a, TRUE, FALSE,
5071 EL_CHAR('A'), -1, -1
5074 Xalpha_b, TRUE, FALSE,
5075 EL_CHAR('B'), -1, -1
5078 Xalpha_c, TRUE, FALSE,
5079 EL_CHAR('C'), -1, -1
5082 Xalpha_d, TRUE, FALSE,
5083 EL_CHAR('D'), -1, -1
5086 Xalpha_e, TRUE, FALSE,
5087 EL_CHAR('E'), -1, -1
5090 Xalpha_f, TRUE, FALSE,
5091 EL_CHAR('F'), -1, -1
5094 Xalpha_g, TRUE, FALSE,
5095 EL_CHAR('G'), -1, -1
5098 Xalpha_h, TRUE, FALSE,
5099 EL_CHAR('H'), -1, -1
5102 Xalpha_i, TRUE, FALSE,
5103 EL_CHAR('I'), -1, -1
5106 Xalpha_j, TRUE, FALSE,
5107 EL_CHAR('J'), -1, -1
5110 Xalpha_k, TRUE, FALSE,
5111 EL_CHAR('K'), -1, -1
5114 Xalpha_l, TRUE, FALSE,
5115 EL_CHAR('L'), -1, -1
5118 Xalpha_m, TRUE, FALSE,
5119 EL_CHAR('M'), -1, -1
5122 Xalpha_n, TRUE, FALSE,
5123 EL_CHAR('N'), -1, -1
5126 Xalpha_o, TRUE, FALSE,
5127 EL_CHAR('O'), -1, -1
5130 Xalpha_p, TRUE, FALSE,
5131 EL_CHAR('P'), -1, -1
5134 Xalpha_q, TRUE, FALSE,
5135 EL_CHAR('Q'), -1, -1
5138 Xalpha_r, TRUE, FALSE,
5139 EL_CHAR('R'), -1, -1
5142 Xalpha_s, TRUE, FALSE,
5143 EL_CHAR('S'), -1, -1
5146 Xalpha_t, TRUE, FALSE,
5147 EL_CHAR('T'), -1, -1
5150 Xalpha_u, TRUE, FALSE,
5151 EL_CHAR('U'), -1, -1
5154 Xalpha_v, TRUE, FALSE,
5155 EL_CHAR('V'), -1, -1
5158 Xalpha_w, TRUE, FALSE,
5159 EL_CHAR('W'), -1, -1
5162 Xalpha_x, TRUE, FALSE,
5163 EL_CHAR('X'), -1, -1
5166 Xalpha_y, TRUE, FALSE,
5167 EL_CHAR('Y'), -1, -1
5170 Xalpha_z, TRUE, FALSE,
5171 EL_CHAR('Z'), -1, -1
5174 Xalpha_arrow_e, TRUE, FALSE,
5175 EL_CHAR('>'), -1, -1
5178 Xalpha_arrow_w, TRUE, FALSE,
5179 EL_CHAR('<'), -1, -1
5182 Xalpha_copyr, TRUE, FALSE,
5183 EL_CHAR('©'), -1, -1
5187 Xboom_bug, FALSE, FALSE,
5188 EL_BUG, ACTION_EXPLODING, -1
5191 Xboom_bomb, FALSE, FALSE,
5192 EL_BOMB, ACTION_EXPLODING, -1
5195 Xboom_android, FALSE, FALSE,
5196 EL_EMC_ANDROID, ACTION_OTHER, -1
5199 Xboom_1, FALSE, FALSE,
5200 EL_DEFAULT, ACTION_EXPLODING, -1
5203 Xboom_2, FALSE, FALSE,
5204 EL_DEFAULT, ACTION_EXPLODING, -1
5207 Znormal, FALSE, FALSE,
5211 Zdynamite, FALSE, FALSE,
5215 Zplayer, FALSE, FALSE,
5219 ZBORDER, FALSE, FALSE,
5229 static struct Mapping_EM_to_RND_player
5238 em_player_mapping_list[] =
5242 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5246 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5250 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5254 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5258 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5262 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5266 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5270 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5274 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5278 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5282 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5286 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5290 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5294 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5298 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5302 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5306 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5310 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5314 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5318 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5322 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5326 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5330 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5334 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5338 EL_PLAYER_1, ACTION_DEFAULT, -1,
5342 EL_PLAYER_2, ACTION_DEFAULT, -1,
5346 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5350 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5354 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5358 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5362 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5366 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5370 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5374 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5378 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5382 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5386 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5390 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5394 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5398 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5402 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5406 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5410 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5414 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5418 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5422 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5426 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5430 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5434 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5438 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5442 EL_PLAYER_3, ACTION_DEFAULT, -1,
5446 EL_PLAYER_4, ACTION_DEFAULT, -1,
5455 int map_element_RND_to_EM(int element_rnd)
5457 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5458 static boolean mapping_initialized = FALSE;
5460 if (!mapping_initialized)
5464 /* return "Xalpha_quest" for all undefined elements in mapping array */
5465 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5466 mapping_RND_to_EM[i] = Xalpha_quest;
5468 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5469 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5470 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5471 em_object_mapping_list[i].element_em;
5473 mapping_initialized = TRUE;
5476 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5477 return mapping_RND_to_EM[element_rnd];
5479 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5484 int map_element_EM_to_RND(int element_em)
5486 static unsigned short mapping_EM_to_RND[TILE_MAX];
5487 static boolean mapping_initialized = FALSE;
5489 if (!mapping_initialized)
5493 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5494 for (i = 0; i < TILE_MAX; i++)
5495 mapping_EM_to_RND[i] = EL_UNKNOWN;
5497 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5498 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5499 em_object_mapping_list[i].element_rnd;
5501 mapping_initialized = TRUE;
5504 if (element_em >= 0 && element_em < TILE_MAX)
5505 return mapping_EM_to_RND[element_em];
5507 Error(ERR_WARN, "invalid EM level element %d", element_em);
5512 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5514 struct LevelInfo_EM *level_em = level->native_em_level;
5515 struct LEVEL *lev = level_em->lev;
5518 for (i = 0; i < TILE_MAX; i++)
5519 lev->android_array[i] = Xblank;
5521 for (i = 0; i < level->num_android_clone_elements; i++)
5523 int element_rnd = level->android_clone_element[i];
5524 int element_em = map_element_RND_to_EM(element_rnd);
5526 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5527 if (em_object_mapping_list[j].element_rnd == element_rnd)
5528 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5532 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5534 struct LevelInfo_EM *level_em = level->native_em_level;
5535 struct LEVEL *lev = level_em->lev;
5538 level->num_android_clone_elements = 0;
5540 for (i = 0; i < TILE_MAX; i++)
5542 int element_em = lev->android_array[i];
5544 boolean element_found = FALSE;
5546 if (element_em == Xblank)
5549 element_rnd = map_element_EM_to_RND(element_em);
5551 for (j = 0; j < level->num_android_clone_elements; j++)
5552 if (level->android_clone_element[j] == element_rnd)
5553 element_found = TRUE;
5557 level->android_clone_element[level->num_android_clone_elements++] =
5560 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5565 if (level->num_android_clone_elements == 0)
5567 level->num_android_clone_elements = 1;
5568 level->android_clone_element[0] = EL_EMPTY;
5572 int map_direction_RND_to_EM(int direction)
5574 return (direction == MV_UP ? 0 :
5575 direction == MV_RIGHT ? 1 :
5576 direction == MV_DOWN ? 2 :
5577 direction == MV_LEFT ? 3 :
5581 int map_direction_EM_to_RND(int direction)
5583 return (direction == 0 ? MV_UP :
5584 direction == 1 ? MV_RIGHT :
5585 direction == 2 ? MV_DOWN :
5586 direction == 3 ? MV_LEFT :
5590 int get_next_element(int element)
5594 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5595 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5596 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5597 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5598 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5599 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5600 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5601 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5602 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5603 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5604 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5606 default: return element;
5611 int el_act_dir2img(int element, int action, int direction)
5613 element = GFX_ELEMENT(element);
5615 if (direction == MV_NONE)
5616 return element_info[element].graphic[action];
5618 direction = MV_DIR_TO_BIT(direction);
5620 return element_info[element].direction_graphic[action][direction];
5623 int el_act_dir2img(int element, int action, int direction)
5625 element = GFX_ELEMENT(element);
5626 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5628 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5629 return element_info[element].direction_graphic[action][direction];
5634 static int el_act_dir2crm(int element, int action, int direction)
5636 element = GFX_ELEMENT(element);
5638 if (direction == MV_NONE)
5639 return element_info[element].crumbled[action];
5641 direction = MV_DIR_TO_BIT(direction);
5643 return element_info[element].direction_crumbled[action][direction];
5646 static int el_act_dir2crm(int element, int action, int direction)
5648 element = GFX_ELEMENT(element);
5649 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5651 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5652 return element_info[element].direction_crumbled[action][direction];
5656 int el_act2img(int element, int action)
5658 element = GFX_ELEMENT(element);
5660 return element_info[element].graphic[action];
5663 int el_act2crm(int element, int action)
5665 element = GFX_ELEMENT(element);
5667 return element_info[element].crumbled[action];
5670 int el_dir2img(int element, int direction)
5672 element = GFX_ELEMENT(element);
5674 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5677 int el2baseimg(int element)
5679 return element_info[element].graphic[ACTION_DEFAULT];
5682 int el2img(int element)
5684 element = GFX_ELEMENT(element);
5686 return element_info[element].graphic[ACTION_DEFAULT];
5689 int el2edimg(int element)
5691 element = GFX_ELEMENT(element);
5693 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5696 int el2preimg(int element)
5698 element = GFX_ELEMENT(element);
5700 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5703 int font2baseimg(int font_nr)
5705 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5708 int getBeltNrFromBeltElement(int element)
5710 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5711 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5712 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5715 int getBeltNrFromBeltActiveElement(int element)
5717 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5718 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5719 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5722 int getBeltNrFromBeltSwitchElement(int element)
5724 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5725 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5726 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5729 int getBeltDirNrFromBeltElement(int element)
5731 static int belt_base_element[4] =
5733 EL_CONVEYOR_BELT_1_LEFT,
5734 EL_CONVEYOR_BELT_2_LEFT,
5735 EL_CONVEYOR_BELT_3_LEFT,
5736 EL_CONVEYOR_BELT_4_LEFT
5739 int belt_nr = getBeltNrFromBeltElement(element);
5740 int belt_dir_nr = element - belt_base_element[belt_nr];
5742 return (belt_dir_nr % 3);
5745 int getBeltDirNrFromBeltSwitchElement(int element)
5747 static int belt_base_element[4] =
5749 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5750 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5751 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5752 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5755 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5756 int belt_dir_nr = element - belt_base_element[belt_nr];
5758 return (belt_dir_nr % 3);
5761 int getBeltDirFromBeltElement(int element)
5763 static int belt_move_dir[3] =
5770 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5772 return belt_move_dir[belt_dir_nr];
5775 int getBeltDirFromBeltSwitchElement(int element)
5777 static int belt_move_dir[3] =
5784 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5786 return belt_move_dir[belt_dir_nr];
5789 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5791 static int belt_base_element[4] =
5793 EL_CONVEYOR_BELT_1_LEFT,
5794 EL_CONVEYOR_BELT_2_LEFT,
5795 EL_CONVEYOR_BELT_3_LEFT,
5796 EL_CONVEYOR_BELT_4_LEFT
5798 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5800 return belt_base_element[belt_nr] + belt_dir_nr;
5803 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5805 static int belt_base_element[4] =
5807 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5808 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5809 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5810 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5812 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5814 return belt_base_element[belt_nr] + belt_dir_nr;
5817 int getNumActivePlayers_EM()
5819 int num_players = 0;
5825 for (i = 0; i < MAX_PLAYERS; i++)
5826 if (tape.player_participates[i])
5832 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5834 int game_frame_delay_value;
5836 game_frame_delay_value =
5837 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5838 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5841 if (tape.playing && tape.warp_forward && !tape.pausing)
5842 game_frame_delay_value = 0;
5844 return game_frame_delay_value;
5847 unsigned int InitRND(long seed)
5849 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5850 return InitEngineRandom_EM(seed);
5852 return InitEngineRandom_RND(seed);
5856 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5857 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5860 void ResetGfxAnimation_EM(int x, int y, int tile)
5865 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5866 Bitmap **src_bitmap, int *src_x, int *src_y,
5869 int element = object_mapping[tile].element_rnd;
5870 int action = object_mapping[tile].action;
5871 int direction = object_mapping[tile].direction;
5872 boolean is_backside = object_mapping[tile].is_backside;
5873 boolean action_removing = (action == ACTION_DIGGING ||
5874 action == ACTION_SNAPPING ||
5875 action == ACTION_COLLECTING);
5876 int effective_element = (frame_em > 0 ? element :
5877 is_backside ? EL_EMPTY :
5878 action_removing ? EL_EMPTY :
5880 int graphic = (direction == MV_NONE ?
5881 el_act2img(effective_element, action) :
5882 el_act_dir2img(effective_element, action, direction));
5883 struct GraphicInfo *g = &graphic_info[graphic];
5886 if (graphic_info[graphic].anim_global_sync)
5887 sync_frame = FrameCounter;
5889 sync_frame = 7 - frame_em;
5891 SetRandomAnimationValue(x, y);
5893 int frame = getAnimationFrame(g->anim_frames,
5896 g->anim_start_frame,
5899 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5902 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
5903 Bitmap **src_bitmap, int *src_x, int *src_y)
5905 int element = player_mapping[player_nr][anim].element_rnd;
5906 int action = player_mapping[player_nr][anim].action;
5907 int direction = player_mapping[player_nr][anim].direction;
5908 int graphic = (direction == MV_NONE ?
5909 el_act2img(element, action) :
5910 el_act_dir2img(element, action, direction));
5911 struct GraphicInfo *g = &graphic_info[graphic];
5914 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
5916 stored_player[player_nr].StepFrame = 7 - frame_em;
5918 sync_frame = stored_player[player_nr].Frame;
5921 printf("::: %d: %d, %d [%d]\n",
5923 stored_player[player_nr].Frame,
5924 stored_player[player_nr].StepFrame,
5928 int frame = getAnimationFrame(g->anim_frames,
5931 g->anim_start_frame,
5934 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5937 void InitGraphicInfo_EM(void)
5940 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5941 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5946 int num_em_gfx_errors = 0;
5948 if (graphic_info_em_object[0][0].bitmap == NULL)
5950 /* EM graphics not yet initialized in em_open_all() */
5955 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5958 /* always start with reliable default values */
5959 for (i = 0; i < TILE_MAX; i++)
5961 object_mapping[i].element_rnd = EL_UNKNOWN;
5962 object_mapping[i].is_backside = FALSE;
5963 object_mapping[i].action = ACTION_DEFAULT;
5964 object_mapping[i].direction = MV_NONE;
5967 /* always start with reliable default values */
5968 for (p = 0; p < MAX_PLAYERS; p++)
5970 for (i = 0; i < SPR_MAX; i++)
5972 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5973 player_mapping[p][i].action = ACTION_DEFAULT;
5974 player_mapping[p][i].direction = MV_NONE;
5978 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5980 int e = em_object_mapping_list[i].element_em;
5982 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5983 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5985 if (em_object_mapping_list[i].action != -1)
5986 object_mapping[e].action = em_object_mapping_list[i].action;
5988 if (em_object_mapping_list[i].direction != -1)
5989 object_mapping[e].direction =
5990 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5993 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5995 int a = em_player_mapping_list[i].action_em;
5996 int p = em_player_mapping_list[i].player_nr;
5998 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6000 if (em_player_mapping_list[i].action != -1)
6001 player_mapping[p][a].action = em_player_mapping_list[i].action;
6003 if (em_player_mapping_list[i].direction != -1)
6004 player_mapping[p][a].direction =
6005 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6008 for (i = 0; i < TILE_MAX; i++)
6010 int element = object_mapping[i].element_rnd;
6011 int action = object_mapping[i].action;
6012 int direction = object_mapping[i].direction;
6013 boolean is_backside = object_mapping[i].is_backside;
6014 boolean action_removing = (action == ACTION_DIGGING ||
6015 action == ACTION_SNAPPING ||
6016 action == ACTION_COLLECTING);
6017 boolean action_exploding = ((action == ACTION_EXPLODING ||
6018 action == ACTION_SMASHED_BY_ROCK ||
6019 action == ACTION_SMASHED_BY_SPRING) &&
6020 element != EL_DIAMOND);
6021 boolean action_active = (action == ACTION_ACTIVE);
6022 boolean action_other = (action == ACTION_OTHER);
6024 for (j = 0; j < 8; j++)
6026 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6027 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6029 i == Xdrip_stretch ? element :
6030 i == Xdrip_stretchB ? element :
6031 i == Ydrip_s1 ? element :
6032 i == Ydrip_s1B ? element :
6033 i == Xball_1B ? element :
6034 i == Xball_2 ? element :
6035 i == Xball_2B ? element :
6036 i == Yball_eat ? element :
6037 i == Ykey_1_eat ? element :
6038 i == Ykey_2_eat ? element :
6039 i == Ykey_3_eat ? element :
6040 i == Ykey_4_eat ? element :
6041 i == Ykey_5_eat ? element :
6042 i == Ykey_6_eat ? element :
6043 i == Ykey_7_eat ? element :
6044 i == Ykey_8_eat ? element :
6045 i == Ylenses_eat ? element :
6046 i == Ymagnify_eat ? element :
6047 i == Ygrass_eat ? element :
6048 i == Ydirt_eat ? element :
6049 i == Yemerald_stone ? EL_EMERALD :
6050 i == Ydiamond_stone ? EL_ROCK :
6051 i == Xsand_stonein_1 ? element :
6052 i == Xsand_stonein_2 ? element :
6053 i == Xsand_stonein_3 ? element :
6054 i == Xsand_stonein_4 ? element :
6055 is_backside ? EL_EMPTY :
6056 action_removing ? EL_EMPTY :
6058 int effective_action = (j < 7 ? action :
6059 i == Xdrip_stretch ? action :
6060 i == Xdrip_stretchB ? action :
6061 i == Ydrip_s1 ? action :
6062 i == Ydrip_s1B ? action :
6063 i == Xball_1B ? action :
6064 i == Xball_2 ? action :
6065 i == Xball_2B ? action :
6066 i == Yball_eat ? action :
6067 i == Ykey_1_eat ? action :
6068 i == Ykey_2_eat ? action :
6069 i == Ykey_3_eat ? action :
6070 i == Ykey_4_eat ? action :
6071 i == Ykey_5_eat ? action :
6072 i == Ykey_6_eat ? action :
6073 i == Ykey_7_eat ? action :
6074 i == Ykey_8_eat ? action :
6075 i == Ylenses_eat ? action :
6076 i == Ymagnify_eat ? action :
6077 i == Ygrass_eat ? action :
6078 i == Ydirt_eat ? action :
6079 i == Xsand_stonein_1 ? action :
6080 i == Xsand_stonein_2 ? action :
6081 i == Xsand_stonein_3 ? action :
6082 i == Xsand_stonein_4 ? action :
6083 i == Xsand_stoneout_1 ? action :
6084 i == Xsand_stoneout_2 ? action :
6085 i == Xboom_android ? ACTION_EXPLODING :
6086 action_exploding ? ACTION_EXPLODING :
6087 action_active ? action :
6088 action_other ? action :
6090 int graphic = (el_act_dir2img(effective_element, effective_action,
6092 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6094 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6095 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6096 boolean has_action_graphics = (graphic != base_graphic);
6097 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6098 struct GraphicInfo *g = &graphic_info[graphic];
6099 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6102 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6103 boolean special_animation = (action != ACTION_DEFAULT &&
6104 g->anim_frames == 3 &&
6105 g->anim_delay == 2 &&
6106 g->anim_mode & ANIM_LINEAR);
6107 int sync_frame = (i == Xdrip_stretch ? 7 :
6108 i == Xdrip_stretchB ? 7 :
6109 i == Ydrip_s2 ? j + 8 :
6110 i == Ydrip_s2B ? j + 8 :
6119 i == Xfake_acid_1 ? 0 :
6120 i == Xfake_acid_2 ? 10 :
6121 i == Xfake_acid_3 ? 20 :
6122 i == Xfake_acid_4 ? 30 :
6123 i == Xfake_acid_5 ? 40 :
6124 i == Xfake_acid_6 ? 50 :
6125 i == Xfake_acid_7 ? 60 :
6126 i == Xfake_acid_8 ? 70 :
6128 i == Xball_2B ? j + 8 :
6129 i == Yball_eat ? j + 1 :
6130 i == Ykey_1_eat ? j + 1 :
6131 i == Ykey_2_eat ? j + 1 :
6132 i == Ykey_3_eat ? j + 1 :
6133 i == Ykey_4_eat ? j + 1 :
6134 i == Ykey_5_eat ? j + 1 :
6135 i == Ykey_6_eat ? j + 1 :
6136 i == Ykey_7_eat ? j + 1 :
6137 i == Ykey_8_eat ? j + 1 :
6138 i == Ylenses_eat ? j + 1 :
6139 i == Ymagnify_eat ? j + 1 :
6140 i == Ygrass_eat ? j + 1 :
6141 i == Ydirt_eat ? j + 1 :
6142 i == Xamoeba_1 ? 0 :
6143 i == Xamoeba_2 ? 1 :
6144 i == Xamoeba_3 ? 2 :
6145 i == Xamoeba_4 ? 3 :
6146 i == Xamoeba_5 ? 0 :
6147 i == Xamoeba_6 ? 1 :
6148 i == Xamoeba_7 ? 2 :
6149 i == Xamoeba_8 ? 3 :
6150 i == Xexit_2 ? j + 8 :
6151 i == Xexit_3 ? j + 16 :
6152 i == Xdynamite_1 ? 0 :
6153 i == Xdynamite_2 ? 8 :
6154 i == Xdynamite_3 ? 16 :
6155 i == Xdynamite_4 ? 24 :
6156 i == Xsand_stonein_1 ? j + 1 :
6157 i == Xsand_stonein_2 ? j + 9 :
6158 i == Xsand_stonein_3 ? j + 17 :
6159 i == Xsand_stonein_4 ? j + 25 :
6160 i == Xsand_stoneout_1 && j == 0 ? 0 :
6161 i == Xsand_stoneout_1 && j == 1 ? 0 :
6162 i == Xsand_stoneout_1 && j == 2 ? 1 :
6163 i == Xsand_stoneout_1 && j == 3 ? 2 :
6164 i == Xsand_stoneout_1 && j == 4 ? 2 :
6165 i == Xsand_stoneout_1 && j == 5 ? 3 :
6166 i == Xsand_stoneout_1 && j == 6 ? 4 :
6167 i == Xsand_stoneout_1 && j == 7 ? 4 :
6168 i == Xsand_stoneout_2 && j == 0 ? 5 :
6169 i == Xsand_stoneout_2 && j == 1 ? 6 :
6170 i == Xsand_stoneout_2 && j == 2 ? 7 :
6171 i == Xsand_stoneout_2 && j == 3 ? 8 :
6172 i == Xsand_stoneout_2 && j == 4 ? 9 :
6173 i == Xsand_stoneout_2 && j == 5 ? 11 :
6174 i == Xsand_stoneout_2 && j == 6 ? 13 :
6175 i == Xsand_stoneout_2 && j == 7 ? 15 :
6176 i == Xboom_bug && j == 1 ? 2 :
6177 i == Xboom_bug && j == 2 ? 2 :
6178 i == Xboom_bug && j == 3 ? 4 :
6179 i == Xboom_bug && j == 4 ? 4 :
6180 i == Xboom_bug && j == 5 ? 2 :
6181 i == Xboom_bug && j == 6 ? 2 :
6182 i == Xboom_bug && j == 7 ? 0 :
6183 i == Xboom_bomb && j == 1 ? 2 :
6184 i == Xboom_bomb && j == 2 ? 2 :
6185 i == Xboom_bomb && j == 3 ? 4 :
6186 i == Xboom_bomb && j == 4 ? 4 :
6187 i == Xboom_bomb && j == 5 ? 2 :
6188 i == Xboom_bomb && j == 6 ? 2 :
6189 i == Xboom_bomb && j == 7 ? 0 :
6190 i == Xboom_android && j == 7 ? 6 :
6191 i == Xboom_1 && j == 1 ? 2 :
6192 i == Xboom_1 && j == 2 ? 2 :
6193 i == Xboom_1 && j == 3 ? 4 :
6194 i == Xboom_1 && j == 4 ? 4 :
6195 i == Xboom_1 && j == 5 ? 6 :
6196 i == Xboom_1 && j == 6 ? 6 :
6197 i == Xboom_1 && j == 7 ? 8 :
6198 i == Xboom_2 && j == 0 ? 8 :
6199 i == Xboom_2 && j == 1 ? 8 :
6200 i == Xboom_2 && j == 2 ? 10 :
6201 i == Xboom_2 && j == 3 ? 10 :
6202 i == Xboom_2 && j == 4 ? 10 :
6203 i == Xboom_2 && j == 5 ? 12 :
6204 i == Xboom_2 && j == 6 ? 12 :
6205 i == Xboom_2 && j == 7 ? 12 :
6206 special_animation && j == 4 ? 3 :
6207 effective_action != action ? 0 :
6211 Bitmap *debug_bitmap = g_em->bitmap;
6212 int debug_src_x = g_em->src_x;
6213 int debug_src_y = g_em->src_y;
6216 int frame = getAnimationFrame(g->anim_frames,
6219 g->anim_start_frame,
6222 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6223 g->double_movement && is_backside);
6225 g_em->bitmap = src_bitmap;
6226 g_em->src_x = src_x;
6227 g_em->src_y = src_y;
6228 g_em->src_offset_x = 0;
6229 g_em->src_offset_y = 0;
6230 g_em->dst_offset_x = 0;
6231 g_em->dst_offset_y = 0;
6232 g_em->width = TILEX;
6233 g_em->height = TILEY;
6235 g_em->crumbled_bitmap = NULL;
6236 g_em->crumbled_src_x = 0;
6237 g_em->crumbled_src_y = 0;
6238 g_em->crumbled_border_size = 0;
6240 g_em->has_crumbled_graphics = FALSE;
6241 g_em->preserve_background = FALSE;
6244 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6245 printf("::: empty crumbled: %d [%s], %d, %d\n",
6246 effective_element, element_info[effective_element].token_name,
6247 effective_action, direction);
6250 /* if element can be crumbled, but certain action graphics are just empty
6251 space (like snapping sand with the original R'n'D graphics), do not
6252 treat these empty space graphics as crumbled graphics in EMC engine */
6253 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6255 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6257 g_em->has_crumbled_graphics = TRUE;
6258 g_em->crumbled_bitmap = src_bitmap;
6259 g_em->crumbled_src_x = src_x;
6260 g_em->crumbled_src_y = src_y;
6261 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6265 if (element == EL_ROCK &&
6266 effective_action == ACTION_FILLING)
6267 printf("::: has_action_graphics == %d\n", has_action_graphics);
6270 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6271 effective_action == ACTION_MOVING ||
6272 effective_action == ACTION_PUSHING ||
6273 effective_action == ACTION_EATING)) ||
6274 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6275 effective_action == ACTION_EMPTYING)))
6278 (effective_action == ACTION_FALLING ||
6279 effective_action == ACTION_FILLING ||
6280 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6281 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6282 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6283 int num_steps = (i == Ydrip_s1 ? 16 :
6284 i == Ydrip_s1B ? 16 :
6285 i == Ydrip_s2 ? 16 :
6286 i == Ydrip_s2B ? 16 :
6287 i == Xsand_stonein_1 ? 32 :
6288 i == Xsand_stonein_2 ? 32 :
6289 i == Xsand_stonein_3 ? 32 :
6290 i == Xsand_stonein_4 ? 32 :
6291 i == Xsand_stoneout_1 ? 16 :
6292 i == Xsand_stoneout_2 ? 16 : 8);
6293 int cx = ABS(dx) * (TILEX / num_steps);
6294 int cy = ABS(dy) * (TILEY / num_steps);
6295 int step_frame = (i == Ydrip_s2 ? j + 8 :
6296 i == Ydrip_s2B ? j + 8 :
6297 i == Xsand_stonein_2 ? j + 8 :
6298 i == Xsand_stonein_3 ? j + 16 :
6299 i == Xsand_stonein_4 ? j + 24 :
6300 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6301 int step = (is_backside ? step_frame : num_steps - step_frame);
6303 if (is_backside) /* tile where movement starts */
6305 if (dx < 0 || dy < 0)
6307 g_em->src_offset_x = cx * step;
6308 g_em->src_offset_y = cy * step;
6312 g_em->dst_offset_x = cx * step;
6313 g_em->dst_offset_y = cy * step;
6316 else /* tile where movement ends */
6318 if (dx < 0 || dy < 0)
6320 g_em->dst_offset_x = cx * step;
6321 g_em->dst_offset_y = cy * step;
6325 g_em->src_offset_x = cx * step;
6326 g_em->src_offset_y = cy * step;
6330 g_em->width = TILEX - cx * step;
6331 g_em->height = TILEY - cy * step;
6334 /* create unique graphic identifier to decide if tile must be redrawn */
6335 /* bit 31 - 16 (16 bit): EM style graphic
6336 bit 15 - 12 ( 4 bit): EM style frame
6337 bit 11 - 6 ( 6 bit): graphic width
6338 bit 5 - 0 ( 6 bit): graphic height */
6339 g_em->unique_identifier =
6340 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6344 /* skip check for EMC elements not contained in original EMC artwork */
6345 if (element == EL_EMC_FAKE_ACID)
6348 if (g_em->bitmap != debug_bitmap ||
6349 g_em->src_x != debug_src_x ||
6350 g_em->src_y != debug_src_y ||
6351 g_em->src_offset_x != 0 ||
6352 g_em->src_offset_y != 0 ||
6353 g_em->dst_offset_x != 0 ||
6354 g_em->dst_offset_y != 0 ||
6355 g_em->width != TILEX ||
6356 g_em->height != TILEY)
6358 static int last_i = -1;
6366 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6367 i, element, element_info[element].token_name,
6368 element_action_info[effective_action].suffix, direction);
6370 if (element != effective_element)
6371 printf(" [%d ('%s')]",
6373 element_info[effective_element].token_name);
6377 if (g_em->bitmap != debug_bitmap)
6378 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6379 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6381 if (g_em->src_x != debug_src_x ||
6382 g_em->src_y != debug_src_y)
6383 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6384 j, (is_backside ? 'B' : 'F'),
6385 g_em->src_x, g_em->src_y,
6386 g_em->src_x / 32, g_em->src_y / 32,
6387 debug_src_x, debug_src_y,
6388 debug_src_x / 32, debug_src_y / 32);
6390 if (g_em->src_offset_x != 0 ||
6391 g_em->src_offset_y != 0 ||
6392 g_em->dst_offset_x != 0 ||
6393 g_em->dst_offset_y != 0)
6394 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6396 g_em->src_offset_x, g_em->src_offset_y,
6397 g_em->dst_offset_x, g_em->dst_offset_y);
6399 if (g_em->width != TILEX ||
6400 g_em->height != TILEY)
6401 printf(" %d (%d): size %d,%d should be %d,%d\n",
6403 g_em->width, g_em->height, TILEX, TILEY);
6405 num_em_gfx_errors++;
6412 for (i = 0; i < TILE_MAX; i++)
6414 for (j = 0; j < 8; j++)
6416 int element = object_mapping[i].element_rnd;
6417 int action = object_mapping[i].action;
6418 int direction = object_mapping[i].direction;
6419 boolean is_backside = object_mapping[i].is_backside;
6420 int graphic_action = el_act_dir2img(element, action, direction);
6421 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6423 if ((action == ACTION_SMASHED_BY_ROCK ||
6424 action == ACTION_SMASHED_BY_SPRING ||
6425 action == ACTION_EATING) &&
6426 graphic_action == graphic_default)
6428 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6429 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6430 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6431 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6434 /* no separate animation for "smashed by rock" -- use rock instead */
6435 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6436 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6438 g_em->bitmap = g_xx->bitmap;
6439 g_em->src_x = g_xx->src_x;
6440 g_em->src_y = g_xx->src_y;
6441 g_em->src_offset_x = g_xx->src_offset_x;
6442 g_em->src_offset_y = g_xx->src_offset_y;
6443 g_em->dst_offset_x = g_xx->dst_offset_x;
6444 g_em->dst_offset_y = g_xx->dst_offset_y;
6445 g_em->width = g_xx->width;
6446 g_em->height = g_xx->height;
6447 g_em->unique_identifier = g_xx->unique_identifier;
6450 g_em->preserve_background = TRUE;
6455 for (p = 0; p < MAX_PLAYERS; p++)
6457 for (i = 0; i < SPR_MAX; i++)
6459 int element = player_mapping[p][i].element_rnd;
6460 int action = player_mapping[p][i].action;
6461 int direction = player_mapping[p][i].direction;
6463 for (j = 0; j < 8; j++)
6465 int effective_element = element;
6466 int effective_action = action;
6467 int graphic = (direction == MV_NONE ?
6468 el_act2img(effective_element, effective_action) :
6469 el_act_dir2img(effective_element, effective_action,
6471 struct GraphicInfo *g = &graphic_info[graphic];
6472 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6478 Bitmap *debug_bitmap = g_em->bitmap;
6479 int debug_src_x = g_em->src_x;
6480 int debug_src_y = g_em->src_y;
6483 int frame = getAnimationFrame(g->anim_frames,
6486 g->anim_start_frame,
6489 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6491 g_em->bitmap = src_bitmap;
6492 g_em->src_x = src_x;
6493 g_em->src_y = src_y;
6494 g_em->src_offset_x = 0;
6495 g_em->src_offset_y = 0;
6496 g_em->dst_offset_x = 0;
6497 g_em->dst_offset_y = 0;
6498 g_em->width = TILEX;
6499 g_em->height = TILEY;
6503 /* skip check for EMC elements not contained in original EMC artwork */
6504 if (element == EL_PLAYER_3 ||
6505 element == EL_PLAYER_4)
6508 if (g_em->bitmap != debug_bitmap ||
6509 g_em->src_x != debug_src_x ||
6510 g_em->src_y != debug_src_y)
6512 static int last_i = -1;
6520 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6521 p, i, element, element_info[element].token_name,
6522 element_action_info[effective_action].suffix, direction);
6524 if (element != effective_element)
6525 printf(" [%d ('%s')]",
6527 element_info[effective_element].token_name);
6531 if (g_em->bitmap != debug_bitmap)
6532 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6533 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6535 if (g_em->src_x != debug_src_x ||
6536 g_em->src_y != debug_src_y)
6537 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6539 g_em->src_x, g_em->src_y,
6540 g_em->src_x / 32, g_em->src_y / 32,
6541 debug_src_x, debug_src_y,
6542 debug_src_x / 32, debug_src_y / 32);
6544 num_em_gfx_errors++;
6554 printf("::: [%d errors found]\n", num_em_gfx_errors);
6560 void PlayMenuSoundExt(int sound)
6562 if (sound == SND_UNDEFINED)
6565 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6566 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6569 if (IS_LOOP_SOUND(sound))
6570 PlaySoundLoop(sound);
6575 void PlayMenuSound()
6577 PlayMenuSoundExt(menu.sound[game_status]);
6580 void PlayMenuSoundStereo(int sound, int stereo_position)
6582 if (sound == SND_UNDEFINED)
6585 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6586 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6589 if (IS_LOOP_SOUND(sound))
6590 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6592 PlaySoundStereo(sound, stereo_position);
6595 void PlayMenuSoundIfLoopExt(int sound)
6597 if (sound == SND_UNDEFINED)
6600 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6601 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6604 if (IS_LOOP_SOUND(sound))
6605 PlaySoundLoop(sound);
6608 void PlayMenuSoundIfLoop()
6610 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6613 void PlayMenuMusicExt(int music)
6615 if (music == MUS_UNDEFINED)
6618 if (!setup.sound_music)
6624 void PlayMenuMusic()
6626 PlayMenuMusicExt(menu.music[game_status]);
6629 void PlaySoundActivating()
6632 PlaySound(SND_MENU_ITEM_ACTIVATING);
6636 void PlaySoundSelecting()
6639 PlaySound(SND_MENU_ITEM_SELECTING);
6643 void ToggleFullscreenIfNeeded()
6645 boolean change_fullscreen = (setup.fullscreen !=
6646 video.fullscreen_enabled);
6647 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6648 !strEqual(setup.fullscreen_mode,
6649 video.fullscreen_mode_current));
6651 if (!video.fullscreen_available)
6655 if (change_fullscreen || change_fullscreen_mode)
6657 if (setup.fullscreen != video.fullscreen_enabled ||
6658 setup.fullscreen_mode != video.fullscreen_mode_current)
6661 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6663 /* save backbuffer content which gets lost when toggling fullscreen mode */
6664 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6667 if (change_fullscreen_mode)
6669 if (setup.fullscreen && video.fullscreen_enabled)
6672 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6674 /* (this is now set in sdl.c) */
6676 video.fullscreen_mode_current = setup.fullscreen_mode;
6678 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6681 /* toggle fullscreen */
6682 ChangeVideoModeIfNeeded(setup.fullscreen);
6684 setup.fullscreen = video.fullscreen_enabled;
6686 /* restore backbuffer content from temporary backbuffer backup bitmap */
6687 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6689 FreeBitmap(tmp_backbuffer);
6692 /* update visible window/screen */
6693 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6695 redraw_mask = REDRAW_ALL;