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;
526 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
527 int x, y, width, height;
528 int fade_delay, post_delay;
530 redraw_mask |= fade_mask;
532 if (fade_mode & FADE_TYPE_SKIP)
534 fade_mode_skip = fade_mode;
539 if (fade_mode_skip & FADE_TYPE_SKIP)
542 printf("::: skipping %d ... [%d]\n", fade_mode, fade_mode_skip);
545 /* skip all fade operations until specified fade operation */
546 if (fade_mode & fade_mode_skip)
547 fade_mode_skip = FADE_MODE_NONE;
553 if (fading.fade_mode == FADE_MODE_NONE)
557 if (fade_mask & REDRAW_FIELD)
562 height = FULL_SYSIZE;
564 fade_delay = fading.fade_delay;
565 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
567 draw_border_function = DrawMaskedBorder_FIELD;
569 else /* REDRAW_ALL */
576 fade_delay = fading.fade_delay;
577 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
581 if (!setup.fade_screens || fade_delay == 0)
583 if (!setup.fade_screens || fade_delay == 0 || fading.anim_mode == ANIM_NONE)
586 if (fade_mode == FADE_MODE_FADE_OUT)
587 ClearRectangle(backbuffer, x, y, width, height);
594 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
595 draw_border_function);
597 redraw_mask &= ~fade_mask;
600 void FadeIn(int fade_mask)
603 if (fading.fade_mode == FADE_MODE_CROSSFADE)
604 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
606 FadeExt(fade_mask, FADE_MODE_FADE_IN);
608 FadeExt(fade_mask, FADE_MODE_FADE_IN);
612 void FadeOut(int fade_mask)
615 if (fading.fade_mode == FADE_MODE_CROSSFADE)
616 FadeCrossSaveBackbuffer();
618 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
620 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
624 void FadeCross(int fade_mask)
626 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
629 void FadeCrossSaveBackbuffer()
631 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
634 void FadeSetEnterMenu()
636 fading = menu.enter_menu;
639 void FadeSetLeaveMenu()
641 fading = menu.leave_menu;
644 void FadeSetStartItem()
646 fading = menu.start_item;
649 void FadeSetFromType(int type)
651 if (type & TYPE_ENTER_SCREEN)
653 else if (type & TYPE_ENTER)
655 else if (type & TYPE_LEAVE)
659 void FadeSetDisabled()
661 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
663 fading = fading_none;
666 void FadeSkipNextFadeIn()
668 FadeExt(0, FADE_MODE_SKIP_FADE_IN);
671 void FadeSkipNextFadeOut()
673 FadeExt(0, FADE_MODE_SKIP_FADE_OUT);
676 void SetWindowBackgroundImageIfDefined(int graphic)
678 if (graphic_info[graphic].bitmap)
679 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
682 void SetMainBackgroundImageIfDefined(int graphic)
684 if (graphic_info[graphic].bitmap)
685 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
688 void SetDoorBackgroundImageIfDefined(int graphic)
690 if (graphic_info[graphic].bitmap)
691 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
694 void SetWindowBackgroundImage(int graphic)
696 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
697 graphic_info[graphic].bitmap ?
698 graphic_info[graphic].bitmap :
699 graphic_info[IMG_BACKGROUND].bitmap);
702 void SetMainBackgroundImage(int graphic)
704 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
705 graphic_info[graphic].bitmap ?
706 graphic_info[graphic].bitmap :
707 graphic_info[IMG_BACKGROUND].bitmap);
710 void SetDoorBackgroundImage(int graphic)
712 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
713 graphic_info[graphic].bitmap ?
714 graphic_info[graphic].bitmap :
715 graphic_info[IMG_BACKGROUND].bitmap);
718 void SetPanelBackground()
720 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
721 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
723 SetDoorBackgroundBitmap(bitmap_db_panel);
726 void DrawBackground(int x, int y, int width, int height)
728 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
729 /* (when entering hall of fame after playing) */
731 ClearRectangleOnBackground(drawto, x, y, width, height);
733 ClearRectangleOnBackground(backbuffer, x, y, width, height);
736 redraw_mask |= REDRAW_FIELD;
739 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
741 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
743 if (font->bitmap == NULL)
746 DrawBackground(x, y, width, height);
749 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
751 struct GraphicInfo *g = &graphic_info[graphic];
753 if (g->bitmap == NULL)
756 DrawBackground(x, y, width, height);
761 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
762 /* (when entering hall of fame after playing) */
763 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
765 /* !!! maybe this should be done before clearing the background !!! */
766 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
768 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
769 SetDrawtoField(DRAW_BUFFERED);
772 SetDrawtoField(DRAW_BACKBUFFER);
774 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
776 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
777 SetDrawtoField(DRAW_DIRECT);
781 void MarkTileDirty(int x, int y)
783 int xx = redraw_x1 + x;
784 int yy = redraw_y1 + y;
789 redraw[xx][yy] = TRUE;
790 redraw_mask |= REDRAW_TILES;
793 void SetBorderElement()
797 BorderElement = EL_EMPTY;
799 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
801 for (x = 0; x < lev_fieldx; x++)
803 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
804 BorderElement = EL_STEELWALL;
806 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
812 void FloodFillLevel(int from_x, int from_y, int fill_element,
813 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
814 int max_fieldx, int max_fieldy)
818 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
819 static int safety = 0;
821 /* check if starting field still has the desired content */
822 if (field[from_x][from_y] == fill_element)
827 if (safety > max_fieldx * max_fieldy)
828 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
830 old_element = field[from_x][from_y];
831 field[from_x][from_y] = fill_element;
833 for (i = 0; i < 4; i++)
835 x = from_x + check[i][0];
836 y = from_y + check[i][1];
838 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
839 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
845 void SetRandomAnimationValue(int x, int y)
847 gfx.anim_random_frame = GfxRandom[x][y];
850 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
852 /* animation synchronized with global frame counter, not move position */
853 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
854 sync_frame = FrameCounter;
856 return getAnimationFrame(graphic_info[graphic].anim_frames,
857 graphic_info[graphic].anim_delay,
858 graphic_info[graphic].anim_mode,
859 graphic_info[graphic].anim_start_frame,
863 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
864 int *x, int *y, boolean get_backside)
866 struct GraphicInfo *g = &graphic_info[graphic];
867 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
868 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
872 if (g->offset_y == 0) /* frames are ordered horizontally */
874 int max_width = g->anim_frames_per_line * g->width;
875 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
877 *x = pos % max_width;
878 *y = src_y % g->height + pos / max_width * g->height;
880 else if (g->offset_x == 0) /* frames are ordered vertically */
882 int max_height = g->anim_frames_per_line * g->height;
883 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
885 *x = src_x % g->width + pos / max_height * g->width;
886 *y = pos % max_height;
888 else /* frames are ordered diagonally */
890 *x = src_x + frame * g->offset_x;
891 *y = src_y + frame * g->offset_y;
895 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
897 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
900 void DrawGraphic(int x, int y, int graphic, int frame)
903 if (!IN_SCR_FIELD(x, y))
905 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
906 printf("DrawGraphic(): This should never happen!\n");
911 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
915 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
921 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
922 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
925 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
928 if (!IN_SCR_FIELD(x, y))
930 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
931 printf("DrawGraphicThruMask(): This should never happen!\n");
936 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
941 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
947 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
949 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
950 dst_x - src_x, dst_y - src_y);
951 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
954 void DrawMiniGraphic(int x, int y, int graphic)
956 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
957 MarkTileDirty(x / 2, y / 2);
960 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
962 struct GraphicInfo *g = &graphic_info[graphic];
964 int mini_starty = g->bitmap->height * 2 / 3;
967 *x = mini_startx + g->src_x / 2;
968 *y = mini_starty + g->src_y / 2;
971 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
976 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
977 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
980 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
981 int graphic, int frame,
982 int cut_mode, int mask_mode)
987 int width = TILEX, height = TILEY;
990 if (dx || dy) /* shifted graphic */
992 if (x < BX1) /* object enters playfield from the left */
999 else if (x > BX2) /* object enters playfield from the right */
1005 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1011 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1013 else if (dx) /* general horizontal movement */
1014 MarkTileDirty(x + SIGN(dx), y);
1016 if (y < BY1) /* object enters playfield from the top */
1018 if (cut_mode==CUT_BELOW) /* object completely above top border */
1026 else if (y > BY2) /* object enters playfield from the bottom */
1032 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1038 else if (dy > 0 && cut_mode == CUT_ABOVE)
1040 if (y == BY2) /* object completely above bottom border */
1046 MarkTileDirty(x, y + 1);
1047 } /* object leaves playfield to the bottom */
1048 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1050 else if (dy) /* general vertical movement */
1051 MarkTileDirty(x, y + SIGN(dy));
1055 if (!IN_SCR_FIELD(x, y))
1057 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1058 printf("DrawGraphicShifted(): This should never happen!\n");
1063 if (width > 0 && height > 0)
1065 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1070 dst_x = FX + x * TILEX + dx;
1071 dst_y = FY + y * TILEY + dy;
1073 if (mask_mode == USE_MASKING)
1075 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1076 dst_x - src_x, dst_y - src_y);
1077 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1081 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1084 MarkTileDirty(x, y);
1088 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1089 int graphic, int frame,
1090 int cut_mode, int mask_mode)
1095 int width = TILEX, height = TILEY;
1098 int x2 = x + SIGN(dx);
1099 int y2 = y + SIGN(dy);
1100 int anim_frames = graphic_info[graphic].anim_frames;
1101 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1102 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1103 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1105 /* re-calculate animation frame for two-tile movement animation */
1106 frame = getGraphicAnimationFrame(graphic, sync_frame);
1108 /* check if movement start graphic inside screen area and should be drawn */
1109 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1111 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1113 dst_x = FX + x1 * TILEX;
1114 dst_y = FY + y1 * TILEY;
1116 if (mask_mode == USE_MASKING)
1118 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1119 dst_x - src_x, dst_y - src_y);
1120 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1124 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1127 MarkTileDirty(x1, y1);
1130 /* check if movement end graphic inside screen area and should be drawn */
1131 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1133 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1135 dst_x = FX + x2 * TILEX;
1136 dst_y = FY + y2 * TILEY;
1138 if (mask_mode == USE_MASKING)
1140 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1141 dst_x - src_x, dst_y - src_y);
1142 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1146 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1149 MarkTileDirty(x2, y2);
1153 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1154 int graphic, int frame,
1155 int cut_mode, int mask_mode)
1159 DrawGraphic(x, y, graphic, frame);
1164 if (graphic_info[graphic].double_movement) /* EM style movement images */
1165 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1167 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1170 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1171 int frame, int cut_mode)
1173 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1176 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1177 int cut_mode, int mask_mode)
1179 int lx = LEVELX(x), ly = LEVELY(y);
1183 if (IN_LEV_FIELD(lx, ly))
1185 SetRandomAnimationValue(lx, ly);
1187 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1188 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1190 /* do not use double (EM style) movement graphic when not moving */
1191 if (graphic_info[graphic].double_movement && !dx && !dy)
1193 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1194 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1197 else /* border element */
1199 graphic = el2img(element);
1200 frame = getGraphicAnimationFrame(graphic, -1);
1203 if (element == EL_EXPANDABLE_WALL)
1205 boolean left_stopped = FALSE, right_stopped = FALSE;
1207 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1208 left_stopped = TRUE;
1209 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1210 right_stopped = TRUE;
1212 if (left_stopped && right_stopped)
1214 else if (left_stopped)
1216 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1217 frame = graphic_info[graphic].anim_frames - 1;
1219 else if (right_stopped)
1221 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1222 frame = graphic_info[graphic].anim_frames - 1;
1227 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1228 else if (mask_mode == USE_MASKING)
1229 DrawGraphicThruMask(x, y, graphic, frame);
1231 DrawGraphic(x, y, graphic, frame);
1234 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1235 int cut_mode, int mask_mode)
1237 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1238 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1239 cut_mode, mask_mode);
1242 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1245 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1248 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1251 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1254 void DrawLevelElementThruMask(int x, int y, int element)
1256 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1259 void DrawLevelFieldThruMask(int x, int y)
1261 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1264 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1268 int sx = SCREENX(x), sy = SCREENY(y);
1270 int width, height, cx, cy, i;
1271 int crumbled_border_size = graphic_info[graphic].border_size;
1272 static int xy[4][2] =
1280 if (!IN_LEV_FIELD(x, y))
1283 element = TILE_GFX_ELEMENT(x, y);
1285 /* crumble field itself */
1286 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1288 if (!IN_SCR_FIELD(sx, sy))
1291 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1293 for (i = 0; i < 4; i++)
1295 int xx = x + xy[i][0];
1296 int yy = y + xy[i][1];
1298 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1301 /* check if neighbour field is of same type */
1302 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1305 if (i == 1 || i == 2)
1307 width = crumbled_border_size;
1309 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1315 height = crumbled_border_size;
1317 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1320 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1321 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1324 MarkTileDirty(sx, sy);
1326 else /* crumble neighbour fields */
1328 for (i = 0; i < 4; i++)
1330 int xx = x + xy[i][0];
1331 int yy = y + xy[i][1];
1332 int sxx = sx + xy[i][0];
1333 int syy = sy + xy[i][1];
1335 if (!IN_LEV_FIELD(xx, yy) ||
1336 !IN_SCR_FIELD(sxx, syy) ||
1340 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1343 element = TILE_GFX_ELEMENT(xx, yy);
1345 if (!GFX_CRUMBLED(element))
1348 graphic = el_act2crm(element, ACTION_DEFAULT);
1349 crumbled_border_size = graphic_info[graphic].border_size;
1351 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1353 if (i == 1 || i == 2)
1355 width = crumbled_border_size;
1357 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1363 height = crumbled_border_size;
1365 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1368 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1369 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1371 MarkTileDirty(sxx, syy);
1376 void DrawLevelFieldCrumbledSand(int x, int y)
1380 if (!IN_LEV_FIELD(x, y))
1384 /* !!! CHECK THIS !!! */
1387 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1388 GFX_CRUMBLED(GfxElement[x][y]))
1391 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1392 GfxElement[x][y] != EL_UNDEFINED &&
1393 GFX_CRUMBLED(GfxElement[x][y]))
1395 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1402 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1404 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1407 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1410 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1413 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1414 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1415 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1416 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1417 int sx = SCREENX(x), sy = SCREENY(y);
1419 DrawGraphic(sx, sy, graphic1, frame1);
1420 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1423 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1425 int sx = SCREENX(x), sy = SCREENY(y);
1426 static int xy[4][2] =
1435 for (i = 0; i < 4; i++)
1437 int xx = x + xy[i][0];
1438 int yy = y + xy[i][1];
1439 int sxx = sx + xy[i][0];
1440 int syy = sy + xy[i][1];
1442 if (!IN_LEV_FIELD(xx, yy) ||
1443 !IN_SCR_FIELD(sxx, syy) ||
1444 !GFX_CRUMBLED(Feld[xx][yy]) ||
1448 DrawLevelField(xx, yy);
1452 static int getBorderElement(int x, int y)
1456 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1457 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1458 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1459 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1460 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1461 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1462 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1464 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1465 int steel_position = (x == -1 && y == -1 ? 0 :
1466 x == lev_fieldx && y == -1 ? 1 :
1467 x == -1 && y == lev_fieldy ? 2 :
1468 x == lev_fieldx && y == lev_fieldy ? 3 :
1469 x == -1 || x == lev_fieldx ? 4 :
1470 y == -1 || y == lev_fieldy ? 5 : 6);
1472 return border[steel_position][steel_type];
1475 void DrawScreenElement(int x, int y, int element)
1477 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1478 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1481 void DrawLevelElement(int x, int y, int element)
1483 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1484 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1487 void DrawScreenField(int x, int y)
1489 int lx = LEVELX(x), ly = LEVELY(y);
1490 int element, content;
1492 if (!IN_LEV_FIELD(lx, ly))
1494 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1497 element = getBorderElement(lx, ly);
1499 DrawScreenElement(x, y, element);
1503 element = Feld[lx][ly];
1504 content = Store[lx][ly];
1506 if (IS_MOVING(lx, ly))
1508 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1509 boolean cut_mode = NO_CUTTING;
1511 if (element == EL_QUICKSAND_EMPTYING ||
1512 element == EL_QUICKSAND_FAST_EMPTYING ||
1513 element == EL_MAGIC_WALL_EMPTYING ||
1514 element == EL_BD_MAGIC_WALL_EMPTYING ||
1515 element == EL_DC_MAGIC_WALL_EMPTYING ||
1516 element == EL_AMOEBA_DROPPING)
1517 cut_mode = CUT_ABOVE;
1518 else if (element == EL_QUICKSAND_FILLING ||
1519 element == EL_QUICKSAND_FAST_FILLING ||
1520 element == EL_MAGIC_WALL_FILLING ||
1521 element == EL_BD_MAGIC_WALL_FILLING ||
1522 element == EL_DC_MAGIC_WALL_FILLING)
1523 cut_mode = CUT_BELOW;
1525 if (cut_mode == CUT_ABOVE)
1526 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1528 DrawScreenElement(x, y, EL_EMPTY);
1531 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1532 else if (cut_mode == NO_CUTTING)
1533 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1535 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1537 if (content == EL_ACID)
1539 int dir = MovDir[lx][ly];
1540 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1541 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1543 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1546 else if (IS_BLOCKED(lx, ly))
1551 boolean cut_mode = NO_CUTTING;
1552 int element_old, content_old;
1554 Blocked2Moving(lx, ly, &oldx, &oldy);
1557 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1558 MovDir[oldx][oldy] == MV_RIGHT);
1560 element_old = Feld[oldx][oldy];
1561 content_old = Store[oldx][oldy];
1563 if (element_old == EL_QUICKSAND_EMPTYING ||
1564 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1565 element_old == EL_MAGIC_WALL_EMPTYING ||
1566 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1567 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1568 element_old == EL_AMOEBA_DROPPING)
1569 cut_mode = CUT_ABOVE;
1571 DrawScreenElement(x, y, EL_EMPTY);
1574 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1576 else if (cut_mode == NO_CUTTING)
1577 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1580 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1583 else if (IS_DRAWABLE(element))
1584 DrawScreenElement(x, y, element);
1586 DrawScreenElement(x, y, EL_EMPTY);
1589 void DrawLevelField(int x, int y)
1591 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1592 DrawScreenField(SCREENX(x), SCREENY(y));
1593 else if (IS_MOVING(x, y))
1597 Moving2Blocked(x, y, &newx, &newy);
1598 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1599 DrawScreenField(SCREENX(newx), SCREENY(newy));
1601 else if (IS_BLOCKED(x, y))
1605 Blocked2Moving(x, y, &oldx, &oldy);
1606 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1607 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1611 void DrawMiniElement(int x, int y, int element)
1615 graphic = el2edimg(element);
1616 DrawMiniGraphic(x, y, graphic);
1619 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1621 int x = sx + scroll_x, y = sy + scroll_y;
1623 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1624 DrawMiniElement(sx, sy, EL_EMPTY);
1625 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1626 DrawMiniElement(sx, sy, Feld[x][y]);
1628 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1631 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1632 int x, int y, int xsize, int ysize, int font_nr)
1634 int font_width = getFontWidth(font_nr);
1635 int font_height = getFontHeight(font_nr);
1636 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1639 int dst_x = SX + startx + x * font_width;
1640 int dst_y = SY + starty + y * font_height;
1641 int width = graphic_info[graphic].width;
1642 int height = graphic_info[graphic].height;
1643 int inner_width = MAX(width - 2 * font_width, font_width);
1644 int inner_height = MAX(height - 2 * font_height, font_height);
1645 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1646 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1647 boolean draw_masked = graphic_info[graphic].draw_masked;
1649 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1651 if (src_bitmap == NULL || width < font_width || height < font_height)
1653 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1657 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1658 inner_sx + (x - 1) * font_width % inner_width);
1659 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1660 inner_sy + (y - 1) * font_height % inner_height);
1664 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1665 dst_x - src_x, dst_y - src_y);
1666 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1670 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1674 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1676 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1677 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1678 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1679 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1680 boolean no_delay = (tape.warp_forward);
1681 unsigned long anim_delay = 0;
1682 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1683 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1684 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1685 int font_width = getFontWidth(font_nr);
1686 int font_height = getFontHeight(font_nr);
1687 int max_xsize = level.envelope[envelope_nr].xsize;
1688 int max_ysize = level.envelope[envelope_nr].ysize;
1689 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1690 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1691 int xend = max_xsize;
1692 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1693 int xstep = (xstart < xend ? 1 : 0);
1694 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1697 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1699 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1700 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1701 int sx = (SXSIZE - xsize * font_width) / 2;
1702 int sy = (SYSIZE - ysize * font_height) / 2;
1705 SetDrawtoField(DRAW_BUFFERED);
1707 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1709 SetDrawtoField(DRAW_BACKBUFFER);
1711 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1712 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1715 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1716 level.envelope[envelope_nr].text, font_nr, max_xsize,
1717 xsize - 2, ysize - 2, mask_mode,
1718 level.envelope[envelope_nr].autowrap,
1719 level.envelope[envelope_nr].centered, FALSE);
1721 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1722 level.envelope[envelope_nr].text, font_nr, max_xsize,
1723 xsize - 2, ysize - 2, mask_mode);
1726 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1729 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1733 void ShowEnvelope(int envelope_nr)
1735 int element = EL_ENVELOPE_1 + envelope_nr;
1736 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1737 int sound_opening = element_info[element].sound[ACTION_OPENING];
1738 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1739 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1740 boolean no_delay = (tape.warp_forward);
1741 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1742 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1743 int anim_mode = graphic_info[graphic].anim_mode;
1744 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1745 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1747 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1749 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1751 if (anim_mode == ANIM_DEFAULT)
1752 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1754 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1757 Delay(wait_delay_value);
1759 WaitForEventToContinue();
1761 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1763 if (anim_mode != ANIM_NONE)
1764 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1766 if (anim_mode == ANIM_DEFAULT)
1767 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1769 game.envelope_active = FALSE;
1771 SetDrawtoField(DRAW_BUFFERED);
1773 redraw_mask |= REDRAW_FIELD;
1777 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1782 int width_mult, width_div;
1783 int height_mult, height_div;
1791 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1792 5 - log_2(tilesize));
1793 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1794 int width_mult = offset_calc[offset_calc_pos].width_mult;
1795 int width_div = offset_calc[offset_calc_pos].width_div;
1796 int height_mult = offset_calc[offset_calc_pos].height_mult;
1797 int height_div = offset_calc[offset_calc_pos].height_div;
1798 int mini_startx = src_bitmap->width * width_mult / width_div;
1799 int mini_starty = src_bitmap->height * height_mult / height_div;
1800 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1801 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1803 *bitmap = src_bitmap;
1808 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1812 int graphic = el2preimg(element);
1814 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1815 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1822 SetDrawBackgroundMask(REDRAW_NONE);
1825 for (x = BX1; x <= BX2; x++)
1826 for (y = BY1; y <= BY2; y++)
1827 DrawScreenField(x, y);
1829 redraw_mask |= REDRAW_FIELD;
1832 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1836 for (x = 0; x < size_x; x++)
1837 for (y = 0; y < size_y; y++)
1838 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1840 redraw_mask |= REDRAW_FIELD;
1843 static void DrawPreviewLevelExt(int from_x, int from_y)
1845 boolean show_level_border = (BorderElement != EL_EMPTY);
1846 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1847 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1848 int tile_size = preview.tile_size;
1849 int preview_width = preview.xsize * tile_size;
1850 int preview_height = preview.ysize * tile_size;
1851 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1852 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1853 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1854 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1857 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1859 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1860 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1862 for (x = 0; x < real_preview_xsize; x++)
1864 for (y = 0; y < real_preview_ysize; y++)
1866 int lx = from_x + x + (show_level_border ? -1 : 0);
1867 int ly = from_y + y + (show_level_border ? -1 : 0);
1868 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1869 getBorderElement(lx, ly));
1871 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1872 element, tile_size);
1876 redraw_mask |= REDRAW_MICROLEVEL;
1879 #define MICROLABEL_EMPTY 0
1880 #define MICROLABEL_LEVEL_NAME 1
1881 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1882 #define MICROLABEL_LEVEL_AUTHOR 3
1883 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1884 #define MICROLABEL_IMPORTED_FROM 5
1885 #define MICROLABEL_IMPORTED_BY_HEAD 6
1886 #define MICROLABEL_IMPORTED_BY 7
1888 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
1890 int max_text_width = SXSIZE;
1891 int font_width = getFontWidth(font_nr);
1893 if (pos->align == ALIGN_CENTER)
1894 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1895 else if (pos->align == ALIGN_RIGHT)
1896 max_text_width = pos->x;
1898 max_text_width = SXSIZE - pos->x;
1900 return max_text_width / font_width;
1903 static void DrawPreviewLevelLabelExt(int mode)
1905 struct TextPosInfo *pos = &menu.main.text.level_info_2;
1906 char label_text[MAX_OUTPUT_LINESIZE + 1];
1907 int max_len_label_text;
1909 int font_nr = pos->font;
1912 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1913 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1914 mode == MICROLABEL_IMPORTED_BY_HEAD)
1915 font_nr = pos->font_alt;
1917 int font_nr = FONT_TEXT_2;
1920 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1921 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1922 mode == MICROLABEL_IMPORTED_BY_HEAD)
1923 font_nr = FONT_TEXT_3;
1927 max_len_label_text = getMaxTextLength(pos, font_nr);
1929 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1933 if (pos->chars != -1)
1934 max_len_label_text = pos->chars;
1937 for (i = 0; i < max_len_label_text; i++)
1938 label_text[i] = ' ';
1939 label_text[max_len_label_text] = '\0';
1941 if (strlen(label_text) > 0)
1944 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1946 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1947 int lypos = MICROLABEL2_YPOS;
1949 DrawText(lxpos, lypos, label_text, font_nr);
1954 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1955 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1956 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1957 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1958 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1959 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1960 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1961 max_len_label_text);
1962 label_text[max_len_label_text] = '\0';
1964 if (strlen(label_text) > 0)
1967 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1969 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1970 int lypos = MICROLABEL2_YPOS;
1972 DrawText(lxpos, lypos, label_text, font_nr);
1976 redraw_mask |= REDRAW_MICROLEVEL;
1979 void DrawPreviewLevel(boolean restart)
1981 static unsigned long scroll_delay = 0;
1982 static unsigned long label_delay = 0;
1983 static int from_x, from_y, scroll_direction;
1984 static int label_state, label_counter;
1985 unsigned long scroll_delay_value = preview.step_delay;
1986 boolean show_level_border = (BorderElement != EL_EMPTY);
1987 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1988 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1989 int last_game_status = game_status; /* save current game status */
1992 /* force PREVIEW font on preview level */
1993 game_status = GAME_MODE_PSEUDO_PREVIEW;
2001 if (preview.anim_mode == ANIM_CENTERED)
2003 if (level_xsize > preview.xsize)
2004 from_x = (level_xsize - preview.xsize) / 2;
2005 if (level_ysize > preview.ysize)
2006 from_y = (level_ysize - preview.ysize) / 2;
2009 from_x += preview.xoffset;
2010 from_y += preview.yoffset;
2012 scroll_direction = MV_RIGHT;
2016 DrawPreviewLevelExt(from_x, from_y);
2017 DrawPreviewLevelLabelExt(label_state);
2019 /* initialize delay counters */
2020 DelayReached(&scroll_delay, 0);
2021 DelayReached(&label_delay, 0);
2023 if (leveldir_current->name)
2025 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2026 char label_text[MAX_OUTPUT_LINESIZE + 1];
2028 int font_nr = pos->font;
2030 int font_nr = FONT_TEXT_1;
2033 int max_len_label_text = getMaxTextLength(pos, font_nr);
2035 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2043 if (pos->chars != -1)
2044 max_len_label_text = pos->chars;
2047 strncpy(label_text, leveldir_current->name, max_len_label_text);
2048 label_text[max_len_label_text] = '\0';
2051 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2053 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2054 lypos = SY + MICROLABEL1_YPOS;
2056 DrawText(lxpos, lypos, label_text, font_nr);
2060 game_status = last_game_status; /* restore current game status */
2065 /* scroll preview level, if needed */
2066 if (preview.anim_mode != ANIM_NONE &&
2067 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2068 DelayReached(&scroll_delay, scroll_delay_value))
2070 switch (scroll_direction)
2075 from_x -= preview.step_offset;
2076 from_x = (from_x < 0 ? 0 : from_x);
2079 scroll_direction = MV_UP;
2083 if (from_x < level_xsize - preview.xsize)
2085 from_x += preview.step_offset;
2086 from_x = (from_x > level_xsize - preview.xsize ?
2087 level_xsize - preview.xsize : from_x);
2090 scroll_direction = MV_DOWN;
2096 from_y -= preview.step_offset;
2097 from_y = (from_y < 0 ? 0 : from_y);
2100 scroll_direction = MV_RIGHT;
2104 if (from_y < level_ysize - preview.ysize)
2106 from_y += preview.step_offset;
2107 from_y = (from_y > level_ysize - preview.ysize ?
2108 level_ysize - preview.ysize : from_y);
2111 scroll_direction = MV_LEFT;
2118 DrawPreviewLevelExt(from_x, from_y);
2121 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2122 /* redraw micro level label, if needed */
2123 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2124 !strEqual(level.author, ANONYMOUS_NAME) &&
2125 !strEqual(level.author, leveldir_current->name) &&
2126 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2128 int max_label_counter = 23;
2130 if (leveldir_current->imported_from != NULL &&
2131 strlen(leveldir_current->imported_from) > 0)
2132 max_label_counter += 14;
2133 if (leveldir_current->imported_by != NULL &&
2134 strlen(leveldir_current->imported_by) > 0)
2135 max_label_counter += 14;
2137 label_counter = (label_counter + 1) % max_label_counter;
2138 label_state = (label_counter >= 0 && label_counter <= 7 ?
2139 MICROLABEL_LEVEL_NAME :
2140 label_counter >= 9 && label_counter <= 12 ?
2141 MICROLABEL_LEVEL_AUTHOR_HEAD :
2142 label_counter >= 14 && label_counter <= 21 ?
2143 MICROLABEL_LEVEL_AUTHOR :
2144 label_counter >= 23 && label_counter <= 26 ?
2145 MICROLABEL_IMPORTED_FROM_HEAD :
2146 label_counter >= 28 && label_counter <= 35 ?
2147 MICROLABEL_IMPORTED_FROM :
2148 label_counter >= 37 && label_counter <= 40 ?
2149 MICROLABEL_IMPORTED_BY_HEAD :
2150 label_counter >= 42 && label_counter <= 49 ?
2151 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2153 if (leveldir_current->imported_from == NULL &&
2154 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2155 label_state == MICROLABEL_IMPORTED_FROM))
2156 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2157 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2159 DrawPreviewLevelLabelExt(label_state);
2162 game_status = last_game_status; /* restore current game status */
2165 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2166 int graphic, int sync_frame, int mask_mode)
2168 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2170 if (mask_mode == USE_MASKING)
2171 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2173 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2176 inline void DrawGraphicAnimation(int x, int y, int graphic)
2178 int lx = LEVELX(x), ly = LEVELY(y);
2180 if (!IN_SCR_FIELD(x, y))
2183 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2184 graphic, GfxFrame[lx][ly], NO_MASKING);
2185 MarkTileDirty(x, y);
2188 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2190 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2193 void DrawLevelElementAnimation(int x, int y, int element)
2195 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2197 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2200 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2202 int sx = SCREENX(x), sy = SCREENY(y);
2204 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2207 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2210 DrawGraphicAnimation(sx, sy, graphic);
2213 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2214 DrawLevelFieldCrumbledSand(x, y);
2216 if (GFX_CRUMBLED(Feld[x][y]))
2217 DrawLevelFieldCrumbledSand(x, y);
2221 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2223 int sx = SCREENX(x), sy = SCREENY(y);
2226 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2229 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2231 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2234 DrawGraphicAnimation(sx, sy, graphic);
2236 if (GFX_CRUMBLED(element))
2237 DrawLevelFieldCrumbledSand(x, y);
2240 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2242 if (player->use_murphy)
2244 /* this works only because currently only one player can be "murphy" ... */
2245 static int last_horizontal_dir = MV_LEFT;
2246 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2248 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2249 last_horizontal_dir = move_dir;
2251 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2253 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2255 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2261 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2264 static boolean equalGraphics(int graphic1, int graphic2)
2266 struct GraphicInfo *g1 = &graphic_info[graphic1];
2267 struct GraphicInfo *g2 = &graphic_info[graphic2];
2269 return (g1->bitmap == g2->bitmap &&
2270 g1->src_x == g2->src_x &&
2271 g1->src_y == g2->src_y &&
2272 g1->anim_frames == g2->anim_frames &&
2273 g1->anim_delay == g2->anim_delay &&
2274 g1->anim_mode == g2->anim_mode);
2277 void DrawAllPlayers()
2281 for (i = 0; i < MAX_PLAYERS; i++)
2282 if (stored_player[i].active)
2283 DrawPlayer(&stored_player[i]);
2286 void DrawPlayerField(int x, int y)
2288 if (!IS_PLAYER(x, y))
2291 DrawPlayer(PLAYERINFO(x, y));
2294 void DrawPlayer(struct PlayerInfo *player)
2296 int jx = player->jx;
2297 int jy = player->jy;
2298 int move_dir = player->MovDir;
2299 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2300 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2301 int last_jx = (player->is_moving ? jx - dx : jx);
2302 int last_jy = (player->is_moving ? jy - dy : jy);
2303 int next_jx = jx + dx;
2304 int next_jy = jy + dy;
2305 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2306 boolean player_is_opaque = FALSE;
2307 int sx = SCREENX(jx), sy = SCREENY(jy);
2308 int sxx = 0, syy = 0;
2309 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2311 int action = ACTION_DEFAULT;
2312 int last_player_graphic = getPlayerGraphic(player, move_dir);
2313 int last_player_frame = player->Frame;
2316 /* GfxElement[][] is set to the element the player is digging or collecting;
2317 remove also for off-screen player if the player is not moving anymore */
2318 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2319 GfxElement[jx][jy] = EL_UNDEFINED;
2321 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2325 if (!IN_LEV_FIELD(jx, jy))
2327 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2328 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2329 printf("DrawPlayerField(): This should never happen!\n");
2334 if (element == EL_EXPLOSION)
2337 action = (player->is_pushing ? ACTION_PUSHING :
2338 player->is_digging ? ACTION_DIGGING :
2339 player->is_collecting ? ACTION_COLLECTING :
2340 player->is_moving ? ACTION_MOVING :
2341 player->is_snapping ? ACTION_SNAPPING :
2342 player->is_dropping ? ACTION_DROPPING :
2343 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2345 if (player->is_waiting)
2346 move_dir = player->dir_waiting;
2348 InitPlayerGfxAnimation(player, action, move_dir);
2350 /* ----------------------------------------------------------------------- */
2351 /* draw things in the field the player is leaving, if needed */
2352 /* ----------------------------------------------------------------------- */
2354 if (player->is_moving)
2356 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2358 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2360 if (last_element == EL_DYNAMITE_ACTIVE ||
2361 last_element == EL_EM_DYNAMITE_ACTIVE ||
2362 last_element == EL_SP_DISK_RED_ACTIVE)
2363 DrawDynamite(last_jx, last_jy);
2365 DrawLevelFieldThruMask(last_jx, last_jy);
2367 else if (last_element == EL_DYNAMITE_ACTIVE ||
2368 last_element == EL_EM_DYNAMITE_ACTIVE ||
2369 last_element == EL_SP_DISK_RED_ACTIVE)
2370 DrawDynamite(last_jx, last_jy);
2372 /* !!! this is not enough to prevent flickering of players which are
2373 moving next to each others without a free tile between them -- this
2374 can only be solved by drawing all players layer by layer (first the
2375 background, then the foreground etc.) !!! => TODO */
2376 else if (!IS_PLAYER(last_jx, last_jy))
2377 DrawLevelField(last_jx, last_jy);
2380 DrawLevelField(last_jx, last_jy);
2383 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2384 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2387 if (!IN_SCR_FIELD(sx, sy))
2390 if (setup.direct_draw)
2391 SetDrawtoField(DRAW_BUFFERED);
2393 /* ----------------------------------------------------------------------- */
2394 /* draw things behind the player, if needed */
2395 /* ----------------------------------------------------------------------- */
2398 DrawLevelElement(jx, jy, Back[jx][jy]);
2399 else if (IS_ACTIVE_BOMB(element))
2400 DrawLevelElement(jx, jy, EL_EMPTY);
2403 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2405 int old_element = GfxElement[jx][jy];
2406 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2407 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2409 if (GFX_CRUMBLED(old_element))
2410 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2412 DrawGraphic(sx, sy, old_graphic, frame);
2414 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2415 player_is_opaque = TRUE;
2419 GfxElement[jx][jy] = EL_UNDEFINED;
2421 /* make sure that pushed elements are drawn with correct frame rate */
2423 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2425 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2426 GfxFrame[jx][jy] = player->StepFrame;
2428 if (player->is_pushing && player->is_moving)
2429 GfxFrame[jx][jy] = player->StepFrame;
2432 DrawLevelField(jx, jy);
2436 /* ----------------------------------------------------------------------- */
2437 /* draw player himself */
2438 /* ----------------------------------------------------------------------- */
2440 graphic = getPlayerGraphic(player, move_dir);
2442 /* in the case of changed player action or direction, prevent the current
2443 animation frame from being restarted for identical animations */
2444 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2445 player->Frame = last_player_frame;
2447 frame = getGraphicAnimationFrame(graphic, player->Frame);
2451 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2452 sxx = player->GfxPos;
2454 syy = player->GfxPos;
2457 if (!setup.soft_scrolling && ScreenMovPos)
2460 if (player_is_opaque)
2461 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2463 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2465 if (SHIELD_ON(player))
2467 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2468 IMG_SHIELD_NORMAL_ACTIVE);
2469 int frame = getGraphicAnimationFrame(graphic, -1);
2471 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2474 /* ----------------------------------------------------------------------- */
2475 /* draw things the player is pushing, if needed */
2476 /* ----------------------------------------------------------------------- */
2479 printf("::: %d, %d [%d, %d] [%d]\n",
2480 player->is_pushing, player_is_moving, player->GfxAction,
2481 player->is_moving, player_is_moving);
2485 if (player->is_pushing && player->is_moving)
2487 int px = SCREENX(jx), py = SCREENY(jy);
2488 int pxx = (TILEX - ABS(sxx)) * dx;
2489 int pyy = (TILEY - ABS(syy)) * dy;
2490 int gfx_frame = GfxFrame[jx][jy];
2496 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2498 element = Feld[next_jx][next_jy];
2499 gfx_frame = GfxFrame[next_jx][next_jy];
2502 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2505 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2506 frame = getGraphicAnimationFrame(graphic, sync_frame);
2508 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2511 /* draw background element under pushed element (like the Sokoban field) */
2512 if (Back[next_jx][next_jy])
2513 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2515 /* masked drawing is needed for EMC style (double) movement graphics */
2516 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2520 /* ----------------------------------------------------------------------- */
2521 /* draw things in front of player (active dynamite or dynabombs) */
2522 /* ----------------------------------------------------------------------- */
2524 if (IS_ACTIVE_BOMB(element))
2526 graphic = el2img(element);
2527 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2529 if (game.emulation == EMU_SUPAPLEX)
2530 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2532 DrawGraphicThruMask(sx, sy, graphic, frame);
2535 if (player_is_moving && last_element == EL_EXPLOSION)
2537 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2538 GfxElement[last_jx][last_jy] : EL_EMPTY);
2539 int graphic = el_act2img(element, ACTION_EXPLODING);
2540 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2541 int phase = ExplodePhase[last_jx][last_jy] - 1;
2542 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2545 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2548 /* ----------------------------------------------------------------------- */
2549 /* draw elements the player is just walking/passing through/under */
2550 /* ----------------------------------------------------------------------- */
2552 if (player_is_moving)
2554 /* handle the field the player is leaving ... */
2555 if (IS_ACCESSIBLE_INSIDE(last_element))
2556 DrawLevelField(last_jx, last_jy);
2557 else if (IS_ACCESSIBLE_UNDER(last_element))
2558 DrawLevelFieldThruMask(last_jx, last_jy);
2561 /* do not redraw accessible elements if the player is just pushing them */
2562 if (!player_is_moving || !player->is_pushing)
2564 /* ... and the field the player is entering */
2565 if (IS_ACCESSIBLE_INSIDE(element))
2566 DrawLevelField(jx, jy);
2567 else if (IS_ACCESSIBLE_UNDER(element))
2568 DrawLevelFieldThruMask(jx, jy);
2571 if (setup.direct_draw)
2573 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2574 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2575 int x_size = TILEX * (1 + ABS(jx - last_jx));
2576 int y_size = TILEY * (1 + ABS(jy - last_jy));
2578 BlitBitmap(drawto_field, window,
2579 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2580 SetDrawtoField(DRAW_DIRECT);
2583 MarkTileDirty(sx, sy);
2586 /* ------------------------------------------------------------------------- */
2588 void WaitForEventToContinue()
2590 boolean still_wait = TRUE;
2592 /* simulate releasing mouse button over last gadget, if still pressed */
2594 HandleGadgets(-1, -1, 0);
2596 button_status = MB_RELEASED;
2612 case EVENT_BUTTONPRESS:
2613 case EVENT_KEYPRESS:
2617 case EVENT_KEYRELEASE:
2618 ClearPlayerAction();
2622 HandleOtherEvents(&event);
2626 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2633 /* don't eat all CPU time */
2638 #define MAX_REQUEST_LINES 13
2639 #define MAX_REQUEST_LINE_FONT1_LEN 7
2640 #define MAX_REQUEST_LINE_FONT2_LEN 10
2642 boolean Request(char *text, unsigned int req_state)
2644 int mx, my, ty, result = -1;
2645 unsigned int old_door_state;
2646 int last_game_status = game_status; /* save current game status */
2647 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2648 int font_nr = FONT_TEXT_2;
2649 int max_word_len = 0;
2652 for (text_ptr = text; *text_ptr; text_ptr++)
2654 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2656 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2658 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2660 font_nr = FONT_TEXT_1;
2662 font_nr = FONT_LEVEL_NUMBER;
2669 if (game_status == GAME_MODE_PLAYING &&
2670 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2671 BlitScreenToBitmap_EM(backbuffer);
2673 /* disable deactivated drawing when quick-loading level tape recording */
2674 if (tape.playing && tape.deactivate_display)
2675 TapeDeactivateDisplayOff(TRUE);
2677 SetMouseCursor(CURSOR_DEFAULT);
2679 #if defined(NETWORK_AVALIABLE)
2680 /* pause network game while waiting for request to answer */
2681 if (options.network &&
2682 game_status == GAME_MODE_PLAYING &&
2683 req_state & REQUEST_WAIT_FOR_INPUT)
2684 SendToServer_PausePlaying();
2687 old_door_state = GetDoorState();
2689 /* simulate releasing mouse button over last gadget, if still pressed */
2691 HandleGadgets(-1, -1, 0);
2695 if (old_door_state & DOOR_OPEN_1)
2697 CloseDoor(DOOR_CLOSE_1);
2699 /* save old door content */
2700 BlitBitmap(bitmap_db_door, bitmap_db_door,
2701 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2702 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2706 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2709 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2711 /* clear door drawing field */
2712 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2714 /* force DOOR font inside door area */
2715 game_status = GAME_MODE_PSEUDO_DOOR;
2717 /* write text for request */
2718 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2720 char text_line[max_request_line_len + 1];
2726 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2729 if (!tc || tc == ' ')
2740 strncpy(text_line, text, tl);
2743 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2744 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2745 text_line, font_nr);
2747 text += tl + (tc == ' ' ? 1 : 0);
2750 game_status = last_game_status; /* restore current game status */
2752 if (req_state & REQ_ASK)
2754 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2755 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2757 else if (req_state & REQ_CONFIRM)
2759 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2761 else if (req_state & REQ_PLAYER)
2763 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2764 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2765 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2766 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2769 /* copy request gadgets to door backbuffer */
2770 BlitBitmap(drawto, bitmap_db_door,
2771 DX, DY, DXSIZE, DYSIZE,
2772 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2774 OpenDoor(DOOR_OPEN_1);
2776 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2778 if (game_status == GAME_MODE_PLAYING)
2780 SetPanelBackground();
2781 SetDrawBackgroundMask(REDRAW_DOOR_1);
2785 SetDrawBackgroundMask(REDRAW_FIELD);
2791 if (game_status != GAME_MODE_MAIN)
2794 button_status = MB_RELEASED;
2796 request_gadget_id = -1;
2798 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2810 case EVENT_BUTTONPRESS:
2811 case EVENT_BUTTONRELEASE:
2812 case EVENT_MOTIONNOTIFY:
2814 if (event.type == EVENT_MOTIONNOTIFY)
2816 if (!PointerInWindow(window))
2817 continue; /* window and pointer are on different screens */
2822 motion_status = TRUE;
2823 mx = ((MotionEvent *) &event)->x;
2824 my = ((MotionEvent *) &event)->y;
2828 motion_status = FALSE;
2829 mx = ((ButtonEvent *) &event)->x;
2830 my = ((ButtonEvent *) &event)->y;
2831 if (event.type == EVENT_BUTTONPRESS)
2832 button_status = ((ButtonEvent *) &event)->button;
2834 button_status = MB_RELEASED;
2837 /* this sets 'request_gadget_id' */
2838 HandleGadgets(mx, my, button_status);
2840 switch (request_gadget_id)
2842 case TOOL_CTRL_ID_YES:
2845 case TOOL_CTRL_ID_NO:
2848 case TOOL_CTRL_ID_CONFIRM:
2849 result = TRUE | FALSE;
2852 case TOOL_CTRL_ID_PLAYER_1:
2855 case TOOL_CTRL_ID_PLAYER_2:
2858 case TOOL_CTRL_ID_PLAYER_3:
2861 case TOOL_CTRL_ID_PLAYER_4:
2872 case EVENT_KEYPRESS:
2873 switch (GetEventKey((KeyEvent *)&event, TRUE))
2886 if (req_state & REQ_PLAYER)
2890 case EVENT_KEYRELEASE:
2891 ClearPlayerAction();
2895 HandleOtherEvents(&event);
2899 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2901 int joy = AnyJoystick();
2903 if (joy & JOY_BUTTON_1)
2905 else if (joy & JOY_BUTTON_2)
2911 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2913 HandleGameActions();
2920 if (!PendingEvent()) /* delay only if no pending events */
2929 if (!PendingEvent()) /* delay only if no pending events */
2932 /* don't eat all CPU time */
2939 if (game_status != GAME_MODE_MAIN)
2944 if (!(req_state & REQ_STAY_OPEN))
2946 CloseDoor(DOOR_CLOSE_1);
2948 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2949 (req_state & REQ_REOPEN))
2950 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2955 if (game_status == GAME_MODE_PLAYING)
2957 SetPanelBackground();
2958 SetDrawBackgroundMask(REDRAW_DOOR_1);
2962 SetDrawBackgroundMask(REDRAW_FIELD);
2965 #if defined(NETWORK_AVALIABLE)
2966 /* continue network game after request */
2967 if (options.network &&
2968 game_status == GAME_MODE_PLAYING &&
2969 req_state & REQUEST_WAIT_FOR_INPUT)
2970 SendToServer_ContinuePlaying();
2973 /* restore deactivated drawing when quick-loading level tape recording */
2974 if (tape.playing && tape.deactivate_display)
2975 TapeDeactivateDisplayOn();
2980 unsigned int OpenDoor(unsigned int door_state)
2982 if (door_state & DOOR_COPY_BACK)
2984 if (door_state & DOOR_OPEN_1)
2985 BlitBitmap(bitmap_db_door, bitmap_db_door,
2986 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2987 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2989 if (door_state & DOOR_OPEN_2)
2990 BlitBitmap(bitmap_db_door, bitmap_db_door,
2991 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2992 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2994 door_state &= ~DOOR_COPY_BACK;
2997 return MoveDoor(door_state);
3000 unsigned int CloseDoor(unsigned int door_state)
3002 unsigned int old_door_state = GetDoorState();
3004 if (!(door_state & DOOR_NO_COPY_BACK))
3006 if (old_door_state & DOOR_OPEN_1)
3007 BlitBitmap(backbuffer, bitmap_db_door,
3008 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3010 if (old_door_state & DOOR_OPEN_2)
3011 BlitBitmap(backbuffer, bitmap_db_door,
3012 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3014 door_state &= ~DOOR_NO_COPY_BACK;
3017 return MoveDoor(door_state);
3020 unsigned int GetDoorState()
3022 return MoveDoor(DOOR_GET_STATE);
3025 unsigned int SetDoorState(unsigned int door_state)
3027 return MoveDoor(door_state | DOOR_SET_STATE);
3030 unsigned int MoveDoor(unsigned int door_state)
3032 static int door1 = DOOR_OPEN_1;
3033 static int door2 = DOOR_CLOSE_2;
3034 unsigned long door_delay = 0;
3035 unsigned long door_delay_value;
3038 if (door_1.width < 0 || door_1.width > DXSIZE)
3039 door_1.width = DXSIZE;
3040 if (door_1.height < 0 || door_1.height > DYSIZE)
3041 door_1.height = DYSIZE;
3042 if (door_2.width < 0 || door_2.width > VXSIZE)
3043 door_2.width = VXSIZE;
3044 if (door_2.height < 0 || door_2.height > VYSIZE)
3045 door_2.height = VYSIZE;
3047 if (door_state == DOOR_GET_STATE)
3048 return (door1 | door2);
3050 if (door_state & DOOR_SET_STATE)
3052 if (door_state & DOOR_ACTION_1)
3053 door1 = door_state & DOOR_ACTION_1;
3054 if (door_state & DOOR_ACTION_2)
3055 door2 = door_state & DOOR_ACTION_2;
3057 return (door1 | door2);
3060 if (!(door_state & DOOR_FORCE_REDRAW))
3062 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3063 door_state &= ~DOOR_OPEN_1;
3064 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3065 door_state &= ~DOOR_CLOSE_1;
3066 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3067 door_state &= ~DOOR_OPEN_2;
3068 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3069 door_state &= ~DOOR_CLOSE_2;
3072 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3075 if (setup.quick_doors)
3077 stepsize = 20; /* must be chosen to always draw last frame */
3078 door_delay_value = 0;
3081 if (global.autoplay_leveldir)
3083 door_state |= DOOR_NO_DELAY;
3084 door_state &= ~DOOR_CLOSE_ALL;
3087 if (door_state & DOOR_ACTION)
3089 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3090 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3091 boolean door_1_done = (!handle_door_1);
3092 boolean door_2_done = (!handle_door_2);
3093 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3094 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3095 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3096 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3097 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3098 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3099 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3100 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3101 int door_skip = max_door_size - door_size;
3102 int end = door_size;
3103 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3106 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3108 /* opening door sound has priority over simultaneously closing door */
3109 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3110 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3111 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3112 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3115 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3118 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3119 GC gc = bitmap->stored_clip_gc;
3121 if (door_state & DOOR_ACTION_1)
3123 int a = MIN(x * door_1.step_offset, end);
3124 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3125 int i = p + door_skip;
3127 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3129 BlitBitmap(bitmap_db_door, drawto,
3130 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3131 DXSIZE, DYSIZE, DX, DY);
3135 BlitBitmap(bitmap_db_door, drawto,
3136 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3137 DXSIZE, DYSIZE - p / 2, DX, DY);
3139 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3142 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3144 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3145 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3146 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3147 int dst2_x = DX, dst2_y = DY;
3148 int width = i, height = DYSIZE;
3150 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3151 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3154 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3155 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3158 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3160 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3161 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3162 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3163 int dst2_x = DX, dst2_y = DY;
3164 int width = DXSIZE, height = i;
3166 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3167 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3170 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3171 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3174 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3176 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3178 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3179 BlitBitmapMasked(bitmap, drawto,
3180 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3181 DX + DXSIZE - i, DY + j);
3182 BlitBitmapMasked(bitmap, drawto,
3183 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3184 DX + DXSIZE - i, DY + 140 + j);
3185 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3186 DY - (DOOR_GFX_PAGEY1 + j));
3187 BlitBitmapMasked(bitmap, drawto,
3188 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3190 BlitBitmapMasked(bitmap, drawto,
3191 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3194 BlitBitmapMasked(bitmap, drawto,
3195 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3197 BlitBitmapMasked(bitmap, drawto,
3198 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3200 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3201 BlitBitmapMasked(bitmap, drawto,
3202 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3203 DX + DXSIZE - i, DY + 77 + j);
3204 BlitBitmapMasked(bitmap, drawto,
3205 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3206 DX + DXSIZE - i, DY + 203 + j);
3209 redraw_mask |= REDRAW_DOOR_1;
3210 door_1_done = (a == end);
3213 if (door_state & DOOR_ACTION_2)
3215 int a = MIN(x * door_2.step_offset, door_size);
3216 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3217 int i = p + door_skip;
3219 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3221 BlitBitmap(bitmap_db_door, drawto,
3222 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3223 VXSIZE, VYSIZE, VX, VY);
3225 else if (x <= VYSIZE)
3227 BlitBitmap(bitmap_db_door, drawto,
3228 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3229 VXSIZE, VYSIZE - p / 2, VX, VY);
3231 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3234 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3236 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3237 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3238 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3239 int dst2_x = VX, dst2_y = VY;
3240 int width = i, height = VYSIZE;
3242 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3243 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3246 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3247 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3250 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3252 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3253 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3254 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3255 int dst2_x = VX, dst2_y = VY;
3256 int width = VXSIZE, height = i;
3258 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3259 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3262 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3263 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3266 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3268 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3270 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3271 BlitBitmapMasked(bitmap, drawto,
3272 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3273 VX + VXSIZE - i, VY + j);
3274 SetClipOrigin(bitmap, gc,
3275 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3276 BlitBitmapMasked(bitmap, drawto,
3277 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3280 BlitBitmapMasked(bitmap, drawto,
3281 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3282 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3283 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3284 BlitBitmapMasked(bitmap, drawto,
3285 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3287 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3290 redraw_mask |= REDRAW_DOOR_2;
3291 door_2_done = (a == VXSIZE);
3294 if (!(door_state & DOOR_NO_DELAY))
3298 if (game_status == GAME_MODE_MAIN)
3301 WaitUntilDelayReached(&door_delay, door_delay_value);
3306 if (door_state & DOOR_ACTION_1)
3307 door1 = door_state & DOOR_ACTION_1;
3308 if (door_state & DOOR_ACTION_2)
3309 door2 = door_state & DOOR_ACTION_2;
3311 return (door1 | door2);
3314 void DrawSpecialEditorDoor()
3316 /* draw bigger toolbox window */
3317 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3318 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3320 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3321 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3324 redraw_mask |= REDRAW_ALL;
3327 void UndrawSpecialEditorDoor()
3329 /* draw normal tape recorder window */
3330 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3331 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3334 redraw_mask |= REDRAW_ALL;
3338 /* ---------- new tool button stuff ---------------------------------------- */
3340 /* graphic position values for tool buttons */
3341 #define TOOL_BUTTON_YES_XPOS 2
3342 #define TOOL_BUTTON_YES_YPOS 250
3343 #define TOOL_BUTTON_YES_GFX_YPOS 0
3344 #define TOOL_BUTTON_YES_XSIZE 46
3345 #define TOOL_BUTTON_YES_YSIZE 28
3346 #define TOOL_BUTTON_NO_XPOS 52
3347 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3348 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3349 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3350 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3351 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3352 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3353 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3354 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3355 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3356 #define TOOL_BUTTON_PLAYER_XSIZE 30
3357 #define TOOL_BUTTON_PLAYER_YSIZE 30
3358 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3359 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3360 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3361 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3362 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3363 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3364 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3365 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3366 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3367 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3368 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3369 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3370 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3371 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3372 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3373 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3374 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3375 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3376 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3377 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3386 } toolbutton_info[NUM_TOOL_BUTTONS] =
3389 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3390 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3391 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3396 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3397 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3398 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3403 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3404 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3405 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3406 TOOL_CTRL_ID_CONFIRM,
3410 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3411 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3412 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3413 TOOL_CTRL_ID_PLAYER_1,
3417 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3418 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3419 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3420 TOOL_CTRL_ID_PLAYER_2,
3424 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3425 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3426 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3427 TOOL_CTRL_ID_PLAYER_3,
3431 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3432 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3433 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3434 TOOL_CTRL_ID_PLAYER_4,
3439 void CreateToolButtons()
3443 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3445 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3446 Bitmap *deco_bitmap = None;
3447 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3448 struct GadgetInfo *gi;
3449 unsigned long event_mask;
3450 int gd_xoffset, gd_yoffset;
3451 int gd_x1, gd_x2, gd_y;
3454 event_mask = GD_EVENT_RELEASED;
3456 gd_xoffset = toolbutton_info[i].xpos;
3457 gd_yoffset = toolbutton_info[i].ypos;
3458 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3459 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3460 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3462 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3464 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3466 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3467 &deco_bitmap, &deco_x, &deco_y);
3468 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3469 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3472 gi = CreateGadget(GDI_CUSTOM_ID, id,
3473 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3474 GDI_X, DX + toolbutton_info[i].x,
3475 GDI_Y, DY + toolbutton_info[i].y,
3476 GDI_WIDTH, toolbutton_info[i].width,
3477 GDI_HEIGHT, toolbutton_info[i].height,
3478 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3479 GDI_STATE, GD_BUTTON_UNPRESSED,
3480 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3481 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3482 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3483 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3484 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3485 GDI_DECORATION_SHIFTING, 1, 1,
3486 GDI_DIRECT_DRAW, FALSE,
3487 GDI_EVENT_MASK, event_mask,
3488 GDI_CALLBACK_ACTION, HandleToolButtons,
3492 Error(ERR_EXIT, "cannot create gadget");
3494 tool_gadget[id] = gi;
3498 void FreeToolButtons()
3502 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3503 FreeGadget(tool_gadget[i]);
3506 static void UnmapToolButtons()
3510 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3511 UnmapGadget(tool_gadget[i]);
3514 static void HandleToolButtons(struct GadgetInfo *gi)
3516 request_gadget_id = gi->custom_id;
3519 static struct Mapping_EM_to_RND_object
3522 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3523 boolean is_backside; /* backside of moving element */
3529 em_object_mapping_list[] =
3532 Xblank, TRUE, FALSE,
3536 Yacid_splash_eB, FALSE, FALSE,
3537 EL_ACID_SPLASH_RIGHT, -1, -1
3540 Yacid_splash_wB, FALSE, FALSE,
3541 EL_ACID_SPLASH_LEFT, -1, -1
3544 #ifdef EM_ENGINE_BAD_ROLL
3546 Xstone_force_e, FALSE, FALSE,
3547 EL_ROCK, -1, MV_BIT_RIGHT
3550 Xstone_force_w, FALSE, FALSE,
3551 EL_ROCK, -1, MV_BIT_LEFT
3554 Xnut_force_e, FALSE, FALSE,
3555 EL_NUT, -1, MV_BIT_RIGHT
3558 Xnut_force_w, FALSE, FALSE,
3559 EL_NUT, -1, MV_BIT_LEFT
3562 Xspring_force_e, FALSE, FALSE,
3563 EL_SPRING, -1, MV_BIT_RIGHT
3566 Xspring_force_w, FALSE, FALSE,
3567 EL_SPRING, -1, MV_BIT_LEFT
3570 Xemerald_force_e, FALSE, FALSE,
3571 EL_EMERALD, -1, MV_BIT_RIGHT
3574 Xemerald_force_w, FALSE, FALSE,
3575 EL_EMERALD, -1, MV_BIT_LEFT
3578 Xdiamond_force_e, FALSE, FALSE,
3579 EL_DIAMOND, -1, MV_BIT_RIGHT
3582 Xdiamond_force_w, FALSE, FALSE,
3583 EL_DIAMOND, -1, MV_BIT_LEFT
3586 Xbomb_force_e, FALSE, FALSE,
3587 EL_BOMB, -1, MV_BIT_RIGHT
3590 Xbomb_force_w, FALSE, FALSE,
3591 EL_BOMB, -1, MV_BIT_LEFT
3593 #endif /* EM_ENGINE_BAD_ROLL */
3596 Xstone, TRUE, FALSE,
3600 Xstone_pause, FALSE, FALSE,
3604 Xstone_fall, FALSE, FALSE,
3608 Ystone_s, FALSE, FALSE,
3609 EL_ROCK, ACTION_FALLING, -1
3612 Ystone_sB, FALSE, TRUE,
3613 EL_ROCK, ACTION_FALLING, -1
3616 Ystone_e, FALSE, FALSE,
3617 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3620 Ystone_eB, FALSE, TRUE,
3621 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3624 Ystone_w, FALSE, FALSE,
3625 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3628 Ystone_wB, FALSE, TRUE,
3629 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3636 Xnut_pause, FALSE, FALSE,
3640 Xnut_fall, FALSE, FALSE,
3644 Ynut_s, FALSE, FALSE,
3645 EL_NUT, ACTION_FALLING, -1
3648 Ynut_sB, FALSE, TRUE,
3649 EL_NUT, ACTION_FALLING, -1
3652 Ynut_e, FALSE, FALSE,
3653 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3656 Ynut_eB, FALSE, TRUE,
3657 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3660 Ynut_w, FALSE, FALSE,
3661 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3664 Ynut_wB, FALSE, TRUE,
3665 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3668 Xbug_n, TRUE, FALSE,
3672 Xbug_e, TRUE, FALSE,
3673 EL_BUG_RIGHT, -1, -1
3676 Xbug_s, TRUE, FALSE,
3680 Xbug_w, TRUE, FALSE,
3684 Xbug_gon, FALSE, FALSE,
3688 Xbug_goe, FALSE, FALSE,
3689 EL_BUG_RIGHT, -1, -1
3692 Xbug_gos, FALSE, FALSE,
3696 Xbug_gow, FALSE, FALSE,
3700 Ybug_n, FALSE, FALSE,
3701 EL_BUG, ACTION_MOVING, MV_BIT_UP
3704 Ybug_nB, FALSE, TRUE,
3705 EL_BUG, ACTION_MOVING, MV_BIT_UP
3708 Ybug_e, FALSE, FALSE,
3709 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3712 Ybug_eB, FALSE, TRUE,
3713 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3716 Ybug_s, FALSE, FALSE,
3717 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3720 Ybug_sB, FALSE, TRUE,
3721 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3724 Ybug_w, FALSE, FALSE,
3725 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3728 Ybug_wB, FALSE, TRUE,
3729 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3732 Ybug_w_n, FALSE, FALSE,
3733 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3736 Ybug_n_e, FALSE, FALSE,
3737 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3740 Ybug_e_s, FALSE, FALSE,
3741 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3744 Ybug_s_w, FALSE, FALSE,
3745 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3748 Ybug_e_n, FALSE, FALSE,
3749 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3752 Ybug_s_e, FALSE, FALSE,
3753 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3756 Ybug_w_s, FALSE, FALSE,
3757 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3760 Ybug_n_w, FALSE, FALSE,
3761 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3764 Ybug_stone, FALSE, FALSE,
3765 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3768 Ybug_spring, FALSE, FALSE,
3769 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3772 Xtank_n, TRUE, FALSE,
3773 EL_SPACESHIP_UP, -1, -1
3776 Xtank_e, TRUE, FALSE,
3777 EL_SPACESHIP_RIGHT, -1, -1
3780 Xtank_s, TRUE, FALSE,
3781 EL_SPACESHIP_DOWN, -1, -1
3784 Xtank_w, TRUE, FALSE,
3785 EL_SPACESHIP_LEFT, -1, -1
3788 Xtank_gon, FALSE, FALSE,
3789 EL_SPACESHIP_UP, -1, -1
3792 Xtank_goe, FALSE, FALSE,
3793 EL_SPACESHIP_RIGHT, -1, -1
3796 Xtank_gos, FALSE, FALSE,
3797 EL_SPACESHIP_DOWN, -1, -1
3800 Xtank_gow, FALSE, FALSE,
3801 EL_SPACESHIP_LEFT, -1, -1
3804 Ytank_n, FALSE, FALSE,
3805 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3808 Ytank_nB, FALSE, TRUE,
3809 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3812 Ytank_e, FALSE, FALSE,
3813 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3816 Ytank_eB, FALSE, TRUE,
3817 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3820 Ytank_s, FALSE, FALSE,
3821 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3824 Ytank_sB, FALSE, TRUE,
3825 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3828 Ytank_w, FALSE, FALSE,
3829 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3832 Ytank_wB, FALSE, TRUE,
3833 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3836 Ytank_w_n, FALSE, FALSE,
3837 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3840 Ytank_n_e, FALSE, FALSE,
3841 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3844 Ytank_e_s, FALSE, FALSE,
3845 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3848 Ytank_s_w, FALSE, FALSE,
3849 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3852 Ytank_e_n, FALSE, FALSE,
3853 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3856 Ytank_s_e, FALSE, FALSE,
3857 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3860 Ytank_w_s, FALSE, FALSE,
3861 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3864 Ytank_n_w, FALSE, FALSE,
3865 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3868 Ytank_stone, FALSE, FALSE,
3869 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3872 Ytank_spring, FALSE, FALSE,
3873 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3876 Xandroid, TRUE, FALSE,
3877 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3880 Xandroid_1_n, FALSE, FALSE,
3881 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3884 Xandroid_2_n, FALSE, FALSE,
3885 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3888 Xandroid_1_e, FALSE, FALSE,
3889 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3892 Xandroid_2_e, FALSE, FALSE,
3893 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3896 Xandroid_1_w, FALSE, FALSE,
3897 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3900 Xandroid_2_w, FALSE, FALSE,
3901 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3904 Xandroid_1_s, FALSE, FALSE,
3905 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3908 Xandroid_2_s, FALSE, FALSE,
3909 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3912 Yandroid_n, FALSE, FALSE,
3913 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3916 Yandroid_nB, FALSE, TRUE,
3917 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3920 Yandroid_ne, FALSE, FALSE,
3921 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3924 Yandroid_neB, FALSE, TRUE,
3925 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3928 Yandroid_e, FALSE, FALSE,
3929 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3932 Yandroid_eB, FALSE, TRUE,
3933 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3936 Yandroid_se, FALSE, FALSE,
3937 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3940 Yandroid_seB, FALSE, TRUE,
3941 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3944 Yandroid_s, FALSE, FALSE,
3945 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3948 Yandroid_sB, FALSE, TRUE,
3949 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3952 Yandroid_sw, FALSE, FALSE,
3953 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3956 Yandroid_swB, FALSE, TRUE,
3957 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3960 Yandroid_w, FALSE, FALSE,
3961 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3964 Yandroid_wB, FALSE, TRUE,
3965 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3968 Yandroid_nw, FALSE, FALSE,
3969 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3972 Yandroid_nwB, FALSE, TRUE,
3973 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3976 Xspring, TRUE, FALSE,
3980 Xspring_pause, FALSE, FALSE,
3984 Xspring_e, FALSE, FALSE,
3988 Xspring_w, FALSE, FALSE,
3992 Xspring_fall, FALSE, FALSE,
3996 Yspring_s, FALSE, FALSE,
3997 EL_SPRING, ACTION_FALLING, -1
4000 Yspring_sB, FALSE, TRUE,
4001 EL_SPRING, ACTION_FALLING, -1
4004 Yspring_e, FALSE, FALSE,
4005 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4008 Yspring_eB, FALSE, TRUE,
4009 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4012 Yspring_w, FALSE, FALSE,
4013 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4016 Yspring_wB, FALSE, TRUE,
4017 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4020 Yspring_kill_e, FALSE, FALSE,
4021 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4024 Yspring_kill_eB, FALSE, TRUE,
4025 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4028 Yspring_kill_w, FALSE, FALSE,
4029 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4032 Yspring_kill_wB, FALSE, TRUE,
4033 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4036 Xeater_n, TRUE, FALSE,
4037 EL_YAMYAM_UP, -1, -1
4040 Xeater_e, TRUE, FALSE,
4041 EL_YAMYAM_RIGHT, -1, -1
4044 Xeater_w, TRUE, FALSE,
4045 EL_YAMYAM_LEFT, -1, -1
4048 Xeater_s, TRUE, FALSE,
4049 EL_YAMYAM_DOWN, -1, -1
4052 Yeater_n, FALSE, FALSE,
4053 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4056 Yeater_nB, FALSE, TRUE,
4057 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4060 Yeater_e, FALSE, FALSE,
4061 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4064 Yeater_eB, FALSE, TRUE,
4065 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4068 Yeater_s, FALSE, FALSE,
4069 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4072 Yeater_sB, FALSE, TRUE,
4073 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4076 Yeater_w, FALSE, FALSE,
4077 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4080 Yeater_wB, FALSE, TRUE,
4081 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4084 Yeater_stone, FALSE, FALSE,
4085 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4088 Yeater_spring, FALSE, FALSE,
4089 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4092 Xalien, TRUE, FALSE,
4096 Xalien_pause, FALSE, FALSE,
4100 Yalien_n, FALSE, FALSE,
4101 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4104 Yalien_nB, FALSE, TRUE,
4105 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4108 Yalien_e, FALSE, FALSE,
4109 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4112 Yalien_eB, FALSE, TRUE,
4113 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4116 Yalien_s, FALSE, FALSE,
4117 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4120 Yalien_sB, FALSE, TRUE,
4121 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4124 Yalien_w, FALSE, FALSE,
4125 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4128 Yalien_wB, FALSE, TRUE,
4129 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4132 Yalien_stone, FALSE, FALSE,
4133 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4136 Yalien_spring, FALSE, FALSE,
4137 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4140 Xemerald, TRUE, FALSE,
4144 Xemerald_pause, FALSE, FALSE,
4148 Xemerald_fall, FALSE, FALSE,
4152 Xemerald_shine, FALSE, FALSE,
4153 EL_EMERALD, ACTION_TWINKLING, -1
4156 Yemerald_s, FALSE, FALSE,
4157 EL_EMERALD, ACTION_FALLING, -1
4160 Yemerald_sB, FALSE, TRUE,
4161 EL_EMERALD, ACTION_FALLING, -1
4164 Yemerald_e, FALSE, FALSE,
4165 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4168 Yemerald_eB, FALSE, TRUE,
4169 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4172 Yemerald_w, FALSE, FALSE,
4173 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4176 Yemerald_wB, FALSE, TRUE,
4177 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4180 Yemerald_eat, FALSE, FALSE,
4181 EL_EMERALD, ACTION_COLLECTING, -1
4184 Yemerald_stone, FALSE, FALSE,
4185 EL_NUT, ACTION_BREAKING, -1
4188 Xdiamond, TRUE, FALSE,
4192 Xdiamond_pause, FALSE, FALSE,
4196 Xdiamond_fall, FALSE, FALSE,
4200 Xdiamond_shine, FALSE, FALSE,
4201 EL_DIAMOND, ACTION_TWINKLING, -1
4204 Ydiamond_s, FALSE, FALSE,
4205 EL_DIAMOND, ACTION_FALLING, -1
4208 Ydiamond_sB, FALSE, TRUE,
4209 EL_DIAMOND, ACTION_FALLING, -1
4212 Ydiamond_e, FALSE, FALSE,
4213 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4216 Ydiamond_eB, FALSE, TRUE,
4217 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4220 Ydiamond_w, FALSE, FALSE,
4221 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4224 Ydiamond_wB, FALSE, TRUE,
4225 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4228 Ydiamond_eat, FALSE, FALSE,
4229 EL_DIAMOND, ACTION_COLLECTING, -1
4232 Ydiamond_stone, FALSE, FALSE,
4233 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4236 Xdrip_fall, TRUE, FALSE,
4237 EL_AMOEBA_DROP, -1, -1
4240 Xdrip_stretch, FALSE, FALSE,
4241 EL_AMOEBA_DROP, ACTION_FALLING, -1
4244 Xdrip_stretchB, FALSE, TRUE,
4245 EL_AMOEBA_DROP, ACTION_FALLING, -1
4248 Xdrip_eat, FALSE, FALSE,
4249 EL_AMOEBA_DROP, ACTION_GROWING, -1
4252 Ydrip_s1, FALSE, FALSE,
4253 EL_AMOEBA_DROP, ACTION_FALLING, -1
4256 Ydrip_s1B, FALSE, TRUE,
4257 EL_AMOEBA_DROP, ACTION_FALLING, -1
4260 Ydrip_s2, FALSE, FALSE,
4261 EL_AMOEBA_DROP, ACTION_FALLING, -1
4264 Ydrip_s2B, FALSE, TRUE,
4265 EL_AMOEBA_DROP, ACTION_FALLING, -1
4272 Xbomb_pause, FALSE, FALSE,
4276 Xbomb_fall, FALSE, FALSE,
4280 Ybomb_s, FALSE, FALSE,
4281 EL_BOMB, ACTION_FALLING, -1
4284 Ybomb_sB, FALSE, TRUE,
4285 EL_BOMB, ACTION_FALLING, -1
4288 Ybomb_e, FALSE, FALSE,
4289 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4292 Ybomb_eB, FALSE, TRUE,
4293 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4296 Ybomb_w, FALSE, FALSE,
4297 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4300 Ybomb_wB, FALSE, TRUE,
4301 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4304 Ybomb_eat, FALSE, FALSE,
4305 EL_BOMB, ACTION_ACTIVATING, -1
4308 Xballoon, TRUE, FALSE,
4312 Yballoon_n, FALSE, FALSE,
4313 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4316 Yballoon_nB, FALSE, TRUE,
4317 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4320 Yballoon_e, FALSE, FALSE,
4321 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4324 Yballoon_eB, FALSE, TRUE,
4325 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4328 Yballoon_s, FALSE, FALSE,
4329 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4332 Yballoon_sB, FALSE, TRUE,
4333 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4336 Yballoon_w, FALSE, FALSE,
4337 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4340 Yballoon_wB, FALSE, TRUE,
4341 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4344 Xgrass, TRUE, FALSE,
4345 EL_EMC_GRASS, -1, -1
4348 Ygrass_nB, FALSE, FALSE,
4349 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4352 Ygrass_eB, FALSE, FALSE,
4353 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4356 Ygrass_sB, FALSE, FALSE,
4357 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4360 Ygrass_wB, FALSE, FALSE,
4361 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4368 Ydirt_nB, FALSE, FALSE,
4369 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4372 Ydirt_eB, FALSE, FALSE,
4373 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4376 Ydirt_sB, FALSE, FALSE,
4377 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4380 Ydirt_wB, FALSE, FALSE,
4381 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4384 Xacid_ne, TRUE, FALSE,
4385 EL_ACID_POOL_TOPRIGHT, -1, -1
4388 Xacid_se, TRUE, FALSE,
4389 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4392 Xacid_s, TRUE, FALSE,
4393 EL_ACID_POOL_BOTTOM, -1, -1
4396 Xacid_sw, TRUE, FALSE,
4397 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4400 Xacid_nw, TRUE, FALSE,
4401 EL_ACID_POOL_TOPLEFT, -1, -1
4404 Xacid_1, TRUE, FALSE,
4408 Xacid_2, FALSE, FALSE,
4412 Xacid_3, FALSE, FALSE,
4416 Xacid_4, FALSE, FALSE,
4420 Xacid_5, FALSE, FALSE,
4424 Xacid_6, FALSE, FALSE,
4428 Xacid_7, FALSE, FALSE,
4432 Xacid_8, FALSE, FALSE,
4436 Xball_1, TRUE, FALSE,
4437 EL_EMC_MAGIC_BALL, -1, -1
4440 Xball_1B, FALSE, FALSE,
4441 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4444 Xball_2, FALSE, FALSE,
4445 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4448 Xball_2B, FALSE, FALSE,
4449 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4452 Yball_eat, FALSE, FALSE,
4453 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4456 Ykey_1_eat, FALSE, FALSE,
4457 EL_EM_KEY_1, ACTION_COLLECTING, -1
4460 Ykey_2_eat, FALSE, FALSE,
4461 EL_EM_KEY_2, ACTION_COLLECTING, -1
4464 Ykey_3_eat, FALSE, FALSE,
4465 EL_EM_KEY_3, ACTION_COLLECTING, -1
4468 Ykey_4_eat, FALSE, FALSE,
4469 EL_EM_KEY_4, ACTION_COLLECTING, -1
4472 Ykey_5_eat, FALSE, FALSE,
4473 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4476 Ykey_6_eat, FALSE, FALSE,
4477 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4480 Ykey_7_eat, FALSE, FALSE,
4481 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4484 Ykey_8_eat, FALSE, FALSE,
4485 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4488 Ylenses_eat, FALSE, FALSE,
4489 EL_EMC_LENSES, ACTION_COLLECTING, -1
4492 Ymagnify_eat, FALSE, FALSE,
4493 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4496 Ygrass_eat, FALSE, FALSE,
4497 EL_EMC_GRASS, ACTION_SNAPPING, -1
4500 Ydirt_eat, FALSE, FALSE,
4501 EL_SAND, ACTION_SNAPPING, -1
4504 Xgrow_ns, TRUE, FALSE,
4505 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4508 Ygrow_ns_eat, FALSE, FALSE,
4509 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4512 Xgrow_ew, TRUE, FALSE,
4513 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4516 Ygrow_ew_eat, FALSE, FALSE,
4517 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4520 Xwonderwall, TRUE, FALSE,
4521 EL_MAGIC_WALL, -1, -1
4524 XwonderwallB, FALSE, FALSE,
4525 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4528 Xamoeba_1, TRUE, FALSE,
4529 EL_AMOEBA_DRY, ACTION_OTHER, -1
4532 Xamoeba_2, FALSE, FALSE,
4533 EL_AMOEBA_DRY, ACTION_OTHER, -1
4536 Xamoeba_3, FALSE, FALSE,
4537 EL_AMOEBA_DRY, ACTION_OTHER, -1
4540 Xamoeba_4, FALSE, FALSE,
4541 EL_AMOEBA_DRY, ACTION_OTHER, -1
4544 Xamoeba_5, TRUE, FALSE,
4545 EL_AMOEBA_WET, ACTION_OTHER, -1
4548 Xamoeba_6, FALSE, FALSE,
4549 EL_AMOEBA_WET, ACTION_OTHER, -1
4552 Xamoeba_7, FALSE, FALSE,
4553 EL_AMOEBA_WET, ACTION_OTHER, -1
4556 Xamoeba_8, FALSE, FALSE,
4557 EL_AMOEBA_WET, ACTION_OTHER, -1
4560 Xdoor_1, TRUE, FALSE,
4561 EL_EM_GATE_1, -1, -1
4564 Xdoor_2, TRUE, FALSE,
4565 EL_EM_GATE_2, -1, -1
4568 Xdoor_3, TRUE, FALSE,
4569 EL_EM_GATE_3, -1, -1
4572 Xdoor_4, TRUE, FALSE,
4573 EL_EM_GATE_4, -1, -1
4576 Xdoor_5, TRUE, FALSE,
4577 EL_EMC_GATE_5, -1, -1
4580 Xdoor_6, TRUE, FALSE,
4581 EL_EMC_GATE_6, -1, -1
4584 Xdoor_7, TRUE, FALSE,
4585 EL_EMC_GATE_7, -1, -1
4588 Xdoor_8, TRUE, FALSE,
4589 EL_EMC_GATE_8, -1, -1
4592 Xkey_1, TRUE, FALSE,
4596 Xkey_2, TRUE, FALSE,
4600 Xkey_3, TRUE, FALSE,
4604 Xkey_4, TRUE, FALSE,
4608 Xkey_5, TRUE, FALSE,
4609 EL_EMC_KEY_5, -1, -1
4612 Xkey_6, TRUE, FALSE,
4613 EL_EMC_KEY_6, -1, -1
4616 Xkey_7, TRUE, FALSE,
4617 EL_EMC_KEY_7, -1, -1
4620 Xkey_8, TRUE, FALSE,
4621 EL_EMC_KEY_8, -1, -1
4624 Xwind_n, TRUE, FALSE,
4625 EL_BALLOON_SWITCH_UP, -1, -1
4628 Xwind_e, TRUE, FALSE,
4629 EL_BALLOON_SWITCH_RIGHT, -1, -1
4632 Xwind_s, TRUE, FALSE,
4633 EL_BALLOON_SWITCH_DOWN, -1, -1
4636 Xwind_w, TRUE, FALSE,
4637 EL_BALLOON_SWITCH_LEFT, -1, -1
4640 Xwind_nesw, TRUE, FALSE,
4641 EL_BALLOON_SWITCH_ANY, -1, -1
4644 Xwind_stop, TRUE, FALSE,
4645 EL_BALLOON_SWITCH_NONE, -1, -1
4649 EL_EM_EXIT_CLOSED, -1, -1
4652 Xexit_1, TRUE, FALSE,
4653 EL_EM_EXIT_OPEN, -1, -1
4656 Xexit_2, FALSE, FALSE,
4657 EL_EM_EXIT_OPEN, -1, -1
4660 Xexit_3, FALSE, FALSE,
4661 EL_EM_EXIT_OPEN, -1, -1
4664 Xdynamite, TRUE, FALSE,
4665 EL_EM_DYNAMITE, -1, -1
4668 Ydynamite_eat, FALSE, FALSE,
4669 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4672 Xdynamite_1, TRUE, FALSE,
4673 EL_EM_DYNAMITE_ACTIVE, -1, -1
4676 Xdynamite_2, FALSE, FALSE,
4677 EL_EM_DYNAMITE_ACTIVE, -1, -1
4680 Xdynamite_3, FALSE, FALSE,
4681 EL_EM_DYNAMITE_ACTIVE, -1, -1
4684 Xdynamite_4, FALSE, FALSE,
4685 EL_EM_DYNAMITE_ACTIVE, -1, -1
4688 Xbumper, TRUE, FALSE,
4689 EL_EMC_SPRING_BUMPER, -1, -1
4692 XbumperB, FALSE, FALSE,
4693 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4696 Xwheel, TRUE, FALSE,
4697 EL_ROBOT_WHEEL, -1, -1
4700 XwheelB, FALSE, FALSE,
4701 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4704 Xswitch, TRUE, FALSE,
4705 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4708 XswitchB, FALSE, FALSE,
4709 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4713 EL_QUICKSAND_EMPTY, -1, -1
4716 Xsand_stone, TRUE, FALSE,
4717 EL_QUICKSAND_FULL, -1, -1
4720 Xsand_stonein_1, FALSE, TRUE,
4721 EL_ROCK, ACTION_FILLING, -1
4724 Xsand_stonein_2, FALSE, TRUE,
4725 EL_ROCK, ACTION_FILLING, -1
4728 Xsand_stonein_3, FALSE, TRUE,
4729 EL_ROCK, ACTION_FILLING, -1
4732 Xsand_stonein_4, FALSE, TRUE,
4733 EL_ROCK, ACTION_FILLING, -1
4736 Xsand_stonesand_1, FALSE, FALSE,
4737 EL_QUICKSAND_FULL, -1, -1
4740 Xsand_stonesand_2, FALSE, FALSE,
4741 EL_QUICKSAND_FULL, -1, -1
4744 Xsand_stonesand_3, FALSE, FALSE,
4745 EL_QUICKSAND_FULL, -1, -1
4748 Xsand_stonesand_4, FALSE, FALSE,
4749 EL_QUICKSAND_FULL, -1, -1
4752 Xsand_stoneout_1, FALSE, FALSE,
4753 EL_ROCK, ACTION_EMPTYING, -1
4756 Xsand_stoneout_2, FALSE, FALSE,
4757 EL_ROCK, ACTION_EMPTYING, -1
4760 Xsand_sandstone_1, FALSE, FALSE,
4761 EL_QUICKSAND_FULL, -1, -1
4764 Xsand_sandstone_2, FALSE, FALSE,
4765 EL_QUICKSAND_FULL, -1, -1
4768 Xsand_sandstone_3, FALSE, FALSE,
4769 EL_QUICKSAND_FULL, -1, -1
4772 Xsand_sandstone_4, FALSE, FALSE,
4773 EL_QUICKSAND_FULL, -1, -1
4776 Xplant, TRUE, FALSE,
4777 EL_EMC_PLANT, -1, -1
4780 Yplant, FALSE, FALSE,
4781 EL_EMC_PLANT, -1, -1
4784 Xlenses, TRUE, FALSE,
4785 EL_EMC_LENSES, -1, -1
4788 Xmagnify, TRUE, FALSE,
4789 EL_EMC_MAGNIFIER, -1, -1
4792 Xdripper, TRUE, FALSE,
4793 EL_EMC_DRIPPER, -1, -1
4796 XdripperB, FALSE, FALSE,
4797 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4800 Xfake_blank, TRUE, FALSE,
4801 EL_INVISIBLE_WALL, -1, -1
4804 Xfake_blankB, FALSE, FALSE,
4805 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4808 Xfake_grass, TRUE, FALSE,
4809 EL_EMC_FAKE_GRASS, -1, -1
4812 Xfake_grassB, FALSE, FALSE,
4813 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4816 Xfake_door_1, TRUE, FALSE,
4817 EL_EM_GATE_1_GRAY, -1, -1
4820 Xfake_door_2, TRUE, FALSE,
4821 EL_EM_GATE_2_GRAY, -1, -1
4824 Xfake_door_3, TRUE, FALSE,
4825 EL_EM_GATE_3_GRAY, -1, -1
4828 Xfake_door_4, TRUE, FALSE,
4829 EL_EM_GATE_4_GRAY, -1, -1
4832 Xfake_door_5, TRUE, FALSE,
4833 EL_EMC_GATE_5_GRAY, -1, -1
4836 Xfake_door_6, TRUE, FALSE,
4837 EL_EMC_GATE_6_GRAY, -1, -1
4840 Xfake_door_7, TRUE, FALSE,
4841 EL_EMC_GATE_7_GRAY, -1, -1
4844 Xfake_door_8, TRUE, FALSE,
4845 EL_EMC_GATE_8_GRAY, -1, -1
4848 Xfake_acid_1, TRUE, FALSE,
4849 EL_EMC_FAKE_ACID, -1, -1
4852 Xfake_acid_2, FALSE, FALSE,
4853 EL_EMC_FAKE_ACID, -1, -1
4856 Xfake_acid_3, FALSE, FALSE,
4857 EL_EMC_FAKE_ACID, -1, -1
4860 Xfake_acid_4, FALSE, FALSE,
4861 EL_EMC_FAKE_ACID, -1, -1
4864 Xfake_acid_5, FALSE, FALSE,
4865 EL_EMC_FAKE_ACID, -1, -1
4868 Xfake_acid_6, FALSE, FALSE,
4869 EL_EMC_FAKE_ACID, -1, -1
4872 Xfake_acid_7, FALSE, FALSE,
4873 EL_EMC_FAKE_ACID, -1, -1
4876 Xfake_acid_8, FALSE, FALSE,
4877 EL_EMC_FAKE_ACID, -1, -1
4880 Xsteel_1, TRUE, FALSE,
4881 EL_STEELWALL, -1, -1
4884 Xsteel_2, TRUE, FALSE,
4885 EL_EMC_STEELWALL_2, -1, -1
4888 Xsteel_3, TRUE, FALSE,
4889 EL_EMC_STEELWALL_3, -1, -1
4892 Xsteel_4, TRUE, FALSE,
4893 EL_EMC_STEELWALL_4, -1, -1
4896 Xwall_1, TRUE, FALSE,
4900 Xwall_2, TRUE, FALSE,
4901 EL_EMC_WALL_14, -1, -1
4904 Xwall_3, TRUE, FALSE,
4905 EL_EMC_WALL_15, -1, -1
4908 Xwall_4, TRUE, FALSE,
4909 EL_EMC_WALL_16, -1, -1
4912 Xround_wall_1, TRUE, FALSE,
4913 EL_WALL_SLIPPERY, -1, -1
4916 Xround_wall_2, TRUE, FALSE,
4917 EL_EMC_WALL_SLIPPERY_2, -1, -1
4920 Xround_wall_3, TRUE, FALSE,
4921 EL_EMC_WALL_SLIPPERY_3, -1, -1
4924 Xround_wall_4, TRUE, FALSE,
4925 EL_EMC_WALL_SLIPPERY_4, -1, -1
4928 Xdecor_1, TRUE, FALSE,
4929 EL_EMC_WALL_8, -1, -1
4932 Xdecor_2, TRUE, FALSE,
4933 EL_EMC_WALL_6, -1, -1
4936 Xdecor_3, TRUE, FALSE,
4937 EL_EMC_WALL_4, -1, -1
4940 Xdecor_4, TRUE, FALSE,
4941 EL_EMC_WALL_7, -1, -1
4944 Xdecor_5, TRUE, FALSE,
4945 EL_EMC_WALL_5, -1, -1
4948 Xdecor_6, TRUE, FALSE,
4949 EL_EMC_WALL_9, -1, -1
4952 Xdecor_7, TRUE, FALSE,
4953 EL_EMC_WALL_10, -1, -1
4956 Xdecor_8, TRUE, FALSE,
4957 EL_EMC_WALL_1, -1, -1
4960 Xdecor_9, TRUE, FALSE,
4961 EL_EMC_WALL_2, -1, -1
4964 Xdecor_10, TRUE, FALSE,
4965 EL_EMC_WALL_3, -1, -1
4968 Xdecor_11, TRUE, FALSE,
4969 EL_EMC_WALL_11, -1, -1
4972 Xdecor_12, TRUE, FALSE,
4973 EL_EMC_WALL_12, -1, -1
4976 Xalpha_0, TRUE, FALSE,
4977 EL_CHAR('0'), -1, -1
4980 Xalpha_1, TRUE, FALSE,
4981 EL_CHAR('1'), -1, -1
4984 Xalpha_2, TRUE, FALSE,
4985 EL_CHAR('2'), -1, -1
4988 Xalpha_3, TRUE, FALSE,
4989 EL_CHAR('3'), -1, -1
4992 Xalpha_4, TRUE, FALSE,
4993 EL_CHAR('4'), -1, -1
4996 Xalpha_5, TRUE, FALSE,
4997 EL_CHAR('5'), -1, -1
5000 Xalpha_6, TRUE, FALSE,
5001 EL_CHAR('6'), -1, -1
5004 Xalpha_7, TRUE, FALSE,
5005 EL_CHAR('7'), -1, -1
5008 Xalpha_8, TRUE, FALSE,
5009 EL_CHAR('8'), -1, -1
5012 Xalpha_9, TRUE, FALSE,
5013 EL_CHAR('9'), -1, -1
5016 Xalpha_excla, TRUE, FALSE,
5017 EL_CHAR('!'), -1, -1
5020 Xalpha_quote, TRUE, FALSE,
5021 EL_CHAR('"'), -1, -1
5024 Xalpha_comma, TRUE, FALSE,
5025 EL_CHAR(','), -1, -1
5028 Xalpha_minus, TRUE, FALSE,
5029 EL_CHAR('-'), -1, -1
5032 Xalpha_perio, TRUE, FALSE,
5033 EL_CHAR('.'), -1, -1
5036 Xalpha_colon, TRUE, FALSE,
5037 EL_CHAR(':'), -1, -1
5040 Xalpha_quest, TRUE, FALSE,
5041 EL_CHAR('?'), -1, -1
5044 Xalpha_a, TRUE, FALSE,
5045 EL_CHAR('A'), -1, -1
5048 Xalpha_b, TRUE, FALSE,
5049 EL_CHAR('B'), -1, -1
5052 Xalpha_c, TRUE, FALSE,
5053 EL_CHAR('C'), -1, -1
5056 Xalpha_d, TRUE, FALSE,
5057 EL_CHAR('D'), -1, -1
5060 Xalpha_e, TRUE, FALSE,
5061 EL_CHAR('E'), -1, -1
5064 Xalpha_f, TRUE, FALSE,
5065 EL_CHAR('F'), -1, -1
5068 Xalpha_g, TRUE, FALSE,
5069 EL_CHAR('G'), -1, -1
5072 Xalpha_h, TRUE, FALSE,
5073 EL_CHAR('H'), -1, -1
5076 Xalpha_i, TRUE, FALSE,
5077 EL_CHAR('I'), -1, -1
5080 Xalpha_j, TRUE, FALSE,
5081 EL_CHAR('J'), -1, -1
5084 Xalpha_k, TRUE, FALSE,
5085 EL_CHAR('K'), -1, -1
5088 Xalpha_l, TRUE, FALSE,
5089 EL_CHAR('L'), -1, -1
5092 Xalpha_m, TRUE, FALSE,
5093 EL_CHAR('M'), -1, -1
5096 Xalpha_n, TRUE, FALSE,
5097 EL_CHAR('N'), -1, -1
5100 Xalpha_o, TRUE, FALSE,
5101 EL_CHAR('O'), -1, -1
5104 Xalpha_p, TRUE, FALSE,
5105 EL_CHAR('P'), -1, -1
5108 Xalpha_q, TRUE, FALSE,
5109 EL_CHAR('Q'), -1, -1
5112 Xalpha_r, TRUE, FALSE,
5113 EL_CHAR('R'), -1, -1
5116 Xalpha_s, TRUE, FALSE,
5117 EL_CHAR('S'), -1, -1
5120 Xalpha_t, TRUE, FALSE,
5121 EL_CHAR('T'), -1, -1
5124 Xalpha_u, TRUE, FALSE,
5125 EL_CHAR('U'), -1, -1
5128 Xalpha_v, TRUE, FALSE,
5129 EL_CHAR('V'), -1, -1
5132 Xalpha_w, TRUE, FALSE,
5133 EL_CHAR('W'), -1, -1
5136 Xalpha_x, TRUE, FALSE,
5137 EL_CHAR('X'), -1, -1
5140 Xalpha_y, TRUE, FALSE,
5141 EL_CHAR('Y'), -1, -1
5144 Xalpha_z, TRUE, FALSE,
5145 EL_CHAR('Z'), -1, -1
5148 Xalpha_arrow_e, TRUE, FALSE,
5149 EL_CHAR('>'), -1, -1
5152 Xalpha_arrow_w, TRUE, FALSE,
5153 EL_CHAR('<'), -1, -1
5156 Xalpha_copyr, TRUE, FALSE,
5157 EL_CHAR('©'), -1, -1
5161 Xboom_bug, FALSE, FALSE,
5162 EL_BUG, ACTION_EXPLODING, -1
5165 Xboom_bomb, FALSE, FALSE,
5166 EL_BOMB, ACTION_EXPLODING, -1
5169 Xboom_android, FALSE, FALSE,
5170 EL_EMC_ANDROID, ACTION_OTHER, -1
5173 Xboom_1, FALSE, FALSE,
5174 EL_DEFAULT, ACTION_EXPLODING, -1
5177 Xboom_2, FALSE, FALSE,
5178 EL_DEFAULT, ACTION_EXPLODING, -1
5181 Znormal, FALSE, FALSE,
5185 Zdynamite, FALSE, FALSE,
5189 Zplayer, FALSE, FALSE,
5193 ZBORDER, FALSE, FALSE,
5203 static struct Mapping_EM_to_RND_player
5212 em_player_mapping_list[] =
5216 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5220 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5224 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5228 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5232 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5236 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5240 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5244 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5248 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5252 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5256 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5260 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5264 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5268 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5272 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5276 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5280 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5284 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5288 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5292 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5296 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5300 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5304 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5308 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5312 EL_PLAYER_1, ACTION_DEFAULT, -1,
5316 EL_PLAYER_2, ACTION_DEFAULT, -1,
5320 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5324 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5328 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5332 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5336 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5340 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5344 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5348 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5352 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5356 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5360 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5364 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5368 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5372 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5376 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5380 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5384 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5388 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5392 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5396 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5400 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5404 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5408 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5412 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5416 EL_PLAYER_3, ACTION_DEFAULT, -1,
5420 EL_PLAYER_4, ACTION_DEFAULT, -1,
5429 int map_element_RND_to_EM(int element_rnd)
5431 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5432 static boolean mapping_initialized = FALSE;
5434 if (!mapping_initialized)
5438 /* return "Xalpha_quest" for all undefined elements in mapping array */
5439 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5440 mapping_RND_to_EM[i] = Xalpha_quest;
5442 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5443 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5444 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5445 em_object_mapping_list[i].element_em;
5447 mapping_initialized = TRUE;
5450 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5451 return mapping_RND_to_EM[element_rnd];
5453 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5458 int map_element_EM_to_RND(int element_em)
5460 static unsigned short mapping_EM_to_RND[TILE_MAX];
5461 static boolean mapping_initialized = FALSE;
5463 if (!mapping_initialized)
5467 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5468 for (i = 0; i < TILE_MAX; i++)
5469 mapping_EM_to_RND[i] = EL_UNKNOWN;
5471 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5472 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5473 em_object_mapping_list[i].element_rnd;
5475 mapping_initialized = TRUE;
5478 if (element_em >= 0 && element_em < TILE_MAX)
5479 return mapping_EM_to_RND[element_em];
5481 Error(ERR_WARN, "invalid EM level element %d", element_em);
5486 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5488 struct LevelInfo_EM *level_em = level->native_em_level;
5489 struct LEVEL *lev = level_em->lev;
5492 for (i = 0; i < TILE_MAX; i++)
5493 lev->android_array[i] = Xblank;
5495 for (i = 0; i < level->num_android_clone_elements; i++)
5497 int element_rnd = level->android_clone_element[i];
5498 int element_em = map_element_RND_to_EM(element_rnd);
5500 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5501 if (em_object_mapping_list[j].element_rnd == element_rnd)
5502 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5506 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5508 struct LevelInfo_EM *level_em = level->native_em_level;
5509 struct LEVEL *lev = level_em->lev;
5512 level->num_android_clone_elements = 0;
5514 for (i = 0; i < TILE_MAX; i++)
5516 int element_em = lev->android_array[i];
5518 boolean element_found = FALSE;
5520 if (element_em == Xblank)
5523 element_rnd = map_element_EM_to_RND(element_em);
5525 for (j = 0; j < level->num_android_clone_elements; j++)
5526 if (level->android_clone_element[j] == element_rnd)
5527 element_found = TRUE;
5531 level->android_clone_element[level->num_android_clone_elements++] =
5534 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5539 if (level->num_android_clone_elements == 0)
5541 level->num_android_clone_elements = 1;
5542 level->android_clone_element[0] = EL_EMPTY;
5546 int map_direction_RND_to_EM(int direction)
5548 return (direction == MV_UP ? 0 :
5549 direction == MV_RIGHT ? 1 :
5550 direction == MV_DOWN ? 2 :
5551 direction == MV_LEFT ? 3 :
5555 int map_direction_EM_to_RND(int direction)
5557 return (direction == 0 ? MV_UP :
5558 direction == 1 ? MV_RIGHT :
5559 direction == 2 ? MV_DOWN :
5560 direction == 3 ? MV_LEFT :
5564 int get_next_element(int element)
5568 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5569 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5570 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5571 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5572 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5573 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5574 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5575 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5576 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5577 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5578 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5580 default: return element;
5585 int el_act_dir2img(int element, int action, int direction)
5587 element = GFX_ELEMENT(element);
5589 if (direction == MV_NONE)
5590 return element_info[element].graphic[action];
5592 direction = MV_DIR_TO_BIT(direction);
5594 return element_info[element].direction_graphic[action][direction];
5597 int el_act_dir2img(int element, int action, int direction)
5599 element = GFX_ELEMENT(element);
5600 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5602 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5603 return element_info[element].direction_graphic[action][direction];
5608 static int el_act_dir2crm(int element, int action, int direction)
5610 element = GFX_ELEMENT(element);
5612 if (direction == MV_NONE)
5613 return element_info[element].crumbled[action];
5615 direction = MV_DIR_TO_BIT(direction);
5617 return element_info[element].direction_crumbled[action][direction];
5620 static int el_act_dir2crm(int element, int action, int direction)
5622 element = GFX_ELEMENT(element);
5623 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5625 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5626 return element_info[element].direction_crumbled[action][direction];
5630 int el_act2img(int element, int action)
5632 element = GFX_ELEMENT(element);
5634 return element_info[element].graphic[action];
5637 int el_act2crm(int element, int action)
5639 element = GFX_ELEMENT(element);
5641 return element_info[element].crumbled[action];
5644 int el_dir2img(int element, int direction)
5646 element = GFX_ELEMENT(element);
5648 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5651 int el2baseimg(int element)
5653 return element_info[element].graphic[ACTION_DEFAULT];
5656 int el2img(int element)
5658 element = GFX_ELEMENT(element);
5660 return element_info[element].graphic[ACTION_DEFAULT];
5663 int el2edimg(int element)
5665 element = GFX_ELEMENT(element);
5667 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5670 int el2preimg(int element)
5672 element = GFX_ELEMENT(element);
5674 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5677 int font2baseimg(int font_nr)
5679 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5682 int getBeltNrFromBeltElement(int element)
5684 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5685 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5686 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5689 int getBeltNrFromBeltActiveElement(int element)
5691 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5692 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5693 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5696 int getBeltNrFromBeltSwitchElement(int element)
5698 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5699 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5700 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5703 int getBeltDirNrFromBeltElement(int element)
5705 static int belt_base_element[4] =
5707 EL_CONVEYOR_BELT_1_LEFT,
5708 EL_CONVEYOR_BELT_2_LEFT,
5709 EL_CONVEYOR_BELT_3_LEFT,
5710 EL_CONVEYOR_BELT_4_LEFT
5713 int belt_nr = getBeltNrFromBeltElement(element);
5714 int belt_dir_nr = element - belt_base_element[belt_nr];
5716 return (belt_dir_nr % 3);
5719 int getBeltDirNrFromBeltSwitchElement(int element)
5721 static int belt_base_element[4] =
5723 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5724 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5725 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5726 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5729 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5730 int belt_dir_nr = element - belt_base_element[belt_nr];
5732 return (belt_dir_nr % 3);
5735 int getBeltDirFromBeltElement(int element)
5737 static int belt_move_dir[3] =
5744 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5746 return belt_move_dir[belt_dir_nr];
5749 int getBeltDirFromBeltSwitchElement(int element)
5751 static int belt_move_dir[3] =
5758 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5760 return belt_move_dir[belt_dir_nr];
5763 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5765 static int belt_base_element[4] =
5767 EL_CONVEYOR_BELT_1_LEFT,
5768 EL_CONVEYOR_BELT_2_LEFT,
5769 EL_CONVEYOR_BELT_3_LEFT,
5770 EL_CONVEYOR_BELT_4_LEFT
5772 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5774 return belt_base_element[belt_nr] + belt_dir_nr;
5777 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5779 static int belt_base_element[4] =
5781 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5782 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5783 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5784 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5786 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5788 return belt_base_element[belt_nr] + belt_dir_nr;
5791 int getNumActivePlayers_EM()
5793 int num_players = 0;
5799 for (i = 0; i < MAX_PLAYERS; i++)
5800 if (tape.player_participates[i])
5806 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5808 int game_frame_delay_value;
5810 game_frame_delay_value =
5811 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5812 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5815 if (tape.playing && tape.warp_forward && !tape.pausing)
5816 game_frame_delay_value = 0;
5818 return game_frame_delay_value;
5821 unsigned int InitRND(long seed)
5823 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5824 return InitEngineRandom_EM(seed);
5826 return InitEngineRandom_RND(seed);
5830 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5831 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5834 void ResetGfxAnimation_EM(int x, int y, int tile)
5839 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5840 Bitmap **src_bitmap, int *src_x, int *src_y,
5843 int element = object_mapping[tile].element_rnd;
5844 int action = object_mapping[tile].action;
5845 int direction = object_mapping[tile].direction;
5846 boolean is_backside = object_mapping[tile].is_backside;
5847 boolean action_removing = (action == ACTION_DIGGING ||
5848 action == ACTION_SNAPPING ||
5849 action == ACTION_COLLECTING);
5850 int effective_element = (frame_em > 0 ? element :
5851 is_backside ? EL_EMPTY :
5852 action_removing ? EL_EMPTY :
5854 int graphic = (direction == MV_NONE ?
5855 el_act2img(effective_element, action) :
5856 el_act_dir2img(effective_element, action, direction));
5857 struct GraphicInfo *g = &graphic_info[graphic];
5860 if (graphic_info[graphic].anim_global_sync)
5861 sync_frame = FrameCounter;
5863 sync_frame = 7 - frame_em;
5865 SetRandomAnimationValue(x, y);
5867 int frame = getAnimationFrame(g->anim_frames,
5870 g->anim_start_frame,
5873 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5876 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
5877 Bitmap **src_bitmap, int *src_x, int *src_y)
5879 int element = player_mapping[player_nr][anim].element_rnd;
5880 int action = player_mapping[player_nr][anim].action;
5881 int direction = player_mapping[player_nr][anim].direction;
5882 int graphic = (direction == MV_NONE ?
5883 el_act2img(element, action) :
5884 el_act_dir2img(element, action, direction));
5885 struct GraphicInfo *g = &graphic_info[graphic];
5888 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
5890 stored_player[player_nr].StepFrame = 7 - frame_em;
5892 sync_frame = stored_player[player_nr].Frame;
5895 printf("::: %d: %d, %d [%d]\n",
5897 stored_player[player_nr].Frame,
5898 stored_player[player_nr].StepFrame,
5902 int frame = getAnimationFrame(g->anim_frames,
5905 g->anim_start_frame,
5908 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5911 void InitGraphicInfo_EM(void)
5914 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5915 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5920 int num_em_gfx_errors = 0;
5922 if (graphic_info_em_object[0][0].bitmap == NULL)
5924 /* EM graphics not yet initialized in em_open_all() */
5929 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5932 /* always start with reliable default values */
5933 for (i = 0; i < TILE_MAX; i++)
5935 object_mapping[i].element_rnd = EL_UNKNOWN;
5936 object_mapping[i].is_backside = FALSE;
5937 object_mapping[i].action = ACTION_DEFAULT;
5938 object_mapping[i].direction = MV_NONE;
5941 /* always start with reliable default values */
5942 for (p = 0; p < MAX_PLAYERS; p++)
5944 for (i = 0; i < SPR_MAX; i++)
5946 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5947 player_mapping[p][i].action = ACTION_DEFAULT;
5948 player_mapping[p][i].direction = MV_NONE;
5952 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5954 int e = em_object_mapping_list[i].element_em;
5956 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5957 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5959 if (em_object_mapping_list[i].action != -1)
5960 object_mapping[e].action = em_object_mapping_list[i].action;
5962 if (em_object_mapping_list[i].direction != -1)
5963 object_mapping[e].direction =
5964 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5967 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5969 int a = em_player_mapping_list[i].action_em;
5970 int p = em_player_mapping_list[i].player_nr;
5972 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5974 if (em_player_mapping_list[i].action != -1)
5975 player_mapping[p][a].action = em_player_mapping_list[i].action;
5977 if (em_player_mapping_list[i].direction != -1)
5978 player_mapping[p][a].direction =
5979 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5982 for (i = 0; i < TILE_MAX; i++)
5984 int element = object_mapping[i].element_rnd;
5985 int action = object_mapping[i].action;
5986 int direction = object_mapping[i].direction;
5987 boolean is_backside = object_mapping[i].is_backside;
5988 boolean action_removing = (action == ACTION_DIGGING ||
5989 action == ACTION_SNAPPING ||
5990 action == ACTION_COLLECTING);
5991 boolean action_exploding = ((action == ACTION_EXPLODING ||
5992 action == ACTION_SMASHED_BY_ROCK ||
5993 action == ACTION_SMASHED_BY_SPRING) &&
5994 element != EL_DIAMOND);
5995 boolean action_active = (action == ACTION_ACTIVE);
5996 boolean action_other = (action == ACTION_OTHER);
5998 for (j = 0; j < 8; j++)
6000 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6001 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6003 i == Xdrip_stretch ? element :
6004 i == Xdrip_stretchB ? element :
6005 i == Ydrip_s1 ? element :
6006 i == Ydrip_s1B ? element :
6007 i == Xball_1B ? element :
6008 i == Xball_2 ? element :
6009 i == Xball_2B ? element :
6010 i == Yball_eat ? element :
6011 i == Ykey_1_eat ? element :
6012 i == Ykey_2_eat ? element :
6013 i == Ykey_3_eat ? element :
6014 i == Ykey_4_eat ? element :
6015 i == Ykey_5_eat ? element :
6016 i == Ykey_6_eat ? element :
6017 i == Ykey_7_eat ? element :
6018 i == Ykey_8_eat ? element :
6019 i == Ylenses_eat ? element :
6020 i == Ymagnify_eat ? element :
6021 i == Ygrass_eat ? element :
6022 i == Ydirt_eat ? element :
6023 i == Yemerald_stone ? EL_EMERALD :
6024 i == Ydiamond_stone ? EL_ROCK :
6025 i == Xsand_stonein_1 ? element :
6026 i == Xsand_stonein_2 ? element :
6027 i == Xsand_stonein_3 ? element :
6028 i == Xsand_stonein_4 ? element :
6029 is_backside ? EL_EMPTY :
6030 action_removing ? EL_EMPTY :
6032 int effective_action = (j < 7 ? action :
6033 i == Xdrip_stretch ? action :
6034 i == Xdrip_stretchB ? action :
6035 i == Ydrip_s1 ? action :
6036 i == Ydrip_s1B ? action :
6037 i == Xball_1B ? action :
6038 i == Xball_2 ? action :
6039 i == Xball_2B ? action :
6040 i == Yball_eat ? action :
6041 i == Ykey_1_eat ? action :
6042 i == Ykey_2_eat ? action :
6043 i == Ykey_3_eat ? action :
6044 i == Ykey_4_eat ? action :
6045 i == Ykey_5_eat ? action :
6046 i == Ykey_6_eat ? action :
6047 i == Ykey_7_eat ? action :
6048 i == Ykey_8_eat ? action :
6049 i == Ylenses_eat ? action :
6050 i == Ymagnify_eat ? action :
6051 i == Ygrass_eat ? action :
6052 i == Ydirt_eat ? action :
6053 i == Xsand_stonein_1 ? action :
6054 i == Xsand_stonein_2 ? action :
6055 i == Xsand_stonein_3 ? action :
6056 i == Xsand_stonein_4 ? action :
6057 i == Xsand_stoneout_1 ? action :
6058 i == Xsand_stoneout_2 ? action :
6059 i == Xboom_android ? ACTION_EXPLODING :
6060 action_exploding ? ACTION_EXPLODING :
6061 action_active ? action :
6062 action_other ? action :
6064 int graphic = (el_act_dir2img(effective_element, effective_action,
6066 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6068 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6069 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6070 boolean has_action_graphics = (graphic != base_graphic);
6071 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6072 struct GraphicInfo *g = &graphic_info[graphic];
6073 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6076 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6077 boolean special_animation = (action != ACTION_DEFAULT &&
6078 g->anim_frames == 3 &&
6079 g->anim_delay == 2 &&
6080 g->anim_mode & ANIM_LINEAR);
6081 int sync_frame = (i == Xdrip_stretch ? 7 :
6082 i == Xdrip_stretchB ? 7 :
6083 i == Ydrip_s2 ? j + 8 :
6084 i == Ydrip_s2B ? j + 8 :
6093 i == Xfake_acid_1 ? 0 :
6094 i == Xfake_acid_2 ? 10 :
6095 i == Xfake_acid_3 ? 20 :
6096 i == Xfake_acid_4 ? 30 :
6097 i == Xfake_acid_5 ? 40 :
6098 i == Xfake_acid_6 ? 50 :
6099 i == Xfake_acid_7 ? 60 :
6100 i == Xfake_acid_8 ? 70 :
6102 i == Xball_2B ? j + 8 :
6103 i == Yball_eat ? j + 1 :
6104 i == Ykey_1_eat ? j + 1 :
6105 i == Ykey_2_eat ? j + 1 :
6106 i == Ykey_3_eat ? j + 1 :
6107 i == Ykey_4_eat ? j + 1 :
6108 i == Ykey_5_eat ? j + 1 :
6109 i == Ykey_6_eat ? j + 1 :
6110 i == Ykey_7_eat ? j + 1 :
6111 i == Ykey_8_eat ? j + 1 :
6112 i == Ylenses_eat ? j + 1 :
6113 i == Ymagnify_eat ? j + 1 :
6114 i == Ygrass_eat ? j + 1 :
6115 i == Ydirt_eat ? j + 1 :
6116 i == Xamoeba_1 ? 0 :
6117 i == Xamoeba_2 ? 1 :
6118 i == Xamoeba_3 ? 2 :
6119 i == Xamoeba_4 ? 3 :
6120 i == Xamoeba_5 ? 0 :
6121 i == Xamoeba_6 ? 1 :
6122 i == Xamoeba_7 ? 2 :
6123 i == Xamoeba_8 ? 3 :
6124 i == Xexit_2 ? j + 8 :
6125 i == Xexit_3 ? j + 16 :
6126 i == Xdynamite_1 ? 0 :
6127 i == Xdynamite_2 ? 8 :
6128 i == Xdynamite_3 ? 16 :
6129 i == Xdynamite_4 ? 24 :
6130 i == Xsand_stonein_1 ? j + 1 :
6131 i == Xsand_stonein_2 ? j + 9 :
6132 i == Xsand_stonein_3 ? j + 17 :
6133 i == Xsand_stonein_4 ? j + 25 :
6134 i == Xsand_stoneout_1 && j == 0 ? 0 :
6135 i == Xsand_stoneout_1 && j == 1 ? 0 :
6136 i == Xsand_stoneout_1 && j == 2 ? 1 :
6137 i == Xsand_stoneout_1 && j == 3 ? 2 :
6138 i == Xsand_stoneout_1 && j == 4 ? 2 :
6139 i == Xsand_stoneout_1 && j == 5 ? 3 :
6140 i == Xsand_stoneout_1 && j == 6 ? 4 :
6141 i == Xsand_stoneout_1 && j == 7 ? 4 :
6142 i == Xsand_stoneout_2 && j == 0 ? 5 :
6143 i == Xsand_stoneout_2 && j == 1 ? 6 :
6144 i == Xsand_stoneout_2 && j == 2 ? 7 :
6145 i == Xsand_stoneout_2 && j == 3 ? 8 :
6146 i == Xsand_stoneout_2 && j == 4 ? 9 :
6147 i == Xsand_stoneout_2 && j == 5 ? 11 :
6148 i == Xsand_stoneout_2 && j == 6 ? 13 :
6149 i == Xsand_stoneout_2 && j == 7 ? 15 :
6150 i == Xboom_bug && j == 1 ? 2 :
6151 i == Xboom_bug && j == 2 ? 2 :
6152 i == Xboom_bug && j == 3 ? 4 :
6153 i == Xboom_bug && j == 4 ? 4 :
6154 i == Xboom_bug && j == 5 ? 2 :
6155 i == Xboom_bug && j == 6 ? 2 :
6156 i == Xboom_bug && j == 7 ? 0 :
6157 i == Xboom_bomb && j == 1 ? 2 :
6158 i == Xboom_bomb && j == 2 ? 2 :
6159 i == Xboom_bomb && j == 3 ? 4 :
6160 i == Xboom_bomb && j == 4 ? 4 :
6161 i == Xboom_bomb && j == 5 ? 2 :
6162 i == Xboom_bomb && j == 6 ? 2 :
6163 i == Xboom_bomb && j == 7 ? 0 :
6164 i == Xboom_android && j == 7 ? 6 :
6165 i == Xboom_1 && j == 1 ? 2 :
6166 i == Xboom_1 && j == 2 ? 2 :
6167 i == Xboom_1 && j == 3 ? 4 :
6168 i == Xboom_1 && j == 4 ? 4 :
6169 i == Xboom_1 && j == 5 ? 6 :
6170 i == Xboom_1 && j == 6 ? 6 :
6171 i == Xboom_1 && j == 7 ? 8 :
6172 i == Xboom_2 && j == 0 ? 8 :
6173 i == Xboom_2 && j == 1 ? 8 :
6174 i == Xboom_2 && j == 2 ? 10 :
6175 i == Xboom_2 && j == 3 ? 10 :
6176 i == Xboom_2 && j == 4 ? 10 :
6177 i == Xboom_2 && j == 5 ? 12 :
6178 i == Xboom_2 && j == 6 ? 12 :
6179 i == Xboom_2 && j == 7 ? 12 :
6180 special_animation && j == 4 ? 3 :
6181 effective_action != action ? 0 :
6185 Bitmap *debug_bitmap = g_em->bitmap;
6186 int debug_src_x = g_em->src_x;
6187 int debug_src_y = g_em->src_y;
6190 int frame = getAnimationFrame(g->anim_frames,
6193 g->anim_start_frame,
6196 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6197 g->double_movement && is_backside);
6199 g_em->bitmap = src_bitmap;
6200 g_em->src_x = src_x;
6201 g_em->src_y = src_y;
6202 g_em->src_offset_x = 0;
6203 g_em->src_offset_y = 0;
6204 g_em->dst_offset_x = 0;
6205 g_em->dst_offset_y = 0;
6206 g_em->width = TILEX;
6207 g_em->height = TILEY;
6209 g_em->crumbled_bitmap = NULL;
6210 g_em->crumbled_src_x = 0;
6211 g_em->crumbled_src_y = 0;
6212 g_em->crumbled_border_size = 0;
6214 g_em->has_crumbled_graphics = FALSE;
6215 g_em->preserve_background = FALSE;
6218 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6219 printf("::: empty crumbled: %d [%s], %d, %d\n",
6220 effective_element, element_info[effective_element].token_name,
6221 effective_action, direction);
6224 /* if element can be crumbled, but certain action graphics are just empty
6225 space (like snapping sand with the original R'n'D graphics), do not
6226 treat these empty space graphics as crumbled graphics in EMC engine */
6227 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6229 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6231 g_em->has_crumbled_graphics = TRUE;
6232 g_em->crumbled_bitmap = src_bitmap;
6233 g_em->crumbled_src_x = src_x;
6234 g_em->crumbled_src_y = src_y;
6235 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6239 if (element == EL_ROCK &&
6240 effective_action == ACTION_FILLING)
6241 printf("::: has_action_graphics == %d\n", has_action_graphics);
6244 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6245 effective_action == ACTION_MOVING ||
6246 effective_action == ACTION_PUSHING ||
6247 effective_action == ACTION_EATING)) ||
6248 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6249 effective_action == ACTION_EMPTYING)))
6252 (effective_action == ACTION_FALLING ||
6253 effective_action == ACTION_FILLING ||
6254 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6255 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6256 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6257 int num_steps = (i == Ydrip_s1 ? 16 :
6258 i == Ydrip_s1B ? 16 :
6259 i == Ydrip_s2 ? 16 :
6260 i == Ydrip_s2B ? 16 :
6261 i == Xsand_stonein_1 ? 32 :
6262 i == Xsand_stonein_2 ? 32 :
6263 i == Xsand_stonein_3 ? 32 :
6264 i == Xsand_stonein_4 ? 32 :
6265 i == Xsand_stoneout_1 ? 16 :
6266 i == Xsand_stoneout_2 ? 16 : 8);
6267 int cx = ABS(dx) * (TILEX / num_steps);
6268 int cy = ABS(dy) * (TILEY / num_steps);
6269 int step_frame = (i == Ydrip_s2 ? j + 8 :
6270 i == Ydrip_s2B ? j + 8 :
6271 i == Xsand_stonein_2 ? j + 8 :
6272 i == Xsand_stonein_3 ? j + 16 :
6273 i == Xsand_stonein_4 ? j + 24 :
6274 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6275 int step = (is_backside ? step_frame : num_steps - step_frame);
6277 if (is_backside) /* tile where movement starts */
6279 if (dx < 0 || dy < 0)
6281 g_em->src_offset_x = cx * step;
6282 g_em->src_offset_y = cy * step;
6286 g_em->dst_offset_x = cx * step;
6287 g_em->dst_offset_y = cy * step;
6290 else /* tile where movement ends */
6292 if (dx < 0 || dy < 0)
6294 g_em->dst_offset_x = cx * step;
6295 g_em->dst_offset_y = cy * step;
6299 g_em->src_offset_x = cx * step;
6300 g_em->src_offset_y = cy * step;
6304 g_em->width = TILEX - cx * step;
6305 g_em->height = TILEY - cy * step;
6308 /* create unique graphic identifier to decide if tile must be redrawn */
6309 /* bit 31 - 16 (16 bit): EM style graphic
6310 bit 15 - 12 ( 4 bit): EM style frame
6311 bit 11 - 6 ( 6 bit): graphic width
6312 bit 5 - 0 ( 6 bit): graphic height */
6313 g_em->unique_identifier =
6314 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6318 /* skip check for EMC elements not contained in original EMC artwork */
6319 if (element == EL_EMC_FAKE_ACID)
6322 if (g_em->bitmap != debug_bitmap ||
6323 g_em->src_x != debug_src_x ||
6324 g_em->src_y != debug_src_y ||
6325 g_em->src_offset_x != 0 ||
6326 g_em->src_offset_y != 0 ||
6327 g_em->dst_offset_x != 0 ||
6328 g_em->dst_offset_y != 0 ||
6329 g_em->width != TILEX ||
6330 g_em->height != TILEY)
6332 static int last_i = -1;
6340 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6341 i, element, element_info[element].token_name,
6342 element_action_info[effective_action].suffix, direction);
6344 if (element != effective_element)
6345 printf(" [%d ('%s')]",
6347 element_info[effective_element].token_name);
6351 if (g_em->bitmap != debug_bitmap)
6352 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6353 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6355 if (g_em->src_x != debug_src_x ||
6356 g_em->src_y != debug_src_y)
6357 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6358 j, (is_backside ? 'B' : 'F'),
6359 g_em->src_x, g_em->src_y,
6360 g_em->src_x / 32, g_em->src_y / 32,
6361 debug_src_x, debug_src_y,
6362 debug_src_x / 32, debug_src_y / 32);
6364 if (g_em->src_offset_x != 0 ||
6365 g_em->src_offset_y != 0 ||
6366 g_em->dst_offset_x != 0 ||
6367 g_em->dst_offset_y != 0)
6368 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6370 g_em->src_offset_x, g_em->src_offset_y,
6371 g_em->dst_offset_x, g_em->dst_offset_y);
6373 if (g_em->width != TILEX ||
6374 g_em->height != TILEY)
6375 printf(" %d (%d): size %d,%d should be %d,%d\n",
6377 g_em->width, g_em->height, TILEX, TILEY);
6379 num_em_gfx_errors++;
6386 for (i = 0; i < TILE_MAX; i++)
6388 for (j = 0; j < 8; j++)
6390 int element = object_mapping[i].element_rnd;
6391 int action = object_mapping[i].action;
6392 int direction = object_mapping[i].direction;
6393 boolean is_backside = object_mapping[i].is_backside;
6394 int graphic_action = el_act_dir2img(element, action, direction);
6395 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6397 if ((action == ACTION_SMASHED_BY_ROCK ||
6398 action == ACTION_SMASHED_BY_SPRING ||
6399 action == ACTION_EATING) &&
6400 graphic_action == graphic_default)
6402 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6403 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6404 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6405 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6408 /* no separate animation for "smashed by rock" -- use rock instead */
6409 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6410 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6412 g_em->bitmap = g_xx->bitmap;
6413 g_em->src_x = g_xx->src_x;
6414 g_em->src_y = g_xx->src_y;
6415 g_em->src_offset_x = g_xx->src_offset_x;
6416 g_em->src_offset_y = g_xx->src_offset_y;
6417 g_em->dst_offset_x = g_xx->dst_offset_x;
6418 g_em->dst_offset_y = g_xx->dst_offset_y;
6419 g_em->width = g_xx->width;
6420 g_em->height = g_xx->height;
6421 g_em->unique_identifier = g_xx->unique_identifier;
6424 g_em->preserve_background = TRUE;
6429 for (p = 0; p < MAX_PLAYERS; p++)
6431 for (i = 0; i < SPR_MAX; i++)
6433 int element = player_mapping[p][i].element_rnd;
6434 int action = player_mapping[p][i].action;
6435 int direction = player_mapping[p][i].direction;
6437 for (j = 0; j < 8; j++)
6439 int effective_element = element;
6440 int effective_action = action;
6441 int graphic = (direction == MV_NONE ?
6442 el_act2img(effective_element, effective_action) :
6443 el_act_dir2img(effective_element, effective_action,
6445 struct GraphicInfo *g = &graphic_info[graphic];
6446 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6452 Bitmap *debug_bitmap = g_em->bitmap;
6453 int debug_src_x = g_em->src_x;
6454 int debug_src_y = g_em->src_y;
6457 int frame = getAnimationFrame(g->anim_frames,
6460 g->anim_start_frame,
6463 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6465 g_em->bitmap = src_bitmap;
6466 g_em->src_x = src_x;
6467 g_em->src_y = src_y;
6468 g_em->src_offset_x = 0;
6469 g_em->src_offset_y = 0;
6470 g_em->dst_offset_x = 0;
6471 g_em->dst_offset_y = 0;
6472 g_em->width = TILEX;
6473 g_em->height = TILEY;
6477 /* skip check for EMC elements not contained in original EMC artwork */
6478 if (element == EL_PLAYER_3 ||
6479 element == EL_PLAYER_4)
6482 if (g_em->bitmap != debug_bitmap ||
6483 g_em->src_x != debug_src_x ||
6484 g_em->src_y != debug_src_y)
6486 static int last_i = -1;
6494 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6495 p, i, element, element_info[element].token_name,
6496 element_action_info[effective_action].suffix, direction);
6498 if (element != effective_element)
6499 printf(" [%d ('%s')]",
6501 element_info[effective_element].token_name);
6505 if (g_em->bitmap != debug_bitmap)
6506 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6507 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6509 if (g_em->src_x != debug_src_x ||
6510 g_em->src_y != debug_src_y)
6511 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6513 g_em->src_x, g_em->src_y,
6514 g_em->src_x / 32, g_em->src_y / 32,
6515 debug_src_x, debug_src_y,
6516 debug_src_x / 32, debug_src_y / 32);
6518 num_em_gfx_errors++;
6528 printf("::: [%d errors found]\n", num_em_gfx_errors);
6534 void PlayMenuSoundExt(int sound)
6536 if (sound == SND_UNDEFINED)
6539 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6540 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6543 if (IS_LOOP_SOUND(sound))
6544 PlaySoundLoop(sound);
6549 void PlayMenuSound()
6551 PlayMenuSoundExt(menu.sound[game_status]);
6554 void PlayMenuSoundStereo(int sound, int stereo_position)
6556 if (sound == SND_UNDEFINED)
6559 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6560 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6563 if (IS_LOOP_SOUND(sound))
6564 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6566 PlaySoundStereo(sound, stereo_position);
6569 void PlayMenuSoundIfLoopExt(int sound)
6571 if (sound == SND_UNDEFINED)
6574 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6575 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6578 if (IS_LOOP_SOUND(sound))
6579 PlaySoundLoop(sound);
6582 void PlayMenuSoundIfLoop()
6584 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6587 void PlayMenuMusicExt(int music)
6589 if (music == MUS_UNDEFINED)
6592 if (!setup.sound_music)
6598 void PlayMenuMusic()
6600 PlayMenuMusicExt(menu.music[game_status]);
6603 void PlaySoundActivating()
6606 PlaySound(SND_MENU_ITEM_ACTIVATING);
6610 void PlaySoundSelecting()
6613 PlaySound(SND_MENU_ITEM_SELECTING);
6617 void ToggleFullscreenIfNeeded()
6619 boolean change_fullscreen = (setup.fullscreen !=
6620 video.fullscreen_enabled);
6621 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6622 !strEqual(setup.fullscreen_mode,
6623 video.fullscreen_mode_current));
6625 if (!video.fullscreen_available)
6629 if (change_fullscreen || change_fullscreen_mode)
6631 if (setup.fullscreen != video.fullscreen_enabled ||
6632 setup.fullscreen_mode != video.fullscreen_mode_current)
6635 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6637 /* save backbuffer content which gets lost when toggling fullscreen mode */
6638 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6641 if (change_fullscreen_mode)
6643 if (setup.fullscreen && video.fullscreen_enabled)
6646 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6648 /* (this is now set in sdl.c) */
6650 video.fullscreen_mode_current = setup.fullscreen_mode;
6652 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6655 /* toggle fullscreen */
6656 ChangeVideoModeIfNeeded(setup.fullscreen);
6658 setup.fullscreen = video.fullscreen_enabled;
6660 /* restore backbuffer content from temporary backbuffer backup bitmap */
6661 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6663 FreeBitmap(tmp_backbuffer);
6666 /* update visible window/screen */
6667 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6669 redraw_mask = REDRAW_ALL;