1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX 0
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES 0
29 #define TOOL_CTRL_ID_NO 1
30 #define TOOL_CTRL_ID_CONFIRM 2
31 #define TOOL_CTRL_ID_PLAYER_1 3
32 #define TOOL_CTRL_ID_PLAYER_2 4
33 #define TOOL_CTRL_ID_PLAYER_3 5
34 #define TOOL_CTRL_ID_PLAYER_4 6
36 #define NUM_TOOL_BUTTONS 7
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
47 static int preview_tilesize = TILEX / 4;
49 static char *print_if_not_empty(int element)
51 static char *s = NULL;
52 char *token_name = element_info[element].token_name;
57 s = checked_malloc(strlen(token_name) + 10 + 1);
59 if (element != EL_EMPTY)
60 sprintf(s, "%d\t['%s']", element, token_name);
62 sprintf(s, "%d", element);
67 void DumpTile(int x, int y)
72 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
79 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
82 if (!IN_LEV_FIELD(x, y))
84 printf("(not in level field)\n");
90 printf(" Feld: %d\t['%s']\n", Feld[x][y],
91 element_info[Feld[x][y]].token_name);
92 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
93 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
94 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
95 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
96 printf(" MovPos: %d\n", MovPos[x][y]);
97 printf(" MovDir: %d\n", MovDir[x][y]);
98 printf(" MovDelay: %d\n", MovDelay[x][y]);
99 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
100 printf(" CustomValue: %d\n", CustomValue[x][y]);
101 printf(" GfxElement: %d\n", GfxElement[x][y]);
102 printf(" GfxAction: %d\n", GfxAction[x][y]);
103 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
107 void SetDrawtoField(int mode)
109 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
120 drawto_field = fieldbuffer;
122 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
128 BX2 = SCR_FIELDX - 1;
129 BY2 = SCR_FIELDY - 1;
133 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
137 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
139 if (game_status == GAME_MODE_PLAYING &&
140 level.game_engine_type == GAME_ENGINE_TYPE_EM)
142 /* currently there is no partial redraw -- always redraw whole playfield */
144 RedrawPlayfield_EM(TRUE);
146 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
152 width = gfx.sxsize + 2 * TILEX;
153 height = gfx.sysize + 2 * TILEY;
156 if (force_redraw || setup.direct_draw)
159 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
160 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
162 if (setup.direct_draw)
163 SetDrawtoField(DRAW_BACKBUFFER);
165 for (xx = BX1; xx <= BX2; xx++)
166 for (yy = BY1; yy <= BY2; yy++)
167 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
168 DrawScreenField(xx, yy);
171 if (setup.direct_draw)
172 SetDrawtoField(DRAW_DIRECT);
175 if (setup.soft_scrolling)
177 int fx = FX, fy = FY;
179 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
180 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
182 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
186 BlitBitmap(drawto, window, x, y, width, height, x, y);
192 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
194 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
195 redraw_mask &= ~REDRAW_MAIN;
197 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
198 redraw_mask |= REDRAW_FIELD;
200 if (redraw_mask & REDRAW_FIELD)
201 redraw_mask &= ~REDRAW_TILES;
203 if (redraw_mask == REDRAW_NONE)
206 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
208 static boolean last_frame_skipped = FALSE;
209 boolean skip_even_when_not_scrolling = TRUE;
210 boolean just_scrolling = (ScreenMovDir != 0);
211 boolean verbose = FALSE;
213 if (global.fps_slowdown_factor > 1 &&
214 (FrameCounter % global.fps_slowdown_factor) &&
215 (just_scrolling || skip_even_when_not_scrolling))
217 redraw_mask &= ~REDRAW_MAIN;
219 last_frame_skipped = TRUE;
222 printf("FRAME SKIPPED\n");
226 if (last_frame_skipped)
227 redraw_mask |= REDRAW_FIELD;
229 last_frame_skipped = FALSE;
232 printf("frame not skipped\n");
236 /* synchronize X11 graphics at this point; if we would synchronize the
237 display immediately after the buffer switching (after the XFlush),
238 this could mean that we have to wait for the graphics to complete,
239 although we could go on doing calculations for the next frame */
243 if (redraw_mask & REDRAW_ALL)
245 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
247 redraw_mask = REDRAW_NONE;
250 if (redraw_mask & REDRAW_FIELD)
252 if (game_status != GAME_MODE_PLAYING ||
253 redraw_mask & REDRAW_FROM_BACKBUFFER)
255 BlitBitmap(backbuffer, window,
256 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
260 int fx = FX, fy = FY;
262 if (setup.soft_scrolling)
264 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
265 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
268 if (setup.soft_scrolling ||
269 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
270 ABS(ScreenMovPos) == ScrollStepSize ||
271 redraw_tiles > REDRAWTILES_THRESHOLD)
273 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
277 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
279 (setup.soft_scrolling ?
280 "setup.soft_scrolling" :
281 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
282 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
283 ABS(ScreenGfxPos) == ScrollStepSize ?
284 "ABS(ScreenGfxPos) == ScrollStepSize" :
285 "redraw_tiles > REDRAWTILES_THRESHOLD"));
291 redraw_mask &= ~REDRAW_MAIN;
294 if (redraw_mask & REDRAW_DOORS)
296 if (redraw_mask & REDRAW_DOOR_1)
297 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
299 if (redraw_mask & REDRAW_DOOR_2)
300 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
302 if (redraw_mask & REDRAW_DOOR_3)
303 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
305 redraw_mask &= ~REDRAW_DOORS;
308 if (redraw_mask & REDRAW_MICROLEVEL)
310 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
311 SX, SY + 10 * TILEY);
313 redraw_mask &= ~REDRAW_MICROLEVEL;
316 if (redraw_mask & REDRAW_TILES)
318 for (x = 0; x < SCR_FIELDX; x++)
319 for (y = 0 ; y < SCR_FIELDY; y++)
320 if (redraw[redraw_x1 + x][redraw_y1 + y])
321 BlitBitmap(buffer, window,
322 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
323 SX + x * TILEX, SY + y * TILEY);
326 if (redraw_mask & REDRAW_FPS) /* display frames per second */
331 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
332 if (!global.fps_slowdown)
335 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
336 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
341 for (x = 0; x < MAX_BUF_XSIZE; x++)
342 for (y = 0; y < MAX_BUF_YSIZE; y++)
345 redraw_mask = REDRAW_NONE;
351 long fading_delay = 300;
353 if (setup.fading && (redraw_mask & REDRAW_FIELD))
360 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
363 for (i = 0; i < 2 * FULL_SYSIZE; i++)
365 for (y = 0; y < FULL_SYSIZE; y++)
367 BlitBitmap(backbuffer, window,
368 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
376 for (i = 1; i < FULL_SYSIZE; i+=2)
377 BlitBitmap(backbuffer, window,
378 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
384 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
385 BlitBitmapMasked(backbuffer, window,
386 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
391 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
392 BlitBitmapMasked(backbuffer, window,
393 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
398 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
399 BlitBitmapMasked(backbuffer, window,
400 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
405 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
406 BlitBitmapMasked(backbuffer, window,
407 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
412 redraw_mask &= ~REDRAW_MAIN;
419 void FadeIn(int fade_delay)
428 FadeScreen(NULL, FADE_MODE_FADE_IN, fade_delay, 0);
430 redraw_mask = REDRAW_NONE;
433 void FadeOut(int fade_delay, int post_delay)
437 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
443 FadeScreen(NULL, FADE_MODE_FADE_OUT, fade_delay, post_delay);
445 redraw_mask = REDRAW_NONE;
448 void FadeCross(int fade_delay)
452 BlitBitmap(bitmap_db_title, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
458 FadeScreen(bitmap_db_title, FADE_MODE_CROSSFADE, fade_delay, 0);
460 redraw_mask = REDRAW_NONE;
463 void SetMainBackgroundImageIfDefined(int graphic)
465 if (graphic_info[graphic].bitmap)
466 SetMainBackgroundImage(graphic);
469 void SetMainBackgroundImage(int graphic)
471 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
472 graphic_info[graphic].bitmap ?
473 graphic_info[graphic].bitmap :
474 graphic_info[IMG_BACKGROUND].bitmap);
477 void SetDoorBackgroundImage(int graphic)
479 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
480 graphic_info[graphic].bitmap ?
481 graphic_info[graphic].bitmap :
482 graphic_info[IMG_BACKGROUND].bitmap);
485 void DrawBackground(int dst_x, int dst_y, int width, int height)
487 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
489 redraw_mask |= REDRAW_FIELD;
494 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
496 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
498 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
499 SetDrawtoField(DRAW_BUFFERED);
502 SetDrawtoField(DRAW_BACKBUFFER);
504 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
506 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
507 SetDrawtoField(DRAW_DIRECT);
511 void MarkTileDirty(int x, int y)
513 int xx = redraw_x1 + x;
514 int yy = redraw_y1 + y;
519 redraw[xx][yy] = TRUE;
520 redraw_mask |= REDRAW_TILES;
523 void SetBorderElement()
527 BorderElement = EL_EMPTY;
529 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
531 for (x = 0; x < lev_fieldx; x++)
533 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
534 BorderElement = EL_STEELWALL;
536 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
542 void SetRandomAnimationValue(int x, int y)
544 gfx.anim_random_frame = GfxRandom[x][y];
547 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
549 /* animation synchronized with global frame counter, not move position */
550 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
551 sync_frame = FrameCounter;
554 if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
560 printf("::: FOO!\n");
564 return getAnimationFrame(graphic_info[graphic].anim_frames,
565 graphic_info[graphic].anim_delay,
566 graphic_info[graphic].anim_mode,
567 graphic_info[graphic].anim_start_frame,
571 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
572 int *x, int *y, boolean get_backside)
574 struct GraphicInfo *g = &graphic_info[graphic];
575 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
576 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
580 if (g->offset_y == 0) /* frames are ordered horizontally */
582 int max_width = g->anim_frames_per_line * g->width;
583 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
585 *x = pos % max_width;
586 *y = src_y % g->height + pos / max_width * g->height;
588 else if (g->offset_x == 0) /* frames are ordered vertically */
590 int max_height = g->anim_frames_per_line * g->height;
591 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
593 *x = src_x % g->width + pos / max_height * g->width;
594 *y = pos % max_height;
596 else /* frames are ordered diagonally */
598 *x = src_x + frame * g->offset_x;
599 *y = src_y + frame * g->offset_y;
603 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
605 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
608 void DrawGraphic(int x, int y, int graphic, int frame)
611 if (!IN_SCR_FIELD(x, y))
613 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
614 printf("DrawGraphic(): This should never happen!\n");
619 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
623 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
629 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
630 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
633 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
636 if (!IN_SCR_FIELD(x, y))
638 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
639 printf("DrawGraphicThruMask(): This should never happen!\n");
644 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
649 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
655 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
657 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
658 dst_x - src_x, dst_y - src_y);
659 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
662 void DrawMiniGraphic(int x, int y, int graphic)
664 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
665 MarkTileDirty(x / 2, y / 2);
668 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
670 struct GraphicInfo *g = &graphic_info[graphic];
672 int mini_starty = g->bitmap->height * 2 / 3;
675 *x = mini_startx + g->src_x / 2;
676 *y = mini_starty + g->src_y / 2;
679 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
684 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
685 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
688 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
689 int graphic, int frame,
690 int cut_mode, int mask_mode)
695 int width = TILEX, height = TILEY;
698 if (dx || dy) /* shifted graphic */
700 if (x < BX1) /* object enters playfield from the left */
707 else if (x > BX2) /* object enters playfield from the right */
713 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
719 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
721 else if (dx) /* general horizontal movement */
722 MarkTileDirty(x + SIGN(dx), y);
724 if (y < BY1) /* object enters playfield from the top */
726 if (cut_mode==CUT_BELOW) /* object completely above top border */
734 else if (y > BY2) /* object enters playfield from the bottom */
740 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
746 else if (dy > 0 && cut_mode == CUT_ABOVE)
748 if (y == BY2) /* object completely above bottom border */
754 MarkTileDirty(x, y + 1);
755 } /* object leaves playfield to the bottom */
756 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
758 else if (dy) /* general vertical movement */
759 MarkTileDirty(x, y + SIGN(dy));
763 if (!IN_SCR_FIELD(x, y))
765 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
766 printf("DrawGraphicShifted(): This should never happen!\n");
771 if (width > 0 && height > 0)
773 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
778 dst_x = FX + x * TILEX + dx;
779 dst_y = FY + y * TILEY + dy;
781 if (mask_mode == USE_MASKING)
783 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
784 dst_x - src_x, dst_y - src_y);
785 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
789 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
796 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
797 int graphic, int frame,
798 int cut_mode, int mask_mode)
803 int width = TILEX, height = TILEY;
806 int x2 = x + SIGN(dx);
807 int y2 = y + SIGN(dy);
808 int anim_frames = graphic_info[graphic].anim_frames;
809 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
810 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
811 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
813 /* re-calculate animation frame for two-tile movement animation */
814 frame = getGraphicAnimationFrame(graphic, sync_frame);
816 /* check if movement start graphic inside screen area and should be drawn */
817 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
819 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
821 dst_x = FX + x1 * TILEX;
822 dst_y = FY + y1 * TILEY;
824 if (mask_mode == USE_MASKING)
826 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
827 dst_x - src_x, dst_y - src_y);
828 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
832 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
835 MarkTileDirty(x1, y1);
838 /* check if movement end graphic inside screen area and should be drawn */
839 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
841 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
843 dst_x = FX + x2 * TILEX;
844 dst_y = FY + y2 * TILEY;
846 if (mask_mode == USE_MASKING)
848 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
849 dst_x - src_x, dst_y - src_y);
850 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
854 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
857 MarkTileDirty(x2, y2);
861 static void DrawGraphicShifted(int x, int y, int dx, int dy,
862 int graphic, int frame,
863 int cut_mode, int mask_mode)
867 DrawGraphic(x, y, graphic, frame);
872 if (graphic_info[graphic].double_movement) /* EM style movement images */
873 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
875 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
878 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
879 int frame, int cut_mode)
881 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
884 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
885 int cut_mode, int mask_mode)
887 int lx = LEVELX(x), ly = LEVELY(y);
891 if (IN_LEV_FIELD(lx, ly))
893 SetRandomAnimationValue(lx, ly);
895 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
896 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
898 /* do not use double (EM style) movement graphic when not moving */
899 if (graphic_info[graphic].double_movement && !dx && !dy)
901 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
902 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
905 else /* border element */
907 graphic = el2img(element);
908 frame = getGraphicAnimationFrame(graphic, -1);
911 if (element == EL_EXPANDABLE_WALL)
913 boolean left_stopped = FALSE, right_stopped = FALSE;
915 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
917 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
918 right_stopped = TRUE;
920 if (left_stopped && right_stopped)
922 else if (left_stopped)
924 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
925 frame = graphic_info[graphic].anim_frames - 1;
927 else if (right_stopped)
929 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
930 frame = graphic_info[graphic].anim_frames - 1;
935 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
936 else if (mask_mode == USE_MASKING)
937 DrawGraphicThruMask(x, y, graphic, frame);
939 DrawGraphic(x, y, graphic, frame);
942 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
943 int cut_mode, int mask_mode)
945 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
946 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
947 cut_mode, mask_mode);
950 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
953 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
956 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
959 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
962 void DrawLevelElementThruMask(int x, int y, int element)
964 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
967 void DrawLevelFieldThruMask(int x, int y)
969 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
972 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
976 int sx = SCREENX(x), sy = SCREENY(y);
978 int width, height, cx, cy, i;
979 int crumbled_border_size = graphic_info[graphic].border_size;
980 static int xy[4][2] =
988 if (!IN_LEV_FIELD(x, y))
991 element = TILE_GFX_ELEMENT(x, y);
993 /* crumble field itself */
994 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
996 if (!IN_SCR_FIELD(sx, sy))
999 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1001 for (i = 0; i < 4; i++)
1003 int xx = x + xy[i][0];
1004 int yy = y + xy[i][1];
1006 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1009 /* check if neighbour field is of same type */
1010 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1013 if (i == 1 || i == 2)
1015 width = crumbled_border_size;
1017 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1023 height = crumbled_border_size;
1025 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1028 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1029 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1032 MarkTileDirty(sx, sy);
1034 else /* crumble neighbour fields */
1036 for (i = 0; i < 4; i++)
1038 int xx = x + xy[i][0];
1039 int yy = y + xy[i][1];
1040 int sxx = sx + xy[i][0];
1041 int syy = sy + xy[i][1];
1044 if (!IN_LEV_FIELD(xx, yy) ||
1045 !IN_SCR_FIELD(sxx, syy) ||
1050 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1054 element = TILE_GFX_ELEMENT(xx, yy);
1056 if (!GFX_CRUMBLED(element))
1059 if (!IN_LEV_FIELD(xx, yy) ||
1060 !IN_SCR_FIELD(sxx, syy) ||
1061 !GFX_CRUMBLED(Feld[xx][yy]) ||
1067 graphic = el_act2crm(element, ACTION_DEFAULT);
1069 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1071 crumbled_border_size = graphic_info[graphic].border_size;
1073 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1075 if (i == 1 || i == 2)
1077 width = crumbled_border_size;
1079 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1085 height = crumbled_border_size;
1087 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1090 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1091 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1093 MarkTileDirty(sxx, syy);
1098 void DrawLevelFieldCrumbledSand(int x, int y)
1102 if (!IN_LEV_FIELD(x, y))
1106 /* !!! CHECK THIS !!! */
1109 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1110 GFX_CRUMBLED(GfxElement[x][y]))
1113 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1114 GfxElement[x][y] != EL_UNDEFINED &&
1115 GFX_CRUMBLED(GfxElement[x][y]))
1117 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1124 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1126 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1129 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1132 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1135 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1136 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1137 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1138 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1139 int sx = SCREENX(x), sy = SCREENY(y);
1141 DrawGraphic(sx, sy, graphic1, frame1);
1142 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1145 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1147 int sx = SCREENX(x), sy = SCREENY(y);
1148 static int xy[4][2] =
1157 for (i = 0; i < 4; i++)
1159 int xx = x + xy[i][0];
1160 int yy = y + xy[i][1];
1161 int sxx = sx + xy[i][0];
1162 int syy = sy + xy[i][1];
1164 if (!IN_LEV_FIELD(xx, yy) ||
1165 !IN_SCR_FIELD(sxx, syy) ||
1166 !GFX_CRUMBLED(Feld[xx][yy]) ||
1170 DrawLevelField(xx, yy);
1174 static int getBorderElement(int x, int y)
1178 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1179 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1180 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1181 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1182 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1183 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1184 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1186 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1187 int steel_position = (x == -1 && y == -1 ? 0 :
1188 x == lev_fieldx && y == -1 ? 1 :
1189 x == -1 && y == lev_fieldy ? 2 :
1190 x == lev_fieldx && y == lev_fieldy ? 3 :
1191 x == -1 || x == lev_fieldx ? 4 :
1192 y == -1 || y == lev_fieldy ? 5 : 6);
1194 return border[steel_position][steel_type];
1197 void DrawScreenElement(int x, int y, int element)
1199 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1200 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1203 void DrawLevelElement(int x, int y, int element)
1205 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1206 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1209 void DrawScreenField(int x, int y)
1211 int lx = LEVELX(x), ly = LEVELY(y);
1212 int element, content;
1214 if (!IN_LEV_FIELD(lx, ly))
1216 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1219 element = getBorderElement(lx, ly);
1221 DrawScreenElement(x, y, element);
1225 element = Feld[lx][ly];
1226 content = Store[lx][ly];
1228 if (IS_MOVING(lx, ly))
1230 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1231 boolean cut_mode = NO_CUTTING;
1233 if (element == EL_QUICKSAND_EMPTYING ||
1234 element == EL_MAGIC_WALL_EMPTYING ||
1235 element == EL_BD_MAGIC_WALL_EMPTYING ||
1236 element == EL_AMOEBA_DROPPING)
1237 cut_mode = CUT_ABOVE;
1238 else if (element == EL_QUICKSAND_FILLING ||
1239 element == EL_MAGIC_WALL_FILLING ||
1240 element == EL_BD_MAGIC_WALL_FILLING)
1241 cut_mode = CUT_BELOW;
1243 if (cut_mode == CUT_ABOVE)
1244 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1246 DrawScreenElement(x, y, EL_EMPTY);
1249 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1250 else if (cut_mode == NO_CUTTING)
1251 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1253 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1255 if (content == EL_ACID)
1257 int dir = MovDir[lx][ly];
1258 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1259 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1261 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1264 else if (IS_BLOCKED(lx, ly))
1269 boolean cut_mode = NO_CUTTING;
1270 int element_old, content_old;
1272 Blocked2Moving(lx, ly, &oldx, &oldy);
1275 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1276 MovDir[oldx][oldy] == MV_RIGHT);
1278 element_old = Feld[oldx][oldy];
1279 content_old = Store[oldx][oldy];
1281 if (element_old == EL_QUICKSAND_EMPTYING ||
1282 element_old == EL_MAGIC_WALL_EMPTYING ||
1283 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1284 element_old == EL_AMOEBA_DROPPING)
1285 cut_mode = CUT_ABOVE;
1287 DrawScreenElement(x, y, EL_EMPTY);
1290 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1292 else if (cut_mode == NO_CUTTING)
1293 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1296 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1299 else if (IS_DRAWABLE(element))
1300 DrawScreenElement(x, y, element);
1302 DrawScreenElement(x, y, EL_EMPTY);
1305 void DrawLevelField(int x, int y)
1307 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1308 DrawScreenField(SCREENX(x), SCREENY(y));
1309 else if (IS_MOVING(x, y))
1313 Moving2Blocked(x, y, &newx, &newy);
1314 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1315 DrawScreenField(SCREENX(newx), SCREENY(newy));
1317 else if (IS_BLOCKED(x, y))
1321 Blocked2Moving(x, y, &oldx, &oldy);
1322 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1323 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1327 void DrawMiniElement(int x, int y, int element)
1331 graphic = el2edimg(element);
1332 DrawMiniGraphic(x, y, graphic);
1335 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1337 int x = sx + scroll_x, y = sy + scroll_y;
1339 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1340 DrawMiniElement(sx, sy, EL_EMPTY);
1341 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1342 DrawMiniElement(sx, sy, Feld[x][y]);
1344 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1347 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1348 int x, int y, int xsize, int ysize, int font_nr)
1350 int font_width = getFontWidth(font_nr);
1351 int font_height = getFontHeight(font_nr);
1352 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1355 int dst_x = SX + startx + x * font_width;
1356 int dst_y = SY + starty + y * font_height;
1357 int width = graphic_info[graphic].width;
1358 int height = graphic_info[graphic].height;
1359 int inner_width = MAX(width - 2 * font_width, font_width);
1360 int inner_height = MAX(height - 2 * font_height, font_height);
1361 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1362 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1363 boolean draw_masked = graphic_info[graphic].draw_masked;
1365 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1367 if (src_bitmap == NULL || width < font_width || height < font_height)
1369 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1373 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1374 inner_sx + (x - 1) * font_width % inner_width);
1375 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1376 inner_sy + (y - 1) * font_height % inner_height);
1380 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1381 dst_x - src_x, dst_y - src_y);
1382 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1386 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1390 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1392 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1393 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1394 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1395 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1396 boolean no_delay = (tape.warp_forward);
1397 unsigned long anim_delay = 0;
1398 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1399 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1400 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1401 int font_width = getFontWidth(font_nr);
1402 int font_height = getFontHeight(font_nr);
1403 int max_xsize = level.envelope[envelope_nr].xsize;
1404 int max_ysize = level.envelope[envelope_nr].ysize;
1405 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1406 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1407 int xend = max_xsize;
1408 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1409 int xstep = (xstart < xend ? 1 : 0);
1410 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1413 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1415 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1416 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1417 int sx = (SXSIZE - xsize * font_width) / 2;
1418 int sy = (SYSIZE - ysize * font_height) / 2;
1421 SetDrawtoField(DRAW_BUFFERED);
1423 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1425 SetDrawtoField(DRAW_BACKBUFFER);
1427 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1428 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1430 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1431 level.envelope[envelope_nr].text, font_nr, max_xsize,
1432 xsize - 2, ysize - 2, mask_mode);
1434 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1437 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1441 void ShowEnvelope(int envelope_nr)
1443 int element = EL_ENVELOPE_1 + envelope_nr;
1444 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1445 int sound_opening = element_info[element].sound[ACTION_OPENING];
1446 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1447 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1448 boolean no_delay = (tape.warp_forward);
1449 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1450 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1451 int anim_mode = graphic_info[graphic].anim_mode;
1452 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1453 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1455 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1457 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1459 if (anim_mode == ANIM_DEFAULT)
1460 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1462 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1465 Delay(wait_delay_value);
1467 WaitForEventToContinue();
1469 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1471 if (anim_mode != ANIM_NONE)
1472 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1474 if (anim_mode == ANIM_DEFAULT)
1475 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1477 game.envelope_active = FALSE;
1479 SetDrawtoField(DRAW_BUFFERED);
1481 redraw_mask |= REDRAW_FIELD;
1485 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1487 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1488 int mini_startx = src_bitmap->width * 3 / 4;
1489 int mini_starty = src_bitmap->height * 2 / 3;
1490 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1491 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1493 *bitmap = src_bitmap;
1498 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1503 int width_mult, width_div;
1504 int height_mult, height_div;
1512 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1513 5 - log_2(tilesize));
1514 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1515 int width_mult = offset_calc[offset_calc_pos].width_mult;
1516 int width_div = offset_calc[offset_calc_pos].width_div;
1517 int height_mult = offset_calc[offset_calc_pos].height_mult;
1518 int height_div = offset_calc[offset_calc_pos].height_div;
1519 int mini_startx = src_bitmap->width * width_mult / width_div;
1520 int mini_starty = src_bitmap->height * height_mult / height_div;
1521 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1522 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1524 *bitmap = src_bitmap;
1529 void DrawMicroElement(int xpos, int ypos, int element)
1533 int graphic = el2preimg(element);
1535 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1536 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1540 void DrawPreviewElement(int xpos, int ypos, int element, int tilesize)
1544 int graphic = el2preimg(element);
1546 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1547 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, xpos, ypos);
1554 SetDrawBackgroundMask(REDRAW_NONE);
1557 for (x = BX1; x <= BX2; x++)
1558 for (y = BY1; y <= BY2; y++)
1559 DrawScreenField(x, y);
1561 redraw_mask |= REDRAW_FIELD;
1564 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1568 for (x = 0; x < size_x; x++)
1569 for (y = 0; y < size_y; y++)
1570 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1572 redraw_mask |= REDRAW_FIELD;
1575 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1577 boolean show_level_border = (BorderElement != EL_EMPTY);
1578 int level_size_x = lev_fieldx + (show_level_border ? 2 : 0);
1579 int level_size_y = lev_fieldy + (show_level_border ? 2 : 0);
1580 int preview_size_x = MICROLEVEL_XSIZE / preview_tilesize;
1581 int preview_size_y = MICROLEVEL_YSIZE / preview_tilesize;
1582 int real_preview_size_x = MIN(level_size_x, preview_size_x);
1583 int real_preview_size_y = MIN(level_size_y, preview_size_y);
1586 DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
1588 xpos += (MICROLEVEL_XSIZE - real_preview_size_x * preview_tilesize) / 2;
1589 ypos += (MICROLEVEL_YSIZE - real_preview_size_y * preview_tilesize) / 2;
1591 for (x = 0; x < real_preview_size_x; x++)
1593 for (y = 0; y < real_preview_size_y; y++)
1595 int lx = from_x + x + (show_level_border ? -1 : 0);
1596 int ly = from_y + y + (show_level_border ? -1 : 0);
1597 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1598 getBorderElement(lx, ly));
1600 DrawPreviewElement(xpos + x * preview_tilesize,
1601 ypos + y * preview_tilesize,
1602 element, preview_tilesize);
1606 redraw_mask |= REDRAW_MICROLEVEL;
1609 #define MICROLABEL_EMPTY 0
1610 #define MICROLABEL_LEVEL_NAME 1
1611 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1612 #define MICROLABEL_LEVEL_AUTHOR 3
1613 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1614 #define MICROLABEL_IMPORTED_FROM 5
1615 #define MICROLABEL_IMPORTED_BY_HEAD 6
1616 #define MICROLABEL_IMPORTED_BY 7
1618 static void DrawMicroLevelLabelExt(int mode)
1620 char label_text[MAX_OUTPUT_LINESIZE + 1];
1621 int max_len_label_text;
1622 int font_nr = FONT_TEXT_2;
1625 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1626 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1627 mode == MICROLABEL_IMPORTED_BY_HEAD)
1628 font_nr = FONT_TEXT_3;
1630 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1632 for (i = 0; i < max_len_label_text; i++)
1633 label_text[i] = ' ';
1634 label_text[max_len_label_text] = '\0';
1636 if (strlen(label_text) > 0)
1638 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1639 int lypos = MICROLABEL2_YPOS;
1641 DrawText(lxpos, lypos, label_text, font_nr);
1645 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1646 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1647 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1648 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1649 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1650 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1651 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1652 max_len_label_text);
1653 label_text[max_len_label_text] = '\0';
1655 if (strlen(label_text) > 0)
1657 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1658 int lypos = MICROLABEL2_YPOS;
1660 DrawText(lxpos, lypos, label_text, font_nr);
1663 redraw_mask |= REDRAW_MICROLEVEL;
1666 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1668 static unsigned long scroll_delay = 0;
1669 static unsigned long label_delay = 0;
1670 static int from_x, from_y, scroll_direction;
1671 static int label_state, label_counter;
1672 int delay_factor = preview_tilesize / MICRO_TILESIZE;
1673 unsigned long scroll_delay_value = MICROLEVEL_SCROLL_DELAY * delay_factor;
1674 boolean show_level_border = (BorderElement != EL_EMPTY);
1675 int level_size_x = lev_fieldx + (show_level_border ? 2 : 0);
1676 int level_size_y = lev_fieldy + (show_level_border ? 2 : 0);
1677 int preview_size_x = MICROLEVEL_XSIZE / preview_tilesize;
1678 int preview_size_y = MICROLEVEL_YSIZE / preview_tilesize;
1679 int last_game_status = game_status; /* save current game status */
1681 /* force PREVIEW font on preview level */
1682 game_status = GAME_MODE_PSEUDO_PREVIEW;
1686 from_x = from_y = 0;
1687 scroll_direction = MV_RIGHT;
1691 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1692 DrawMicroLevelLabelExt(label_state);
1694 /* initialize delay counters */
1695 DelayReached(&scroll_delay, 0);
1696 DelayReached(&label_delay, 0);
1698 if (leveldir_current->name)
1700 char label_text[MAX_OUTPUT_LINESIZE + 1];
1701 int font_nr = FONT_TEXT_1;
1702 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1705 strncpy(label_text, leveldir_current->name, max_len_label_text);
1706 label_text[max_len_label_text] = '\0';
1708 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1709 lypos = SY + MICROLABEL1_YPOS;
1711 DrawText(lxpos, lypos, label_text, font_nr);
1714 game_status = last_game_status; /* restore current game status */
1719 /* scroll micro level, if needed */
1720 if ((level_size_x > preview_size_x || level_size_y > preview_size_y) &&
1721 DelayReached(&scroll_delay, scroll_delay_value))
1723 switch (scroll_direction)
1729 scroll_direction = MV_UP;
1733 if (from_x < level_size_x - preview_size_x)
1736 scroll_direction = MV_DOWN;
1743 scroll_direction = MV_RIGHT;
1747 if (from_y < level_size_y - preview_size_y)
1750 scroll_direction = MV_LEFT;
1757 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1760 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1761 /* redraw micro level label, if needed */
1762 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1763 !strEqual(level.author, ANONYMOUS_NAME) &&
1764 !strEqual(level.author, leveldir_current->name) &&
1765 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1767 int max_label_counter = 23;
1769 if (leveldir_current->imported_from != NULL &&
1770 strlen(leveldir_current->imported_from) > 0)
1771 max_label_counter += 14;
1772 if (leveldir_current->imported_by != NULL &&
1773 strlen(leveldir_current->imported_by) > 0)
1774 max_label_counter += 14;
1776 label_counter = (label_counter + 1) % max_label_counter;
1777 label_state = (label_counter >= 0 && label_counter <= 7 ?
1778 MICROLABEL_LEVEL_NAME :
1779 label_counter >= 9 && label_counter <= 12 ?
1780 MICROLABEL_LEVEL_AUTHOR_HEAD :
1781 label_counter >= 14 && label_counter <= 21 ?
1782 MICROLABEL_LEVEL_AUTHOR :
1783 label_counter >= 23 && label_counter <= 26 ?
1784 MICROLABEL_IMPORTED_FROM_HEAD :
1785 label_counter >= 28 && label_counter <= 35 ?
1786 MICROLABEL_IMPORTED_FROM :
1787 label_counter >= 37 && label_counter <= 40 ?
1788 MICROLABEL_IMPORTED_BY_HEAD :
1789 label_counter >= 42 && label_counter <= 49 ?
1790 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1792 if (leveldir_current->imported_from == NULL &&
1793 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1794 label_state == MICROLABEL_IMPORTED_FROM))
1795 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1796 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1798 DrawMicroLevelLabelExt(label_state);
1801 game_status = last_game_status; /* restore current game status */
1804 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1805 int graphic, int sync_frame, int mask_mode)
1807 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1809 if (mask_mode == USE_MASKING)
1810 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1812 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1815 inline void DrawGraphicAnimation(int x, int y, int graphic)
1817 int lx = LEVELX(x), ly = LEVELY(y);
1819 if (!IN_SCR_FIELD(x, y))
1822 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1823 graphic, GfxFrame[lx][ly], NO_MASKING);
1824 MarkTileDirty(x, y);
1827 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1829 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1832 void DrawLevelElementAnimation(int x, int y, int element)
1834 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1836 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1839 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1841 int sx = SCREENX(x), sy = SCREENY(y);
1843 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1846 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1849 DrawGraphicAnimation(sx, sy, graphic);
1852 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1853 DrawLevelFieldCrumbledSand(x, y);
1855 if (GFX_CRUMBLED(Feld[x][y]))
1856 DrawLevelFieldCrumbledSand(x, y);
1860 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1862 int sx = SCREENX(x), sy = SCREENY(y);
1865 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1868 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1870 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1873 DrawGraphicAnimation(sx, sy, graphic);
1875 if (GFX_CRUMBLED(element))
1876 DrawLevelFieldCrumbledSand(x, y);
1879 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1881 if (player->use_murphy)
1883 /* this works only because currently only one player can be "murphy" ... */
1884 static int last_horizontal_dir = MV_LEFT;
1885 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1887 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1888 last_horizontal_dir = move_dir;
1890 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1892 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1894 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1900 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1903 static boolean equalGraphics(int graphic1, int graphic2)
1905 struct GraphicInfo *g1 = &graphic_info[graphic1];
1906 struct GraphicInfo *g2 = &graphic_info[graphic2];
1908 return (g1->bitmap == g2->bitmap &&
1909 g1->src_x == g2->src_x &&
1910 g1->src_y == g2->src_y &&
1911 g1->anim_frames == g2->anim_frames &&
1912 g1->anim_delay == g2->anim_delay &&
1913 g1->anim_mode == g2->anim_mode);
1916 void DrawAllPlayers()
1920 for (i = 0; i < MAX_PLAYERS; i++)
1921 if (stored_player[i].active)
1922 DrawPlayer(&stored_player[i]);
1925 void DrawPlayerField(int x, int y)
1927 if (!IS_PLAYER(x, y))
1930 DrawPlayer(PLAYERINFO(x, y));
1933 void DrawPlayer(struct PlayerInfo *player)
1935 int jx = player->jx;
1936 int jy = player->jy;
1937 int move_dir = player->MovDir;
1938 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1939 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1940 int last_jx = (player->is_moving ? jx - dx : jx);
1941 int last_jy = (player->is_moving ? jy - dy : jy);
1942 int next_jx = jx + dx;
1943 int next_jy = jy + dy;
1944 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1945 boolean player_is_opaque = FALSE;
1946 int sx = SCREENX(jx), sy = SCREENY(jy);
1947 int sxx = 0, syy = 0;
1948 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1950 int action = ACTION_DEFAULT;
1951 int last_player_graphic = getPlayerGraphic(player, move_dir);
1952 int last_player_frame = player->Frame;
1956 /* GfxElement[][] is set to the element the player is digging or collecting;
1957 remove also for off-screen player if the player is not moving anymore */
1958 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1959 GfxElement[jx][jy] = EL_UNDEFINED;
1962 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1966 if (!IN_LEV_FIELD(jx, jy))
1968 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1969 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1970 printf("DrawPlayerField(): This should never happen!\n");
1975 if (element == EL_EXPLOSION)
1978 action = (player->is_pushing ? ACTION_PUSHING :
1979 player->is_digging ? ACTION_DIGGING :
1980 player->is_collecting ? ACTION_COLLECTING :
1981 player->is_moving ? ACTION_MOVING :
1982 player->is_snapping ? ACTION_SNAPPING :
1983 player->is_dropping ? ACTION_DROPPING :
1984 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1987 if (player->is_waiting)
1988 move_dir = player->dir_waiting;
1991 InitPlayerGfxAnimation(player, action, move_dir);
1993 /* ----------------------------------------------------------------------- */
1994 /* draw things in the field the player is leaving, if needed */
1995 /* ----------------------------------------------------------------------- */
1997 if (player->is_moving)
1999 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2001 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2003 if (last_element == EL_DYNAMITE_ACTIVE ||
2004 last_element == EL_EM_DYNAMITE_ACTIVE ||
2005 last_element == EL_SP_DISK_RED_ACTIVE)
2006 DrawDynamite(last_jx, last_jy);
2008 DrawLevelFieldThruMask(last_jx, last_jy);
2010 else if (last_element == EL_DYNAMITE_ACTIVE ||
2011 last_element == EL_EM_DYNAMITE_ACTIVE ||
2012 last_element == EL_SP_DISK_RED_ACTIVE)
2013 DrawDynamite(last_jx, last_jy);
2015 /* !!! this is not enough to prevent flickering of players which are
2016 moving next to each others without a free tile between them -- this
2017 can only be solved by drawing all players layer by layer (first the
2018 background, then the foreground etc.) !!! => TODO */
2019 else if (!IS_PLAYER(last_jx, last_jy))
2020 DrawLevelField(last_jx, last_jy);
2023 DrawLevelField(last_jx, last_jy);
2026 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2027 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2030 if (!IN_SCR_FIELD(sx, sy))
2033 if (setup.direct_draw)
2034 SetDrawtoField(DRAW_BUFFERED);
2036 /* ----------------------------------------------------------------------- */
2037 /* draw things behind the player, if needed */
2038 /* ----------------------------------------------------------------------- */
2041 DrawLevelElement(jx, jy, Back[jx][jy]);
2042 else if (IS_ACTIVE_BOMB(element))
2043 DrawLevelElement(jx, jy, EL_EMPTY);
2046 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2048 int old_element = GfxElement[jx][jy];
2049 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2050 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2052 if (GFX_CRUMBLED(old_element))
2053 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2055 DrawGraphic(sx, sy, old_graphic, frame);
2057 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2058 player_is_opaque = TRUE;
2062 GfxElement[jx][jy] = EL_UNDEFINED;
2064 /* make sure that pushed elements are drawn with correct frame rate */
2065 if (player->is_pushing && player->is_moving)
2066 GfxFrame[jx][jy] = player->StepFrame;
2068 DrawLevelField(jx, jy);
2072 /* ----------------------------------------------------------------------- */
2073 /* draw player himself */
2074 /* ----------------------------------------------------------------------- */
2076 graphic = getPlayerGraphic(player, move_dir);
2078 /* in the case of changed player action or direction, prevent the current
2079 animation frame from being restarted for identical animations */
2080 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2081 player->Frame = last_player_frame;
2083 frame = getGraphicAnimationFrame(graphic, player->Frame);
2087 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2088 sxx = player->GfxPos;
2090 syy = player->GfxPos;
2093 if (!setup.soft_scrolling && ScreenMovPos)
2096 if (player_is_opaque)
2097 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2099 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2101 if (SHIELD_ON(player))
2103 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2104 IMG_SHIELD_NORMAL_ACTIVE);
2105 int frame = getGraphicAnimationFrame(graphic, -1);
2107 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2110 /* ----------------------------------------------------------------------- */
2111 /* draw things the player is pushing, if needed */
2112 /* ----------------------------------------------------------------------- */
2115 printf("::: %d, %d [%d, %d] [%d]\n",
2116 player->is_pushing, player_is_moving, player->GfxAction,
2117 player->is_moving, player_is_moving);
2121 if (player->is_pushing && player->is_moving)
2123 int px = SCREENX(jx), py = SCREENY(jy);
2124 int pxx = (TILEX - ABS(sxx)) * dx;
2125 int pyy = (TILEY - ABS(syy)) * dy;
2130 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2131 element = Feld[next_jx][next_jy];
2133 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2134 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2136 /* draw background element under pushed element (like the Sokoban field) */
2137 if (Back[next_jx][next_jy])
2138 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2140 /* masked drawing is needed for EMC style (double) movement graphics */
2141 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2145 /* ----------------------------------------------------------------------- */
2146 /* draw things in front of player (active dynamite or dynabombs) */
2147 /* ----------------------------------------------------------------------- */
2149 if (IS_ACTIVE_BOMB(element))
2151 graphic = el2img(element);
2152 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2154 if (game.emulation == EMU_SUPAPLEX)
2155 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2157 DrawGraphicThruMask(sx, sy, graphic, frame);
2160 if (player_is_moving && last_element == EL_EXPLOSION)
2162 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2163 GfxElement[last_jx][last_jy] : EL_EMPTY);
2164 int graphic = el_act2img(element, ACTION_EXPLODING);
2165 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2166 int phase = ExplodePhase[last_jx][last_jy] - 1;
2167 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2170 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2173 /* ----------------------------------------------------------------------- */
2174 /* draw elements the player is just walking/passing through/under */
2175 /* ----------------------------------------------------------------------- */
2177 if (player_is_moving)
2179 /* handle the field the player is leaving ... */
2180 if (IS_ACCESSIBLE_INSIDE(last_element))
2181 DrawLevelField(last_jx, last_jy);
2182 else if (IS_ACCESSIBLE_UNDER(last_element))
2183 DrawLevelFieldThruMask(last_jx, last_jy);
2186 /* do not redraw accessible elements if the player is just pushing them */
2187 if (!player_is_moving || !player->is_pushing)
2189 /* ... and the field the player is entering */
2190 if (IS_ACCESSIBLE_INSIDE(element))
2191 DrawLevelField(jx, jy);
2192 else if (IS_ACCESSIBLE_UNDER(element))
2193 DrawLevelFieldThruMask(jx, jy);
2196 if (setup.direct_draw)
2198 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2199 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2200 int x_size = TILEX * (1 + ABS(jx - last_jx));
2201 int y_size = TILEY * (1 + ABS(jy - last_jy));
2203 BlitBitmap(drawto_field, window,
2204 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2205 SetDrawtoField(DRAW_DIRECT);
2208 MarkTileDirty(sx, sy);
2211 /* ------------------------------------------------------------------------- */
2213 void WaitForEventToContinue()
2215 boolean still_wait = TRUE;
2217 /* simulate releasing mouse button over last gadget, if still pressed */
2219 HandleGadgets(-1, -1, 0);
2221 button_status = MB_RELEASED;
2233 case EVENT_BUTTONPRESS:
2234 case EVENT_KEYPRESS:
2238 case EVENT_KEYRELEASE:
2239 ClearPlayerAction();
2243 HandleOtherEvents(&event);
2247 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2254 /* don't eat all CPU time */
2259 #define MAX_REQUEST_LINES 13
2260 #define MAX_REQUEST_LINE_FONT1_LEN 7
2261 #define MAX_REQUEST_LINE_FONT2_LEN 10
2263 boolean Request(char *text, unsigned int req_state)
2265 int mx, my, ty, result = -1;
2266 unsigned int old_door_state;
2267 int last_game_status = game_status; /* save current game status */
2268 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2269 int font_nr = FONT_TEXT_2;
2270 int max_word_len = 0;
2273 for (text_ptr = text; *text_ptr; text_ptr++)
2275 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2277 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2279 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2280 font_nr = FONT_LEVEL_NUMBER;
2286 if (game_status == GAME_MODE_PLAYING &&
2287 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2288 BlitScreenToBitmap_EM(backbuffer);
2290 /* disable deactivated drawing when quick-loading level tape recording */
2291 if (tape.playing && tape.deactivate_display)
2292 TapeDeactivateDisplayOff(TRUE);
2294 SetMouseCursor(CURSOR_DEFAULT);
2296 #if defined(NETWORK_AVALIABLE)
2297 /* pause network game while waiting for request to answer */
2298 if (options.network &&
2299 game_status == GAME_MODE_PLAYING &&
2300 req_state & REQUEST_WAIT_FOR_INPUT)
2301 SendToServer_PausePlaying();
2304 old_door_state = GetDoorState();
2306 /* simulate releasing mouse button over last gadget, if still pressed */
2308 HandleGadgets(-1, -1, 0);
2312 if (old_door_state & DOOR_OPEN_1)
2314 CloseDoor(DOOR_CLOSE_1);
2316 /* save old door content */
2317 BlitBitmap(bitmap_db_door, bitmap_db_door,
2318 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2319 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2322 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2324 /* clear door drawing field */
2325 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2327 /* force DOOR font on preview level */
2328 game_status = GAME_MODE_PSEUDO_DOOR;
2330 /* write text for request */
2331 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2333 char text_line[max_request_line_len + 1];
2339 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2342 if (!tc || tc == ' ')
2353 strncpy(text_line, text, tl);
2356 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2357 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2358 text_line, font_nr);
2360 text += tl + (tc == ' ' ? 1 : 0);
2363 game_status = last_game_status; /* restore current game status */
2365 if (req_state & REQ_ASK)
2367 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2368 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2370 else if (req_state & REQ_CONFIRM)
2372 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2374 else if (req_state & REQ_PLAYER)
2376 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2377 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2378 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2379 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2382 /* copy request gadgets to door backbuffer */
2383 BlitBitmap(drawto, bitmap_db_door,
2384 DX, DY, DXSIZE, DYSIZE,
2385 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2387 OpenDoor(DOOR_OPEN_1);
2389 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2391 SetDrawBackgroundMask(REDRAW_FIELD);
2396 if (game_status != GAME_MODE_MAIN)
2399 button_status = MB_RELEASED;
2401 request_gadget_id = -1;
2403 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2415 case EVENT_BUTTONPRESS:
2416 case EVENT_BUTTONRELEASE:
2417 case EVENT_MOTIONNOTIFY:
2419 if (event.type == EVENT_MOTIONNOTIFY)
2421 if (!PointerInWindow(window))
2422 continue; /* window and pointer are on different screens */
2427 motion_status = TRUE;
2428 mx = ((MotionEvent *) &event)->x;
2429 my = ((MotionEvent *) &event)->y;
2433 motion_status = FALSE;
2434 mx = ((ButtonEvent *) &event)->x;
2435 my = ((ButtonEvent *) &event)->y;
2436 if (event.type == EVENT_BUTTONPRESS)
2437 button_status = ((ButtonEvent *) &event)->button;
2439 button_status = MB_RELEASED;
2442 /* this sets 'request_gadget_id' */
2443 HandleGadgets(mx, my, button_status);
2445 switch(request_gadget_id)
2447 case TOOL_CTRL_ID_YES:
2450 case TOOL_CTRL_ID_NO:
2453 case TOOL_CTRL_ID_CONFIRM:
2454 result = TRUE | FALSE;
2457 case TOOL_CTRL_ID_PLAYER_1:
2460 case TOOL_CTRL_ID_PLAYER_2:
2463 case TOOL_CTRL_ID_PLAYER_3:
2466 case TOOL_CTRL_ID_PLAYER_4:
2477 case EVENT_KEYPRESS:
2478 switch(GetEventKey((KeyEvent *)&event, TRUE))
2491 if (req_state & REQ_PLAYER)
2495 case EVENT_KEYRELEASE:
2496 ClearPlayerAction();
2500 HandleOtherEvents(&event);
2504 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2506 int joy = AnyJoystick();
2508 if (joy & JOY_BUTTON_1)
2510 else if (joy & JOY_BUTTON_2)
2516 /* don't eat all CPU time */
2520 if (game_status != GAME_MODE_MAIN)
2525 if (!(req_state & REQ_STAY_OPEN))
2527 CloseDoor(DOOR_CLOSE_1);
2529 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2530 (req_state & REQ_REOPEN))
2531 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2536 SetDrawBackgroundMask(REDRAW_FIELD);
2538 #if defined(NETWORK_AVALIABLE)
2539 /* continue network game after request */
2540 if (options.network &&
2541 game_status == GAME_MODE_PLAYING &&
2542 req_state & REQUEST_WAIT_FOR_INPUT)
2543 SendToServer_ContinuePlaying();
2546 /* restore deactivated drawing when quick-loading level tape recording */
2547 if (tape.playing && tape.deactivate_display)
2548 TapeDeactivateDisplayOn();
2553 unsigned int OpenDoor(unsigned int door_state)
2555 if (door_state & DOOR_COPY_BACK)
2557 if (door_state & DOOR_OPEN_1)
2558 BlitBitmap(bitmap_db_door, bitmap_db_door,
2559 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2560 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2562 if (door_state & DOOR_OPEN_2)
2563 BlitBitmap(bitmap_db_door, bitmap_db_door,
2564 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2565 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2567 door_state &= ~DOOR_COPY_BACK;
2570 return MoveDoor(door_state);
2573 unsigned int CloseDoor(unsigned int door_state)
2575 unsigned int old_door_state = GetDoorState();
2577 if (!(door_state & DOOR_NO_COPY_BACK))
2579 if (old_door_state & DOOR_OPEN_1)
2580 BlitBitmap(backbuffer, bitmap_db_door,
2581 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2583 if (old_door_state & DOOR_OPEN_2)
2584 BlitBitmap(backbuffer, bitmap_db_door,
2585 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2587 door_state &= ~DOOR_NO_COPY_BACK;
2590 return MoveDoor(door_state);
2593 unsigned int GetDoorState()
2595 return MoveDoor(DOOR_GET_STATE);
2598 unsigned int SetDoorState(unsigned int door_state)
2600 return MoveDoor(door_state | DOOR_SET_STATE);
2603 unsigned int MoveDoor(unsigned int door_state)
2605 static int door1 = DOOR_OPEN_1;
2606 static int door2 = DOOR_CLOSE_2;
2607 unsigned long door_delay = 0;
2608 unsigned long door_delay_value;
2611 if (door_1.width < 0 || door_1.width > DXSIZE)
2612 door_1.width = DXSIZE;
2613 if (door_1.height < 0 || door_1.height > DYSIZE)
2614 door_1.height = DYSIZE;
2615 if (door_2.width < 0 || door_2.width > VXSIZE)
2616 door_2.width = VXSIZE;
2617 if (door_2.height < 0 || door_2.height > VYSIZE)
2618 door_2.height = VYSIZE;
2620 if (door_state == DOOR_GET_STATE)
2621 return (door1 | door2);
2623 if (door_state & DOOR_SET_STATE)
2625 if (door_state & DOOR_ACTION_1)
2626 door1 = door_state & DOOR_ACTION_1;
2627 if (door_state & DOOR_ACTION_2)
2628 door2 = door_state & DOOR_ACTION_2;
2630 return (door1 | door2);
2633 if (!(door_state & DOOR_FORCE_REDRAW))
2635 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2636 door_state &= ~DOOR_OPEN_1;
2637 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2638 door_state &= ~DOOR_CLOSE_1;
2639 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2640 door_state &= ~DOOR_OPEN_2;
2641 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2642 door_state &= ~DOOR_CLOSE_2;
2645 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2648 if (setup.quick_doors)
2650 stepsize = 20; /* must be choosen to always draw last frame */
2651 door_delay_value = 0;
2654 if (global.autoplay_leveldir)
2656 door_state |= DOOR_NO_DELAY;
2657 door_state &= ~DOOR_CLOSE_ALL;
2660 if (door_state & DOOR_ACTION)
2662 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2663 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2664 boolean door_1_done = (!handle_door_1);
2665 boolean door_2_done = (!handle_door_2);
2666 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2667 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2668 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2669 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2670 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2671 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2672 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2673 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2674 int door_skip = max_door_size - door_size;
2676 int end = door_size;
2678 int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
2682 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2684 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2688 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2690 /* opening door sound has priority over simultaneously closing door */
2691 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2692 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2693 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2694 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2697 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2700 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2701 GC gc = bitmap->stored_clip_gc;
2703 if (door_state & DOOR_ACTION_1)
2705 int a = MIN(x * door_1.step_offset, end);
2706 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2707 int i = p + door_skip;
2709 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2711 BlitBitmap(bitmap_db_door, drawto,
2712 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2713 DXSIZE, DYSIZE, DX, DY);
2717 BlitBitmap(bitmap_db_door, drawto,
2718 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2719 DXSIZE, DYSIZE - p / 2, DX, DY);
2721 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2724 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2726 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2727 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2728 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2729 int dst2_x = DX, dst2_y = DY;
2730 int width = i, height = DYSIZE;
2732 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2733 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2736 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2737 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2740 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2742 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2743 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2744 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2745 int dst2_x = DX, dst2_y = DY;
2746 int width = DXSIZE, height = i;
2748 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2749 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2752 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2753 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2756 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2758 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2760 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2761 BlitBitmapMasked(bitmap, drawto,
2762 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2763 DX + DXSIZE - i, DY + j);
2764 BlitBitmapMasked(bitmap, drawto,
2765 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2766 DX + DXSIZE - i, DY + 140 + j);
2767 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2768 DY - (DOOR_GFX_PAGEY1 + j));
2769 BlitBitmapMasked(bitmap, drawto,
2770 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2772 BlitBitmapMasked(bitmap, drawto,
2773 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2776 BlitBitmapMasked(bitmap, drawto,
2777 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2779 BlitBitmapMasked(bitmap, drawto,
2780 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2782 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2783 BlitBitmapMasked(bitmap, drawto,
2784 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2785 DX + DXSIZE - i, DY + 77 + j);
2786 BlitBitmapMasked(bitmap, drawto,
2787 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2788 DX + DXSIZE - i, DY + 203 + j);
2791 redraw_mask |= REDRAW_DOOR_1;
2792 door_1_done = (a == end);
2795 if (door_state & DOOR_ACTION_2)
2798 int a = MIN(x * door_2.step_offset, door_size);
2799 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2800 int i = p + door_skip;
2802 int a = MIN(x * door_2.step_offset, door_size_2);
2803 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2804 int i = p + door_skip;
2807 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2809 BlitBitmap(bitmap_db_door, drawto,
2810 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2811 VXSIZE, VYSIZE, VX, VY);
2813 else if (x <= VYSIZE)
2815 BlitBitmap(bitmap_db_door, drawto,
2816 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2817 VXSIZE, VYSIZE - p / 2, VX, VY);
2819 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2822 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2824 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2825 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2826 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2827 int dst2_x = VX, dst2_y = VY;
2828 int width = i, height = VYSIZE;
2830 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2831 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2834 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2835 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2838 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2840 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2841 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2842 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2843 int dst2_x = VX, dst2_y = VY;
2844 int width = VXSIZE, height = i;
2846 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2847 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2850 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2851 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2854 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2856 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2858 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2859 BlitBitmapMasked(bitmap, drawto,
2860 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2861 VX + VXSIZE - i, VY + j);
2862 SetClipOrigin(bitmap, gc,
2863 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2864 BlitBitmapMasked(bitmap, drawto,
2865 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2868 BlitBitmapMasked(bitmap, drawto,
2869 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2870 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2871 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2872 BlitBitmapMasked(bitmap, drawto,
2873 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2875 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2878 redraw_mask |= REDRAW_DOOR_2;
2879 door_2_done = (a == VXSIZE);
2882 if (!(door_state & DOOR_NO_DELAY))
2886 if (game_status == GAME_MODE_MAIN)
2889 WaitUntilDelayReached(&door_delay, door_delay_value);
2894 if (door_state & DOOR_ACTION_1)
2895 door1 = door_state & DOOR_ACTION_1;
2896 if (door_state & DOOR_ACTION_2)
2897 door2 = door_state & DOOR_ACTION_2;
2899 return (door1 | door2);
2902 void DrawSpecialEditorDoor()
2904 /* draw bigger toolbox window */
2905 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2906 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2908 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2909 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2912 redraw_mask |= REDRAW_ALL;
2915 void UndrawSpecialEditorDoor()
2917 /* draw normal tape recorder window */
2918 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2919 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2922 redraw_mask |= REDRAW_ALL;
2926 /* ---------- new tool button stuff ---------------------------------------- */
2928 /* graphic position values for tool buttons */
2929 #define TOOL_BUTTON_YES_XPOS 2
2930 #define TOOL_BUTTON_YES_YPOS 250
2931 #define TOOL_BUTTON_YES_GFX_YPOS 0
2932 #define TOOL_BUTTON_YES_XSIZE 46
2933 #define TOOL_BUTTON_YES_YSIZE 28
2934 #define TOOL_BUTTON_NO_XPOS 52
2935 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2936 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2937 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2938 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2939 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2940 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2941 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2942 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2943 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2944 #define TOOL_BUTTON_PLAYER_XSIZE 30
2945 #define TOOL_BUTTON_PLAYER_YSIZE 30
2946 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2947 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2948 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2949 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2950 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2951 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2952 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2953 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2954 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2955 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2956 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2957 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2958 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2959 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2960 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2961 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2962 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2963 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2964 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2965 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2974 } toolbutton_info[NUM_TOOL_BUTTONS] =
2977 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2978 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2979 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2984 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2985 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2986 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2991 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2992 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2993 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2994 TOOL_CTRL_ID_CONFIRM,
2998 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2999 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3000 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3001 TOOL_CTRL_ID_PLAYER_1,
3005 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3006 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3007 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3008 TOOL_CTRL_ID_PLAYER_2,
3012 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3013 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3014 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3015 TOOL_CTRL_ID_PLAYER_3,
3019 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3020 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3021 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3022 TOOL_CTRL_ID_PLAYER_4,
3027 void CreateToolButtons()
3031 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3033 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3034 Bitmap *deco_bitmap = None;
3035 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3036 struct GadgetInfo *gi;
3037 unsigned long event_mask;
3038 int gd_xoffset, gd_yoffset;
3039 int gd_x1, gd_x2, gd_y;
3042 event_mask = GD_EVENT_RELEASED;
3044 gd_xoffset = toolbutton_info[i].xpos;
3045 gd_yoffset = toolbutton_info[i].ypos;
3046 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3047 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3048 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3050 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3052 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3054 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3055 &deco_bitmap, &deco_x, &deco_y);
3056 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3057 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3060 gi = CreateGadget(GDI_CUSTOM_ID, id,
3061 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3062 GDI_X, DX + toolbutton_info[i].x,
3063 GDI_Y, DY + toolbutton_info[i].y,
3064 GDI_WIDTH, toolbutton_info[i].width,
3065 GDI_HEIGHT, toolbutton_info[i].height,
3066 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3067 GDI_STATE, GD_BUTTON_UNPRESSED,
3068 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3069 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3070 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3071 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3072 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3073 GDI_DECORATION_SHIFTING, 1, 1,
3074 GDI_EVENT_MASK, event_mask,
3075 GDI_CALLBACK_ACTION, HandleToolButtons,
3079 Error(ERR_EXIT, "cannot create gadget");
3081 tool_gadget[id] = gi;
3085 void FreeToolButtons()
3089 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3090 FreeGadget(tool_gadget[i]);
3093 static void UnmapToolButtons()
3097 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3098 UnmapGadget(tool_gadget[i]);
3101 static void HandleToolButtons(struct GadgetInfo *gi)
3103 request_gadget_id = gi->custom_id;
3106 static struct Mapping_EM_to_RND_object
3109 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3110 boolean is_backside; /* backside of moving element */
3116 em_object_mapping_list[] =
3119 Xblank, TRUE, FALSE,
3123 Yacid_splash_eB, FALSE, FALSE,
3124 EL_ACID_SPLASH_RIGHT, -1, -1
3127 Yacid_splash_wB, FALSE, FALSE,
3128 EL_ACID_SPLASH_LEFT, -1, -1
3131 #ifdef EM_ENGINE_BAD_ROLL
3133 Xstone_force_e, FALSE, FALSE,
3134 EL_ROCK, -1, MV_BIT_RIGHT
3137 Xstone_force_w, FALSE, FALSE,
3138 EL_ROCK, -1, MV_BIT_LEFT
3141 Xnut_force_e, FALSE, FALSE,
3142 EL_NUT, -1, MV_BIT_RIGHT
3145 Xnut_force_w, FALSE, FALSE,
3146 EL_NUT, -1, MV_BIT_LEFT
3149 Xspring_force_e, FALSE, FALSE,
3150 EL_SPRING, -1, MV_BIT_RIGHT
3153 Xspring_force_w, FALSE, FALSE,
3154 EL_SPRING, -1, MV_BIT_LEFT
3157 Xemerald_force_e, FALSE, FALSE,
3158 EL_EMERALD, -1, MV_BIT_RIGHT
3161 Xemerald_force_w, FALSE, FALSE,
3162 EL_EMERALD, -1, MV_BIT_LEFT
3165 Xdiamond_force_e, FALSE, FALSE,
3166 EL_DIAMOND, -1, MV_BIT_RIGHT
3169 Xdiamond_force_w, FALSE, FALSE,
3170 EL_DIAMOND, -1, MV_BIT_LEFT
3173 Xbomb_force_e, FALSE, FALSE,
3174 EL_BOMB, -1, MV_BIT_RIGHT
3177 Xbomb_force_w, FALSE, FALSE,
3178 EL_BOMB, -1, MV_BIT_LEFT
3180 #endif /* EM_ENGINE_BAD_ROLL */
3183 Xstone, TRUE, FALSE,
3187 Xstone_pause, FALSE, FALSE,
3191 Xstone_fall, FALSE, FALSE,
3195 Ystone_s, FALSE, FALSE,
3196 EL_ROCK, ACTION_FALLING, -1
3199 Ystone_sB, FALSE, TRUE,
3200 EL_ROCK, ACTION_FALLING, -1
3203 Ystone_e, FALSE, FALSE,
3204 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3207 Ystone_eB, FALSE, TRUE,
3208 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3211 Ystone_w, FALSE, FALSE,
3212 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3215 Ystone_wB, FALSE, TRUE,
3216 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3223 Xnut_pause, FALSE, FALSE,
3227 Xnut_fall, FALSE, FALSE,
3231 Ynut_s, FALSE, FALSE,
3232 EL_NUT, ACTION_FALLING, -1
3235 Ynut_sB, FALSE, TRUE,
3236 EL_NUT, ACTION_FALLING, -1
3239 Ynut_e, FALSE, FALSE,
3240 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3243 Ynut_eB, FALSE, TRUE,
3244 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3247 Ynut_w, FALSE, FALSE,
3248 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3251 Ynut_wB, FALSE, TRUE,
3252 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3255 Xbug_n, TRUE, FALSE,
3259 Xbug_e, TRUE, FALSE,
3260 EL_BUG_RIGHT, -1, -1
3263 Xbug_s, TRUE, FALSE,
3267 Xbug_w, TRUE, FALSE,
3271 Xbug_gon, FALSE, FALSE,
3275 Xbug_goe, FALSE, FALSE,
3276 EL_BUG_RIGHT, -1, -1
3279 Xbug_gos, FALSE, FALSE,
3283 Xbug_gow, FALSE, FALSE,
3287 Ybug_n, FALSE, FALSE,
3288 EL_BUG, ACTION_MOVING, MV_BIT_UP
3291 Ybug_nB, FALSE, TRUE,
3292 EL_BUG, ACTION_MOVING, MV_BIT_UP
3295 Ybug_e, FALSE, FALSE,
3296 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3299 Ybug_eB, FALSE, TRUE,
3300 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3303 Ybug_s, FALSE, FALSE,
3304 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3307 Ybug_sB, FALSE, TRUE,
3308 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3311 Ybug_w, FALSE, FALSE,
3312 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3315 Ybug_wB, FALSE, TRUE,
3316 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3319 Ybug_w_n, FALSE, FALSE,
3320 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3323 Ybug_n_e, FALSE, FALSE,
3324 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3327 Ybug_e_s, FALSE, FALSE,
3328 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3331 Ybug_s_w, FALSE, FALSE,
3332 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3335 Ybug_e_n, FALSE, FALSE,
3336 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3339 Ybug_s_e, FALSE, FALSE,
3340 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3343 Ybug_w_s, FALSE, FALSE,
3344 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3347 Ybug_n_w, FALSE, FALSE,
3348 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3351 Ybug_stone, FALSE, FALSE,
3352 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3355 Ybug_spring, FALSE, FALSE,
3356 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3359 Xtank_n, TRUE, FALSE,
3360 EL_SPACESHIP_UP, -1, -1
3363 Xtank_e, TRUE, FALSE,
3364 EL_SPACESHIP_RIGHT, -1, -1
3367 Xtank_s, TRUE, FALSE,
3368 EL_SPACESHIP_DOWN, -1, -1
3371 Xtank_w, TRUE, FALSE,
3372 EL_SPACESHIP_LEFT, -1, -1
3375 Xtank_gon, FALSE, FALSE,
3376 EL_SPACESHIP_UP, -1, -1
3379 Xtank_goe, FALSE, FALSE,
3380 EL_SPACESHIP_RIGHT, -1, -1
3383 Xtank_gos, FALSE, FALSE,
3384 EL_SPACESHIP_DOWN, -1, -1
3387 Xtank_gow, FALSE, FALSE,
3388 EL_SPACESHIP_LEFT, -1, -1
3391 Ytank_n, FALSE, FALSE,
3392 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3395 Ytank_nB, FALSE, TRUE,
3396 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3399 Ytank_e, FALSE, FALSE,
3400 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3403 Ytank_eB, FALSE, TRUE,
3404 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3407 Ytank_s, FALSE, FALSE,
3408 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3411 Ytank_sB, FALSE, TRUE,
3412 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3415 Ytank_w, FALSE, FALSE,
3416 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3419 Ytank_wB, FALSE, TRUE,
3420 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3423 Ytank_w_n, FALSE, FALSE,
3424 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3427 Ytank_n_e, FALSE, FALSE,
3428 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3431 Ytank_e_s, FALSE, FALSE,
3432 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3435 Ytank_s_w, FALSE, FALSE,
3436 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3439 Ytank_e_n, FALSE, FALSE,
3440 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3443 Ytank_s_e, FALSE, FALSE,
3444 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3447 Ytank_w_s, FALSE, FALSE,
3448 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3451 Ytank_n_w, FALSE, FALSE,
3452 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3455 Ytank_stone, FALSE, FALSE,
3456 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3459 Ytank_spring, FALSE, FALSE,
3460 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3463 Xandroid, TRUE, FALSE,
3464 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3467 Xandroid_1_n, FALSE, FALSE,
3468 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3471 Xandroid_2_n, FALSE, FALSE,
3472 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3475 Xandroid_1_e, FALSE, FALSE,
3476 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3479 Xandroid_2_e, FALSE, FALSE,
3480 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3483 Xandroid_1_w, FALSE, FALSE,
3484 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3487 Xandroid_2_w, FALSE, FALSE,
3488 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3491 Xandroid_1_s, FALSE, FALSE,
3492 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3495 Xandroid_2_s, FALSE, FALSE,
3496 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3499 Yandroid_n, FALSE, FALSE,
3500 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3503 Yandroid_nB, FALSE, TRUE,
3504 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3507 Yandroid_ne, FALSE, FALSE,
3508 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3511 Yandroid_neB, FALSE, TRUE,
3512 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3515 Yandroid_e, FALSE, FALSE,
3516 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3519 Yandroid_eB, FALSE, TRUE,
3520 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3523 Yandroid_se, FALSE, FALSE,
3524 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3527 Yandroid_seB, FALSE, TRUE,
3528 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3531 Yandroid_s, FALSE, FALSE,
3532 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3535 Yandroid_sB, FALSE, TRUE,
3536 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3539 Yandroid_sw, FALSE, FALSE,
3540 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3543 Yandroid_swB, FALSE, TRUE,
3544 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3547 Yandroid_w, FALSE, FALSE,
3548 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3551 Yandroid_wB, FALSE, TRUE,
3552 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3555 Yandroid_nw, FALSE, FALSE,
3556 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3559 Yandroid_nwB, FALSE, TRUE,
3560 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3563 Xspring, TRUE, FALSE,
3567 Xspring_pause, FALSE, FALSE,
3571 Xspring_e, FALSE, FALSE,
3575 Xspring_w, FALSE, FALSE,
3579 Xspring_fall, FALSE, FALSE,
3583 Yspring_s, FALSE, FALSE,
3584 EL_SPRING, ACTION_FALLING, -1
3587 Yspring_sB, FALSE, TRUE,
3588 EL_SPRING, ACTION_FALLING, -1
3591 Yspring_e, FALSE, FALSE,
3592 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3595 Yspring_eB, FALSE, TRUE,
3596 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3599 Yspring_w, FALSE, FALSE,
3600 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3603 Yspring_wB, FALSE, TRUE,
3604 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3607 Yspring_kill_e, FALSE, FALSE,
3608 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3611 Yspring_kill_eB, FALSE, TRUE,
3612 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3615 Yspring_kill_w, FALSE, FALSE,
3616 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3619 Yspring_kill_wB, FALSE, TRUE,
3620 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3623 Xeater_n, TRUE, FALSE,
3624 EL_YAMYAM_UP, -1, -1
3627 Xeater_e, TRUE, FALSE,
3628 EL_YAMYAM_RIGHT, -1, -1
3631 Xeater_w, TRUE, FALSE,
3632 EL_YAMYAM_LEFT, -1, -1
3635 Xeater_s, TRUE, FALSE,
3636 EL_YAMYAM_DOWN, -1, -1
3639 Yeater_n, FALSE, FALSE,
3640 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3643 Yeater_nB, FALSE, TRUE,
3644 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3647 Yeater_e, FALSE, FALSE,
3648 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3651 Yeater_eB, FALSE, TRUE,
3652 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3655 Yeater_s, FALSE, FALSE,
3656 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3659 Yeater_sB, FALSE, TRUE,
3660 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3663 Yeater_w, FALSE, FALSE,
3664 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3667 Yeater_wB, FALSE, TRUE,
3668 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3671 Yeater_stone, FALSE, FALSE,
3672 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3675 Yeater_spring, FALSE, FALSE,
3676 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3679 Xalien, TRUE, FALSE,
3683 Xalien_pause, FALSE, FALSE,
3687 Yalien_n, FALSE, FALSE,
3688 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3691 Yalien_nB, FALSE, TRUE,
3692 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3695 Yalien_e, FALSE, FALSE,
3696 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3699 Yalien_eB, FALSE, TRUE,
3700 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3703 Yalien_s, FALSE, FALSE,
3704 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3707 Yalien_sB, FALSE, TRUE,
3708 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3711 Yalien_w, FALSE, FALSE,
3712 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3715 Yalien_wB, FALSE, TRUE,
3716 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3719 Yalien_stone, FALSE, FALSE,
3720 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3723 Yalien_spring, FALSE, FALSE,
3724 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3727 Xemerald, TRUE, FALSE,
3731 Xemerald_pause, FALSE, FALSE,
3735 Xemerald_fall, FALSE, FALSE,
3739 Xemerald_shine, FALSE, FALSE,
3740 EL_EMERALD, ACTION_TWINKLING, -1
3743 Yemerald_s, FALSE, FALSE,
3744 EL_EMERALD, ACTION_FALLING, -1
3747 Yemerald_sB, FALSE, TRUE,
3748 EL_EMERALD, ACTION_FALLING, -1
3751 Yemerald_e, FALSE, FALSE,
3752 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3755 Yemerald_eB, FALSE, TRUE,
3756 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3759 Yemerald_w, FALSE, FALSE,
3760 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3763 Yemerald_wB, FALSE, TRUE,
3764 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3767 Yemerald_eat, FALSE, FALSE,
3768 EL_EMERALD, ACTION_COLLECTING, -1
3771 Yemerald_stone, FALSE, FALSE,
3772 EL_NUT, ACTION_BREAKING, -1
3775 Xdiamond, TRUE, FALSE,
3779 Xdiamond_pause, FALSE, FALSE,
3783 Xdiamond_fall, FALSE, FALSE,
3787 Xdiamond_shine, FALSE, FALSE,
3788 EL_DIAMOND, ACTION_TWINKLING, -1
3791 Ydiamond_s, FALSE, FALSE,
3792 EL_DIAMOND, ACTION_FALLING, -1
3795 Ydiamond_sB, FALSE, TRUE,
3796 EL_DIAMOND, ACTION_FALLING, -1
3799 Ydiamond_e, FALSE, FALSE,
3800 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3803 Ydiamond_eB, FALSE, TRUE,
3804 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3807 Ydiamond_w, FALSE, FALSE,
3808 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3811 Ydiamond_wB, FALSE, TRUE,
3812 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3815 Ydiamond_eat, FALSE, FALSE,
3816 EL_DIAMOND, ACTION_COLLECTING, -1
3819 Ydiamond_stone, FALSE, FALSE,
3820 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3823 Xdrip_fall, TRUE, FALSE,
3824 EL_AMOEBA_DROP, -1, -1
3827 Xdrip_stretch, FALSE, FALSE,
3828 EL_AMOEBA_DROP, ACTION_FALLING, -1
3831 Xdrip_stretchB, FALSE, TRUE,
3832 EL_AMOEBA_DROP, ACTION_FALLING, -1
3835 Xdrip_eat, FALSE, FALSE,
3836 EL_AMOEBA_DROP, ACTION_GROWING, -1
3839 Ydrip_s1, FALSE, FALSE,
3840 EL_AMOEBA_DROP, ACTION_FALLING, -1
3843 Ydrip_s1B, FALSE, TRUE,
3844 EL_AMOEBA_DROP, ACTION_FALLING, -1
3847 Ydrip_s2, FALSE, FALSE,
3848 EL_AMOEBA_DROP, ACTION_FALLING, -1
3851 Ydrip_s2B, FALSE, TRUE,
3852 EL_AMOEBA_DROP, ACTION_FALLING, -1
3859 Xbomb_pause, FALSE, FALSE,
3863 Xbomb_fall, FALSE, FALSE,
3867 Ybomb_s, FALSE, FALSE,
3868 EL_BOMB, ACTION_FALLING, -1
3871 Ybomb_sB, FALSE, TRUE,
3872 EL_BOMB, ACTION_FALLING, -1
3875 Ybomb_e, FALSE, FALSE,
3876 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3879 Ybomb_eB, FALSE, TRUE,
3880 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3883 Ybomb_w, FALSE, FALSE,
3884 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3887 Ybomb_wB, FALSE, TRUE,
3888 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3891 Ybomb_eat, FALSE, FALSE,
3892 EL_BOMB, ACTION_ACTIVATING, -1
3895 Xballoon, TRUE, FALSE,
3899 Yballoon_n, FALSE, FALSE,
3900 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3903 Yballoon_nB, FALSE, TRUE,
3904 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3907 Yballoon_e, FALSE, FALSE,
3908 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3911 Yballoon_eB, FALSE, TRUE,
3912 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3915 Yballoon_s, FALSE, FALSE,
3916 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3919 Yballoon_sB, FALSE, TRUE,
3920 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3923 Yballoon_w, FALSE, FALSE,
3924 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3927 Yballoon_wB, FALSE, TRUE,
3928 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3931 Xgrass, TRUE, FALSE,
3932 EL_EMC_GRASS, -1, -1
3935 Ygrass_nB, FALSE, FALSE,
3936 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3939 Ygrass_eB, FALSE, FALSE,
3940 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3943 Ygrass_sB, FALSE, FALSE,
3944 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3947 Ygrass_wB, FALSE, FALSE,
3948 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3955 Ydirt_nB, FALSE, FALSE,
3956 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3959 Ydirt_eB, FALSE, FALSE,
3960 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3963 Ydirt_sB, FALSE, FALSE,
3964 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3967 Ydirt_wB, FALSE, FALSE,
3968 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3971 Xacid_ne, TRUE, FALSE,
3972 EL_ACID_POOL_TOPRIGHT, -1, -1
3975 Xacid_se, TRUE, FALSE,
3976 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3979 Xacid_s, TRUE, FALSE,
3980 EL_ACID_POOL_BOTTOM, -1, -1
3983 Xacid_sw, TRUE, FALSE,
3984 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3987 Xacid_nw, TRUE, FALSE,
3988 EL_ACID_POOL_TOPLEFT, -1, -1
3991 Xacid_1, TRUE, FALSE,
3995 Xacid_2, FALSE, FALSE,
3999 Xacid_3, FALSE, FALSE,
4003 Xacid_4, FALSE, FALSE,
4007 Xacid_5, FALSE, FALSE,
4011 Xacid_6, FALSE, FALSE,
4015 Xacid_7, FALSE, FALSE,
4019 Xacid_8, FALSE, FALSE,
4023 Xball_1, TRUE, FALSE,
4024 EL_EMC_MAGIC_BALL, -1, -1
4027 Xball_1B, FALSE, FALSE,
4028 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4031 Xball_2, FALSE, FALSE,
4032 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4035 Xball_2B, FALSE, FALSE,
4036 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4039 Yball_eat, FALSE, FALSE,
4040 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4043 Ykey_1_eat, FALSE, FALSE,
4044 EL_EM_KEY_1, ACTION_COLLECTING, -1
4047 Ykey_2_eat, FALSE, FALSE,
4048 EL_EM_KEY_2, ACTION_COLLECTING, -1
4051 Ykey_3_eat, FALSE, FALSE,
4052 EL_EM_KEY_3, ACTION_COLLECTING, -1
4055 Ykey_4_eat, FALSE, FALSE,
4056 EL_EM_KEY_4, ACTION_COLLECTING, -1
4059 Ykey_5_eat, FALSE, FALSE,
4060 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4063 Ykey_6_eat, FALSE, FALSE,
4064 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4067 Ykey_7_eat, FALSE, FALSE,
4068 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4071 Ykey_8_eat, FALSE, FALSE,
4072 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4075 Ylenses_eat, FALSE, FALSE,
4076 EL_EMC_LENSES, ACTION_COLLECTING, -1
4079 Ymagnify_eat, FALSE, FALSE,
4080 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4083 Ygrass_eat, FALSE, FALSE,
4084 EL_EMC_GRASS, ACTION_SNAPPING, -1
4087 Ydirt_eat, FALSE, FALSE,
4088 EL_SAND, ACTION_SNAPPING, -1
4091 Xgrow_ns, TRUE, FALSE,
4092 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4095 Ygrow_ns_eat, FALSE, FALSE,
4096 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4099 Xgrow_ew, TRUE, FALSE,
4100 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4103 Ygrow_ew_eat, FALSE, FALSE,
4104 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4107 Xwonderwall, TRUE, FALSE,
4108 EL_MAGIC_WALL, -1, -1
4111 XwonderwallB, FALSE, FALSE,
4112 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4115 Xamoeba_1, TRUE, FALSE,
4116 EL_AMOEBA_DRY, ACTION_OTHER, -1
4119 Xamoeba_2, FALSE, FALSE,
4120 EL_AMOEBA_DRY, ACTION_OTHER, -1
4123 Xamoeba_3, FALSE, FALSE,
4124 EL_AMOEBA_DRY, ACTION_OTHER, -1
4127 Xamoeba_4, FALSE, FALSE,
4128 EL_AMOEBA_DRY, ACTION_OTHER, -1
4131 Xamoeba_5, TRUE, FALSE,
4132 EL_AMOEBA_WET, ACTION_OTHER, -1
4135 Xamoeba_6, FALSE, FALSE,
4136 EL_AMOEBA_WET, ACTION_OTHER, -1
4139 Xamoeba_7, FALSE, FALSE,
4140 EL_AMOEBA_WET, ACTION_OTHER, -1
4143 Xamoeba_8, FALSE, FALSE,
4144 EL_AMOEBA_WET, ACTION_OTHER, -1
4147 Xdoor_1, TRUE, FALSE,
4148 EL_EM_GATE_1, -1, -1
4151 Xdoor_2, TRUE, FALSE,
4152 EL_EM_GATE_2, -1, -1
4155 Xdoor_3, TRUE, FALSE,
4156 EL_EM_GATE_3, -1, -1
4159 Xdoor_4, TRUE, FALSE,
4160 EL_EM_GATE_4, -1, -1
4163 Xdoor_5, TRUE, FALSE,
4164 EL_EMC_GATE_5, -1, -1
4167 Xdoor_6, TRUE, FALSE,
4168 EL_EMC_GATE_6, -1, -1
4171 Xdoor_7, TRUE, FALSE,
4172 EL_EMC_GATE_7, -1, -1
4175 Xdoor_8, TRUE, FALSE,
4176 EL_EMC_GATE_8, -1, -1
4179 Xkey_1, TRUE, FALSE,
4183 Xkey_2, TRUE, FALSE,
4187 Xkey_3, TRUE, FALSE,
4191 Xkey_4, TRUE, FALSE,
4195 Xkey_5, TRUE, FALSE,
4196 EL_EMC_KEY_5, -1, -1
4199 Xkey_6, TRUE, FALSE,
4200 EL_EMC_KEY_6, -1, -1
4203 Xkey_7, TRUE, FALSE,
4204 EL_EMC_KEY_7, -1, -1
4207 Xkey_8, TRUE, FALSE,
4208 EL_EMC_KEY_8, -1, -1
4211 Xwind_n, TRUE, FALSE,
4212 EL_BALLOON_SWITCH_UP, -1, -1
4215 Xwind_e, TRUE, FALSE,
4216 EL_BALLOON_SWITCH_RIGHT, -1, -1
4219 Xwind_s, TRUE, FALSE,
4220 EL_BALLOON_SWITCH_DOWN, -1, -1
4223 Xwind_w, TRUE, FALSE,
4224 EL_BALLOON_SWITCH_LEFT, -1, -1
4227 Xwind_nesw, TRUE, FALSE,
4228 EL_BALLOON_SWITCH_ANY, -1, -1
4231 Xwind_stop, TRUE, FALSE,
4232 EL_BALLOON_SWITCH_NONE, -1, -1
4236 EL_EXIT_CLOSED, -1, -1
4239 Xexit_1, TRUE, FALSE,
4240 EL_EXIT_OPEN, -1, -1
4243 Xexit_2, FALSE, FALSE,
4244 EL_EXIT_OPEN, -1, -1
4247 Xexit_3, FALSE, FALSE,
4248 EL_EXIT_OPEN, -1, -1
4251 Xdynamite, TRUE, FALSE,
4252 EL_EM_DYNAMITE, -1, -1
4255 Ydynamite_eat, FALSE, FALSE,
4256 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4259 Xdynamite_1, TRUE, FALSE,
4260 EL_EM_DYNAMITE_ACTIVE, -1, -1
4263 Xdynamite_2, FALSE, FALSE,
4264 EL_EM_DYNAMITE_ACTIVE, -1, -1
4267 Xdynamite_3, FALSE, FALSE,
4268 EL_EM_DYNAMITE_ACTIVE, -1, -1
4271 Xdynamite_4, FALSE, FALSE,
4272 EL_EM_DYNAMITE_ACTIVE, -1, -1
4275 Xbumper, TRUE, FALSE,
4276 EL_EMC_SPRING_BUMPER, -1, -1
4279 XbumperB, FALSE, FALSE,
4280 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4283 Xwheel, TRUE, FALSE,
4284 EL_ROBOT_WHEEL, -1, -1
4287 XwheelB, FALSE, FALSE,
4288 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4291 Xswitch, TRUE, FALSE,
4292 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4295 XswitchB, FALSE, FALSE,
4296 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4300 EL_QUICKSAND_EMPTY, -1, -1
4303 Xsand_stone, TRUE, FALSE,
4304 EL_QUICKSAND_FULL, -1, -1
4307 Xsand_stonein_1, FALSE, TRUE,
4308 EL_ROCK, ACTION_FILLING, -1
4311 Xsand_stonein_2, FALSE, TRUE,
4312 EL_ROCK, ACTION_FILLING, -1
4315 Xsand_stonein_3, FALSE, TRUE,
4316 EL_ROCK, ACTION_FILLING, -1
4319 Xsand_stonein_4, FALSE, TRUE,
4320 EL_ROCK, ACTION_FILLING, -1
4323 Xsand_stonesand_1, FALSE, FALSE,
4324 EL_QUICKSAND_FULL, -1, -1
4327 Xsand_stonesand_2, FALSE, FALSE,
4328 EL_QUICKSAND_FULL, -1, -1
4331 Xsand_stonesand_3, FALSE, FALSE,
4332 EL_QUICKSAND_FULL, -1, -1
4335 Xsand_stonesand_4, FALSE, FALSE,
4336 EL_QUICKSAND_FULL, -1, -1
4339 Xsand_stoneout_1, FALSE, FALSE,
4340 EL_ROCK, ACTION_EMPTYING, -1
4343 Xsand_stoneout_2, FALSE, FALSE,
4344 EL_ROCK, ACTION_EMPTYING, -1
4347 Xsand_sandstone_1, FALSE, FALSE,
4348 EL_QUICKSAND_FULL, -1, -1
4351 Xsand_sandstone_2, FALSE, FALSE,
4352 EL_QUICKSAND_FULL, -1, -1
4355 Xsand_sandstone_3, FALSE, FALSE,
4356 EL_QUICKSAND_FULL, -1, -1
4359 Xsand_sandstone_4, FALSE, FALSE,
4360 EL_QUICKSAND_FULL, -1, -1
4363 Xplant, TRUE, FALSE,
4364 EL_EMC_PLANT, -1, -1
4367 Yplant, FALSE, FALSE,
4368 EL_EMC_PLANT, -1, -1
4371 Xlenses, TRUE, FALSE,
4372 EL_EMC_LENSES, -1, -1
4375 Xmagnify, TRUE, FALSE,
4376 EL_EMC_MAGNIFIER, -1, -1
4379 Xdripper, TRUE, FALSE,
4380 EL_EMC_DRIPPER, -1, -1
4383 XdripperB, FALSE, FALSE,
4384 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4387 Xfake_blank, TRUE, FALSE,
4388 EL_INVISIBLE_WALL, -1, -1
4391 Xfake_blankB, FALSE, FALSE,
4392 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4395 Xfake_grass, TRUE, FALSE,
4396 EL_EMC_FAKE_GRASS, -1, -1
4399 Xfake_grassB, FALSE, FALSE,
4400 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4403 Xfake_door_1, TRUE, FALSE,
4404 EL_EM_GATE_1_GRAY, -1, -1
4407 Xfake_door_2, TRUE, FALSE,
4408 EL_EM_GATE_2_GRAY, -1, -1
4411 Xfake_door_3, TRUE, FALSE,
4412 EL_EM_GATE_3_GRAY, -1, -1
4415 Xfake_door_4, TRUE, FALSE,
4416 EL_EM_GATE_4_GRAY, -1, -1
4419 Xfake_door_5, TRUE, FALSE,
4420 EL_EMC_GATE_5_GRAY, -1, -1
4423 Xfake_door_6, TRUE, FALSE,
4424 EL_EMC_GATE_6_GRAY, -1, -1
4427 Xfake_door_7, TRUE, FALSE,
4428 EL_EMC_GATE_7_GRAY, -1, -1
4431 Xfake_door_8, TRUE, FALSE,
4432 EL_EMC_GATE_8_GRAY, -1, -1
4435 Xfake_acid_1, TRUE, FALSE,
4436 EL_EMC_FAKE_ACID, -1, -1
4439 Xfake_acid_2, FALSE, FALSE,
4440 EL_EMC_FAKE_ACID, -1, -1
4443 Xfake_acid_3, FALSE, FALSE,
4444 EL_EMC_FAKE_ACID, -1, -1
4447 Xfake_acid_4, FALSE, FALSE,
4448 EL_EMC_FAKE_ACID, -1, -1
4451 Xfake_acid_5, FALSE, FALSE,
4452 EL_EMC_FAKE_ACID, -1, -1
4455 Xfake_acid_6, FALSE, FALSE,
4456 EL_EMC_FAKE_ACID, -1, -1
4459 Xfake_acid_7, FALSE, FALSE,
4460 EL_EMC_FAKE_ACID, -1, -1
4463 Xfake_acid_8, FALSE, FALSE,
4464 EL_EMC_FAKE_ACID, -1, -1
4467 Xsteel_1, TRUE, FALSE,
4468 EL_STEELWALL, -1, -1
4471 Xsteel_2, TRUE, FALSE,
4472 EL_EMC_STEELWALL_2, -1, -1
4475 Xsteel_3, TRUE, FALSE,
4476 EL_EMC_STEELWALL_3, -1, -1
4479 Xsteel_4, TRUE, FALSE,
4480 EL_EMC_STEELWALL_4, -1, -1
4483 Xwall_1, TRUE, FALSE,
4487 Xwall_2, TRUE, FALSE,
4488 EL_EMC_WALL_14, -1, -1
4491 Xwall_3, TRUE, FALSE,
4492 EL_EMC_WALL_15, -1, -1
4495 Xwall_4, TRUE, FALSE,
4496 EL_EMC_WALL_16, -1, -1
4499 Xround_wall_1, TRUE, FALSE,
4500 EL_WALL_SLIPPERY, -1, -1
4503 Xround_wall_2, TRUE, FALSE,
4504 EL_EMC_WALL_SLIPPERY_2, -1, -1
4507 Xround_wall_3, TRUE, FALSE,
4508 EL_EMC_WALL_SLIPPERY_3, -1, -1
4511 Xround_wall_4, TRUE, FALSE,
4512 EL_EMC_WALL_SLIPPERY_4, -1, -1
4515 Xdecor_1, TRUE, FALSE,
4516 EL_EMC_WALL_8, -1, -1
4519 Xdecor_2, TRUE, FALSE,
4520 EL_EMC_WALL_6, -1, -1
4523 Xdecor_3, TRUE, FALSE,
4524 EL_EMC_WALL_4, -1, -1
4527 Xdecor_4, TRUE, FALSE,
4528 EL_EMC_WALL_7, -1, -1
4531 Xdecor_5, TRUE, FALSE,
4532 EL_EMC_WALL_5, -1, -1
4535 Xdecor_6, TRUE, FALSE,
4536 EL_EMC_WALL_9, -1, -1
4539 Xdecor_7, TRUE, FALSE,
4540 EL_EMC_WALL_10, -1, -1
4543 Xdecor_8, TRUE, FALSE,
4544 EL_EMC_WALL_1, -1, -1
4547 Xdecor_9, TRUE, FALSE,
4548 EL_EMC_WALL_2, -1, -1
4551 Xdecor_10, TRUE, FALSE,
4552 EL_EMC_WALL_3, -1, -1
4555 Xdecor_11, TRUE, FALSE,
4556 EL_EMC_WALL_11, -1, -1
4559 Xdecor_12, TRUE, FALSE,
4560 EL_EMC_WALL_12, -1, -1
4563 Xalpha_0, TRUE, FALSE,
4564 EL_CHAR('0'), -1, -1
4567 Xalpha_1, TRUE, FALSE,
4568 EL_CHAR('1'), -1, -1
4571 Xalpha_2, TRUE, FALSE,
4572 EL_CHAR('2'), -1, -1
4575 Xalpha_3, TRUE, FALSE,
4576 EL_CHAR('3'), -1, -1
4579 Xalpha_4, TRUE, FALSE,
4580 EL_CHAR('4'), -1, -1
4583 Xalpha_5, TRUE, FALSE,
4584 EL_CHAR('5'), -1, -1
4587 Xalpha_6, TRUE, FALSE,
4588 EL_CHAR('6'), -1, -1
4591 Xalpha_7, TRUE, FALSE,
4592 EL_CHAR('7'), -1, -1
4595 Xalpha_8, TRUE, FALSE,
4596 EL_CHAR('8'), -1, -1
4599 Xalpha_9, TRUE, FALSE,
4600 EL_CHAR('9'), -1, -1
4603 Xalpha_excla, TRUE, FALSE,
4604 EL_CHAR('!'), -1, -1
4607 Xalpha_quote, TRUE, FALSE,
4608 EL_CHAR('"'), -1, -1
4611 Xalpha_comma, TRUE, FALSE,
4612 EL_CHAR(','), -1, -1
4615 Xalpha_minus, TRUE, FALSE,
4616 EL_CHAR('-'), -1, -1
4619 Xalpha_perio, TRUE, FALSE,
4620 EL_CHAR('.'), -1, -1
4623 Xalpha_colon, TRUE, FALSE,
4624 EL_CHAR(':'), -1, -1
4627 Xalpha_quest, TRUE, FALSE,
4628 EL_CHAR('?'), -1, -1
4631 Xalpha_a, TRUE, FALSE,
4632 EL_CHAR('A'), -1, -1
4635 Xalpha_b, TRUE, FALSE,
4636 EL_CHAR('B'), -1, -1
4639 Xalpha_c, TRUE, FALSE,
4640 EL_CHAR('C'), -1, -1
4643 Xalpha_d, TRUE, FALSE,
4644 EL_CHAR('D'), -1, -1
4647 Xalpha_e, TRUE, FALSE,
4648 EL_CHAR('E'), -1, -1
4651 Xalpha_f, TRUE, FALSE,
4652 EL_CHAR('F'), -1, -1
4655 Xalpha_g, TRUE, FALSE,
4656 EL_CHAR('G'), -1, -1
4659 Xalpha_h, TRUE, FALSE,
4660 EL_CHAR('H'), -1, -1
4663 Xalpha_i, TRUE, FALSE,
4664 EL_CHAR('I'), -1, -1
4667 Xalpha_j, TRUE, FALSE,
4668 EL_CHAR('J'), -1, -1
4671 Xalpha_k, TRUE, FALSE,
4672 EL_CHAR('K'), -1, -1
4675 Xalpha_l, TRUE, FALSE,
4676 EL_CHAR('L'), -1, -1
4679 Xalpha_m, TRUE, FALSE,
4680 EL_CHAR('M'), -1, -1
4683 Xalpha_n, TRUE, FALSE,
4684 EL_CHAR('N'), -1, -1
4687 Xalpha_o, TRUE, FALSE,
4688 EL_CHAR('O'), -1, -1
4691 Xalpha_p, TRUE, FALSE,
4692 EL_CHAR('P'), -1, -1
4695 Xalpha_q, TRUE, FALSE,
4696 EL_CHAR('Q'), -1, -1
4699 Xalpha_r, TRUE, FALSE,
4700 EL_CHAR('R'), -1, -1
4703 Xalpha_s, TRUE, FALSE,
4704 EL_CHAR('S'), -1, -1
4707 Xalpha_t, TRUE, FALSE,
4708 EL_CHAR('T'), -1, -1
4711 Xalpha_u, TRUE, FALSE,
4712 EL_CHAR('U'), -1, -1
4715 Xalpha_v, TRUE, FALSE,
4716 EL_CHAR('V'), -1, -1
4719 Xalpha_w, TRUE, FALSE,
4720 EL_CHAR('W'), -1, -1
4723 Xalpha_x, TRUE, FALSE,
4724 EL_CHAR('X'), -1, -1
4727 Xalpha_y, TRUE, FALSE,
4728 EL_CHAR('Y'), -1, -1
4731 Xalpha_z, TRUE, FALSE,
4732 EL_CHAR('Z'), -1, -1
4735 Xalpha_arrow_e, TRUE, FALSE,
4736 EL_CHAR('>'), -1, -1
4739 Xalpha_arrow_w, TRUE, FALSE,
4740 EL_CHAR('<'), -1, -1
4743 Xalpha_copyr, TRUE, FALSE,
4744 EL_CHAR('©'), -1, -1
4748 Xboom_bug, FALSE, FALSE,
4749 EL_BUG, ACTION_EXPLODING, -1
4752 Xboom_bomb, FALSE, FALSE,
4753 EL_BOMB, ACTION_EXPLODING, -1
4756 Xboom_android, FALSE, FALSE,
4757 EL_EMC_ANDROID, ACTION_OTHER, -1
4760 Xboom_1, FALSE, FALSE,
4761 EL_DEFAULT, ACTION_EXPLODING, -1
4764 Xboom_2, FALSE, FALSE,
4765 EL_DEFAULT, ACTION_EXPLODING, -1
4768 Znormal, FALSE, FALSE,
4772 Zdynamite, FALSE, FALSE,
4776 Zplayer, FALSE, FALSE,
4780 ZBORDER, FALSE, FALSE,
4790 static struct Mapping_EM_to_RND_player
4799 em_player_mapping_list[] =
4803 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4807 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4811 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4815 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4819 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4823 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4827 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4831 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4835 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4839 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4843 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4847 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4851 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4855 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4859 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4863 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4867 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4871 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4875 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4879 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4883 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4887 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4891 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4895 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4899 EL_PLAYER_1, ACTION_DEFAULT, -1,
4903 EL_PLAYER_2, ACTION_DEFAULT, -1,
4907 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4911 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4915 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4919 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4923 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4927 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4931 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4935 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4939 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4943 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4947 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4951 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4955 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4959 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4963 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4967 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4971 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4975 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4979 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4983 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4987 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4991 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4995 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4999 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5003 EL_PLAYER_3, ACTION_DEFAULT, -1,
5007 EL_PLAYER_4, ACTION_DEFAULT, -1,
5016 int map_element_RND_to_EM(int element_rnd)
5018 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5019 static boolean mapping_initialized = FALSE;
5021 if (!mapping_initialized)
5025 /* return "Xalpha_quest" for all undefined elements in mapping array */
5026 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5027 mapping_RND_to_EM[i] = Xalpha_quest;
5029 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5030 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5031 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5032 em_object_mapping_list[i].element_em;
5034 mapping_initialized = TRUE;
5037 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5038 return mapping_RND_to_EM[element_rnd];
5040 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5045 int map_element_EM_to_RND(int element_em)
5047 static unsigned short mapping_EM_to_RND[TILE_MAX];
5048 static boolean mapping_initialized = FALSE;
5050 if (!mapping_initialized)
5054 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5055 for (i = 0; i < TILE_MAX; i++)
5056 mapping_EM_to_RND[i] = EL_UNKNOWN;
5058 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5059 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5060 em_object_mapping_list[i].element_rnd;
5062 mapping_initialized = TRUE;
5065 if (element_em >= 0 && element_em < TILE_MAX)
5066 return mapping_EM_to_RND[element_em];
5068 Error(ERR_WARN, "invalid EM level element %d", element_em);
5073 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5075 struct LevelInfo_EM *level_em = level->native_em_level;
5076 struct LEVEL *lev = level_em->lev;
5079 for (i = 0; i < TILE_MAX; i++)
5080 lev->android_array[i] = Xblank;
5082 for (i = 0; i < level->num_android_clone_elements; i++)
5084 int element_rnd = level->android_clone_element[i];
5085 int element_em = map_element_RND_to_EM(element_rnd);
5087 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5088 if (em_object_mapping_list[j].element_rnd == element_rnd)
5089 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5093 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5095 struct LevelInfo_EM *level_em = level->native_em_level;
5096 struct LEVEL *lev = level_em->lev;
5099 level->num_android_clone_elements = 0;
5101 for (i = 0; i < TILE_MAX; i++)
5103 int element_em = lev->android_array[i];
5105 boolean element_found = FALSE;
5107 if (element_em == Xblank)
5110 element_rnd = map_element_EM_to_RND(element_em);
5112 for (j = 0; j < level->num_android_clone_elements; j++)
5113 if (level->android_clone_element[j] == element_rnd)
5114 element_found = TRUE;
5118 level->android_clone_element[level->num_android_clone_elements++] =
5121 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5126 if (level->num_android_clone_elements == 0)
5128 level->num_android_clone_elements = 1;
5129 level->android_clone_element[0] = EL_EMPTY;
5133 int map_direction_RND_to_EM(int direction)
5135 return (direction == MV_UP ? 0 :
5136 direction == MV_RIGHT ? 1 :
5137 direction == MV_DOWN ? 2 :
5138 direction == MV_LEFT ? 3 :
5142 int map_direction_EM_to_RND(int direction)
5144 return (direction == 0 ? MV_UP :
5145 direction == 1 ? MV_RIGHT :
5146 direction == 2 ? MV_DOWN :
5147 direction == 3 ? MV_LEFT :
5151 int get_next_element(int element)
5155 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5156 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5157 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5158 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5159 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5160 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5161 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5163 default: return element;
5168 int el_act_dir2img(int element, int action, int direction)
5170 element = GFX_ELEMENT(element);
5172 if (direction == MV_NONE)
5173 return element_info[element].graphic[action];
5175 direction = MV_DIR_TO_BIT(direction);
5177 return element_info[element].direction_graphic[action][direction];
5180 int el_act_dir2img(int element, int action, int direction)
5182 element = GFX_ELEMENT(element);
5183 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5185 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5186 return element_info[element].direction_graphic[action][direction];
5191 static int el_act_dir2crm(int element, int action, int direction)
5193 element = GFX_ELEMENT(element);
5195 if (direction == MV_NONE)
5196 return element_info[element].crumbled[action];
5198 direction = MV_DIR_TO_BIT(direction);
5200 return element_info[element].direction_crumbled[action][direction];
5203 static int el_act_dir2crm(int element, int action, int direction)
5205 element = GFX_ELEMENT(element);
5206 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5208 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5209 return element_info[element].direction_crumbled[action][direction];
5213 int el_act2img(int element, int action)
5215 element = GFX_ELEMENT(element);
5217 return element_info[element].graphic[action];
5220 int el_act2crm(int element, int action)
5222 element = GFX_ELEMENT(element);
5224 return element_info[element].crumbled[action];
5227 int el_dir2img(int element, int direction)
5229 element = GFX_ELEMENT(element);
5231 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5234 int el2baseimg(int element)
5236 return element_info[element].graphic[ACTION_DEFAULT];
5239 int el2img(int element)
5241 element = GFX_ELEMENT(element);
5243 return element_info[element].graphic[ACTION_DEFAULT];
5246 int el2edimg(int element)
5248 element = GFX_ELEMENT(element);
5250 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5253 int el2preimg(int element)
5255 element = GFX_ELEMENT(element);
5257 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5260 int font2baseimg(int font_nr)
5262 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5266 void setCenteredPlayerNr_EM(int centered_player_nr)
5268 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5271 int getCenteredPlayerNr_EM()
5274 if (game.centered_player_nr_next >= 0 &&
5275 !native_em_level.ply[game.centered_player_nr_next]->alive)
5276 game.centered_player_nr_next = game.centered_player_nr;
5279 if (game.centered_player_nr != game.centered_player_nr_next)
5280 game.centered_player_nr = game.centered_player_nr_next;
5282 return game.centered_player_nr;
5285 void setSetCenteredPlayer_EM(boolean set_centered_player)
5287 game.set_centered_player = set_centered_player;
5290 boolean getSetCenteredPlayer_EM()
5292 return game.set_centered_player;
5296 int getNumActivePlayers_EM()
5298 int num_players = 0;
5304 for (i = 0; i < MAX_PLAYERS; i++)
5305 if (tape.player_participates[i])
5312 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5314 int game_frame_delay_value;
5316 game_frame_delay_value =
5317 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5318 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5321 if (tape.playing && tape.warp_forward && !tape.pausing)
5322 game_frame_delay_value = 0;
5324 return game_frame_delay_value;
5328 unsigned int InitRND(long seed)
5330 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5331 return InitEngineRND_EM(seed);
5333 return InitEngineRND(seed);
5336 void InitGraphicInfo_EM(void)
5338 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5339 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5343 int num_em_gfx_errors = 0;
5345 if (graphic_info_em_object[0][0].bitmap == NULL)
5347 /* EM graphics not yet initialized in em_open_all() */
5352 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5355 /* always start with reliable default values */
5356 for (i = 0; i < TILE_MAX; i++)
5358 object_mapping[i].element_rnd = EL_UNKNOWN;
5359 object_mapping[i].is_backside = FALSE;
5360 object_mapping[i].action = ACTION_DEFAULT;
5361 object_mapping[i].direction = MV_NONE;
5364 /* always start with reliable default values */
5365 for (p = 0; p < MAX_PLAYERS; p++)
5367 for (i = 0; i < SPR_MAX; i++)
5369 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5370 player_mapping[p][i].action = ACTION_DEFAULT;
5371 player_mapping[p][i].direction = MV_NONE;
5375 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5377 int e = em_object_mapping_list[i].element_em;
5379 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5380 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5382 if (em_object_mapping_list[i].action != -1)
5383 object_mapping[e].action = em_object_mapping_list[i].action;
5385 if (em_object_mapping_list[i].direction != -1)
5386 object_mapping[e].direction =
5387 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5390 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5392 int a = em_player_mapping_list[i].action_em;
5393 int p = em_player_mapping_list[i].player_nr;
5395 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5397 if (em_player_mapping_list[i].action != -1)
5398 player_mapping[p][a].action = em_player_mapping_list[i].action;
5400 if (em_player_mapping_list[i].direction != -1)
5401 player_mapping[p][a].direction =
5402 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5405 for (i = 0; i < TILE_MAX; i++)
5407 int element = object_mapping[i].element_rnd;
5408 int action = object_mapping[i].action;
5409 int direction = object_mapping[i].direction;
5410 boolean is_backside = object_mapping[i].is_backside;
5411 boolean action_removing = (action == ACTION_DIGGING ||
5412 action == ACTION_SNAPPING ||
5413 action == ACTION_COLLECTING);
5414 boolean action_exploding = ((action == ACTION_EXPLODING ||
5415 action == ACTION_SMASHED_BY_ROCK ||
5416 action == ACTION_SMASHED_BY_SPRING) &&
5417 element != EL_DIAMOND);
5418 boolean action_active = (action == ACTION_ACTIVE);
5419 boolean action_other = (action == ACTION_OTHER);
5421 for (j = 0; j < 8; j++)
5423 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5424 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5426 i == Xdrip_stretch ? element :
5427 i == Xdrip_stretchB ? element :
5428 i == Ydrip_s1 ? element :
5429 i == Ydrip_s1B ? element :
5430 i == Xball_1B ? element :
5431 i == Xball_2 ? element :
5432 i == Xball_2B ? element :
5433 i == Yball_eat ? element :
5434 i == Ykey_1_eat ? element :
5435 i == Ykey_2_eat ? element :
5436 i == Ykey_3_eat ? element :
5437 i == Ykey_4_eat ? element :
5438 i == Ykey_5_eat ? element :
5439 i == Ykey_6_eat ? element :
5440 i == Ykey_7_eat ? element :
5441 i == Ykey_8_eat ? element :
5442 i == Ylenses_eat ? element :
5443 i == Ymagnify_eat ? element :
5444 i == Ygrass_eat ? element :
5445 i == Ydirt_eat ? element :
5446 i == Yemerald_stone ? EL_EMERALD :
5447 i == Ydiamond_stone ? EL_ROCK :
5448 i == Xsand_stonein_1 ? element :
5449 i == Xsand_stonein_2 ? element :
5450 i == Xsand_stonein_3 ? element :
5451 i == Xsand_stonein_4 ? element :
5452 is_backside ? EL_EMPTY :
5453 action_removing ? EL_EMPTY :
5455 int effective_action = (j < 7 ? action :
5456 i == Xdrip_stretch ? action :
5457 i == Xdrip_stretchB ? action :
5458 i == Ydrip_s1 ? action :
5459 i == Ydrip_s1B ? action :
5460 i == Xball_1B ? action :
5461 i == Xball_2 ? action :
5462 i == Xball_2B ? action :
5463 i == Yball_eat ? action :
5464 i == Ykey_1_eat ? action :
5465 i == Ykey_2_eat ? action :
5466 i == Ykey_3_eat ? action :
5467 i == Ykey_4_eat ? action :
5468 i == Ykey_5_eat ? action :
5469 i == Ykey_6_eat ? action :
5470 i == Ykey_7_eat ? action :
5471 i == Ykey_8_eat ? action :
5472 i == Ylenses_eat ? action :
5473 i == Ymagnify_eat ? action :
5474 i == Ygrass_eat ? action :
5475 i == Ydirt_eat ? action :
5476 i == Xsand_stonein_1 ? action :
5477 i == Xsand_stonein_2 ? action :
5478 i == Xsand_stonein_3 ? action :
5479 i == Xsand_stonein_4 ? action :
5480 i == Xsand_stoneout_1 ? action :
5481 i == Xsand_stoneout_2 ? action :
5482 i == Xboom_android ? ACTION_EXPLODING :
5483 action_exploding ? ACTION_EXPLODING :
5484 action_active ? action :
5485 action_other ? action :
5487 int graphic = (el_act_dir2img(effective_element, effective_action,
5489 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5491 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5492 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5493 boolean has_action_graphics = (graphic != base_graphic);
5494 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5495 struct GraphicInfo *g = &graphic_info[graphic];
5496 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5499 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5500 boolean special_animation = (action != ACTION_DEFAULT &&
5501 g->anim_frames == 3 &&
5502 g->anim_delay == 2 &&
5503 g->anim_mode & ANIM_LINEAR);
5504 int sync_frame = (i == Xdrip_stretch ? 7 :
5505 i == Xdrip_stretchB ? 7 :
5506 i == Ydrip_s2 ? j + 8 :
5507 i == Ydrip_s2B ? j + 8 :
5516 i == Xfake_acid_1 ? 0 :
5517 i == Xfake_acid_2 ? 10 :
5518 i == Xfake_acid_3 ? 20 :
5519 i == Xfake_acid_4 ? 30 :
5520 i == Xfake_acid_5 ? 40 :
5521 i == Xfake_acid_6 ? 50 :
5522 i == Xfake_acid_7 ? 60 :
5523 i == Xfake_acid_8 ? 70 :
5525 i == Xball_2B ? j + 8 :
5526 i == Yball_eat ? j + 1 :
5527 i == Ykey_1_eat ? j + 1 :
5528 i == Ykey_2_eat ? j + 1 :
5529 i == Ykey_3_eat ? j + 1 :
5530 i == Ykey_4_eat ? j + 1 :
5531 i == Ykey_5_eat ? j + 1 :
5532 i == Ykey_6_eat ? j + 1 :
5533 i == Ykey_7_eat ? j + 1 :
5534 i == Ykey_8_eat ? j + 1 :
5535 i == Ylenses_eat ? j + 1 :
5536 i == Ymagnify_eat ? j + 1 :
5537 i == Ygrass_eat ? j + 1 :
5538 i == Ydirt_eat ? j + 1 :
5539 i == Xamoeba_1 ? 0 :
5540 i == Xamoeba_2 ? 1 :
5541 i == Xamoeba_3 ? 2 :
5542 i == Xamoeba_4 ? 3 :
5543 i == Xamoeba_5 ? 0 :
5544 i == Xamoeba_6 ? 1 :
5545 i == Xamoeba_7 ? 2 :
5546 i == Xamoeba_8 ? 3 :
5547 i == Xexit_2 ? j + 8 :
5548 i == Xexit_3 ? j + 16 :
5549 i == Xdynamite_1 ? 0 :
5550 i == Xdynamite_2 ? 8 :
5551 i == Xdynamite_3 ? 16 :
5552 i == Xdynamite_4 ? 24 :
5553 i == Xsand_stonein_1 ? j + 1 :
5554 i == Xsand_stonein_2 ? j + 9 :
5555 i == Xsand_stonein_3 ? j + 17 :
5556 i == Xsand_stonein_4 ? j + 25 :
5557 i == Xsand_stoneout_1 && j == 0 ? 0 :
5558 i == Xsand_stoneout_1 && j == 1 ? 0 :
5559 i == Xsand_stoneout_1 && j == 2 ? 1 :
5560 i == Xsand_stoneout_1 && j == 3 ? 2 :
5561 i == Xsand_stoneout_1 && j == 4 ? 2 :
5562 i == Xsand_stoneout_1 && j == 5 ? 3 :
5563 i == Xsand_stoneout_1 && j == 6 ? 4 :
5564 i == Xsand_stoneout_1 && j == 7 ? 4 :
5565 i == Xsand_stoneout_2 && j == 0 ? 5 :
5566 i == Xsand_stoneout_2 && j == 1 ? 6 :
5567 i == Xsand_stoneout_2 && j == 2 ? 7 :
5568 i == Xsand_stoneout_2 && j == 3 ? 8 :
5569 i == Xsand_stoneout_2 && j == 4 ? 9 :
5570 i == Xsand_stoneout_2 && j == 5 ? 11 :
5571 i == Xsand_stoneout_2 && j == 6 ? 13 :
5572 i == Xsand_stoneout_2 && j == 7 ? 15 :
5573 i == Xboom_bug && j == 1 ? 2 :
5574 i == Xboom_bug && j == 2 ? 2 :
5575 i == Xboom_bug && j == 3 ? 4 :
5576 i == Xboom_bug && j == 4 ? 4 :
5577 i == Xboom_bug && j == 5 ? 2 :
5578 i == Xboom_bug && j == 6 ? 2 :
5579 i == Xboom_bug && j == 7 ? 0 :
5580 i == Xboom_bomb && j == 1 ? 2 :
5581 i == Xboom_bomb && j == 2 ? 2 :
5582 i == Xboom_bomb && j == 3 ? 4 :
5583 i == Xboom_bomb && j == 4 ? 4 :
5584 i == Xboom_bomb && j == 5 ? 2 :
5585 i == Xboom_bomb && j == 6 ? 2 :
5586 i == Xboom_bomb && j == 7 ? 0 :
5587 i == Xboom_android && j == 7 ? 6 :
5588 i == Xboom_1 && j == 1 ? 2 :
5589 i == Xboom_1 && j == 2 ? 2 :
5590 i == Xboom_1 && j == 3 ? 4 :
5591 i == Xboom_1 && j == 4 ? 4 :
5592 i == Xboom_1 && j == 5 ? 6 :
5593 i == Xboom_1 && j == 6 ? 6 :
5594 i == Xboom_1 && j == 7 ? 8 :
5595 i == Xboom_2 && j == 0 ? 8 :
5596 i == Xboom_2 && j == 1 ? 8 :
5597 i == Xboom_2 && j == 2 ? 10 :
5598 i == Xboom_2 && j == 3 ? 10 :
5599 i == Xboom_2 && j == 4 ? 10 :
5600 i == Xboom_2 && j == 5 ? 12 :
5601 i == Xboom_2 && j == 6 ? 12 :
5602 i == Xboom_2 && j == 7 ? 12 :
5603 special_animation && j == 4 ? 3 :
5604 effective_action != action ? 0 :
5608 Bitmap *debug_bitmap = g_em->bitmap;
5609 int debug_src_x = g_em->src_x;
5610 int debug_src_y = g_em->src_y;
5613 int frame = getAnimationFrame(g->anim_frames,
5616 g->anim_start_frame,
5619 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5620 g->double_movement && is_backside);
5622 g_em->bitmap = src_bitmap;
5623 g_em->src_x = src_x;
5624 g_em->src_y = src_y;
5625 g_em->src_offset_x = 0;
5626 g_em->src_offset_y = 0;
5627 g_em->dst_offset_x = 0;
5628 g_em->dst_offset_y = 0;
5629 g_em->width = TILEX;
5630 g_em->height = TILEY;
5632 g_em->crumbled_bitmap = NULL;
5633 g_em->crumbled_src_x = 0;
5634 g_em->crumbled_src_y = 0;
5635 g_em->crumbled_border_size = 0;
5637 g_em->has_crumbled_graphics = FALSE;
5638 g_em->preserve_background = FALSE;
5641 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5642 printf("::: empty crumbled: %d [%s], %d, %d\n",
5643 effective_element, element_info[effective_element].token_name,
5644 effective_action, direction);
5647 /* if element can be crumbled, but certain action graphics are just empty
5648 space (like snapping sand with the original R'n'D graphics), do not
5649 treat these empty space graphics as crumbled graphics in EMC engine */
5650 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5652 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5654 g_em->has_crumbled_graphics = TRUE;
5655 g_em->crumbled_bitmap = src_bitmap;
5656 g_em->crumbled_src_x = src_x;
5657 g_em->crumbled_src_y = src_y;
5658 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5662 if (element == EL_ROCK &&
5663 effective_action == ACTION_FILLING)
5664 printf("::: has_action_graphics == %d\n", has_action_graphics);
5667 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5668 effective_action == ACTION_MOVING ||
5669 effective_action == ACTION_PUSHING ||
5670 effective_action == ACTION_EATING)) ||
5671 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5672 effective_action == ACTION_EMPTYING)))
5675 (effective_action == ACTION_FALLING ||
5676 effective_action == ACTION_FILLING ||
5677 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5678 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5679 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5680 int num_steps = (i == Ydrip_s1 ? 16 :
5681 i == Ydrip_s1B ? 16 :
5682 i == Ydrip_s2 ? 16 :
5683 i == Ydrip_s2B ? 16 :
5684 i == Xsand_stonein_1 ? 32 :
5685 i == Xsand_stonein_2 ? 32 :
5686 i == Xsand_stonein_3 ? 32 :
5687 i == Xsand_stonein_4 ? 32 :
5688 i == Xsand_stoneout_1 ? 16 :
5689 i == Xsand_stoneout_2 ? 16 : 8);
5690 int cx = ABS(dx) * (TILEX / num_steps);
5691 int cy = ABS(dy) * (TILEY / num_steps);
5692 int step_frame = (i == Ydrip_s2 ? j + 8 :
5693 i == Ydrip_s2B ? j + 8 :
5694 i == Xsand_stonein_2 ? j + 8 :
5695 i == Xsand_stonein_3 ? j + 16 :
5696 i == Xsand_stonein_4 ? j + 24 :
5697 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5698 int step = (is_backside ? step_frame : num_steps - step_frame);
5700 if (is_backside) /* tile where movement starts */
5702 if (dx < 0 || dy < 0)
5704 g_em->src_offset_x = cx * step;
5705 g_em->src_offset_y = cy * step;
5709 g_em->dst_offset_x = cx * step;
5710 g_em->dst_offset_y = cy * step;
5713 else /* tile where movement ends */
5715 if (dx < 0 || dy < 0)
5717 g_em->dst_offset_x = cx * step;
5718 g_em->dst_offset_y = cy * step;
5722 g_em->src_offset_x = cx * step;
5723 g_em->src_offset_y = cy * step;
5727 g_em->width = TILEX - cx * step;
5728 g_em->height = TILEY - cy * step;
5732 /* create unique graphic identifier to decide if tile must be redrawn */
5733 /* bit 31 - 16 (16 bit): EM style graphic
5734 bit 15 - 12 ( 4 bit): EM style frame
5735 bit 11 - 6 ( 6 bit): graphic width
5736 bit 5 - 0 ( 6 bit): graphic height */
5737 g_em->unique_identifier =
5738 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5740 /* create unique graphic identifier to decide if tile must be redrawn */
5741 /* bit 31 - 16 (16 bit): EM style element
5742 bit 15 - 12 ( 4 bit): EM style frame
5743 bit 11 - 6 ( 6 bit): graphic width
5744 bit 5 - 0 ( 6 bit): graphic height */
5745 g_em->unique_identifier =
5746 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5750 if (effective_element == EL_ROCK)
5751 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5752 effective_action, j, graphic, frame, g_em->unique_identifier);
5758 /* skip check for EMC elements not contained in original EMC artwork */
5759 if (element == EL_EMC_FAKE_ACID)
5763 if (g_em->bitmap != debug_bitmap ||
5764 g_em->src_x != debug_src_x ||
5765 g_em->src_y != debug_src_y ||
5766 g_em->src_offset_x != 0 ||
5767 g_em->src_offset_y != 0 ||
5768 g_em->dst_offset_x != 0 ||
5769 g_em->dst_offset_y != 0 ||
5770 g_em->width != TILEX ||
5771 g_em->height != TILEY)
5773 static int last_i = -1;
5781 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5782 i, element, element_info[element].token_name,
5783 element_action_info[effective_action].suffix, direction);
5785 if (element != effective_element)
5786 printf(" [%d ('%s')]",
5788 element_info[effective_element].token_name);
5792 if (g_em->bitmap != debug_bitmap)
5793 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5794 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5796 if (g_em->src_x != debug_src_x ||
5797 g_em->src_y != debug_src_y)
5798 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5799 j, (is_backside ? 'B' : 'F'),
5800 g_em->src_x, g_em->src_y,
5801 g_em->src_x / 32, g_em->src_y / 32,
5802 debug_src_x, debug_src_y,
5803 debug_src_x / 32, debug_src_y / 32);
5805 if (g_em->src_offset_x != 0 ||
5806 g_em->src_offset_y != 0 ||
5807 g_em->dst_offset_x != 0 ||
5808 g_em->dst_offset_y != 0)
5809 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5811 g_em->src_offset_x, g_em->src_offset_y,
5812 g_em->dst_offset_x, g_em->dst_offset_y);
5814 if (g_em->width != TILEX ||
5815 g_em->height != TILEY)
5816 printf(" %d (%d): size %d,%d should be %d,%d\n",
5818 g_em->width, g_em->height, TILEX, TILEY);
5820 num_em_gfx_errors++;
5827 for (i = 0; i < TILE_MAX; i++)
5829 for (j = 0; j < 8; j++)
5831 int element = object_mapping[i].element_rnd;
5832 int action = object_mapping[i].action;
5833 int direction = object_mapping[i].direction;
5834 boolean is_backside = object_mapping[i].is_backside;
5836 int graphic_action = el_act_dir2img(element, action, direction);
5837 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5839 int graphic_action = element_info[element].graphic[action];
5840 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5843 if ((action == ACTION_SMASHED_BY_ROCK ||
5844 action == ACTION_SMASHED_BY_SPRING ||
5845 action == ACTION_EATING) &&
5846 graphic_action == graphic_default)
5848 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5849 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5850 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5851 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5854 /* no separate animation for "smashed by rock" -- use rock instead */
5855 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5856 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5858 g_em->bitmap = g_xx->bitmap;
5859 g_em->src_x = g_xx->src_x;
5860 g_em->src_y = g_xx->src_y;
5861 g_em->src_offset_x = g_xx->src_offset_x;
5862 g_em->src_offset_y = g_xx->src_offset_y;
5863 g_em->dst_offset_x = g_xx->dst_offset_x;
5864 g_em->dst_offset_y = g_xx->dst_offset_y;
5865 g_em->width = g_xx->width;
5866 g_em->height = g_xx->height;
5868 g_em->unique_identifier = g_xx->unique_identifier;
5872 g_em->preserve_background = TRUE;
5877 for (p = 0; p < MAX_PLAYERS; p++)
5879 for (i = 0; i < SPR_MAX; i++)
5881 int element = player_mapping[p][i].element_rnd;
5882 int action = player_mapping[p][i].action;
5883 int direction = player_mapping[p][i].direction;
5885 for (j = 0; j < 8; j++)
5887 int effective_element = element;
5888 int effective_action = action;
5889 int graphic = (direction == MV_NONE ?
5890 el_act2img(effective_element, effective_action) :
5891 el_act_dir2img(effective_element, effective_action,
5893 struct GraphicInfo *g = &graphic_info[graphic];
5894 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5900 Bitmap *debug_bitmap = g_em->bitmap;
5901 int debug_src_x = g_em->src_x;
5902 int debug_src_y = g_em->src_y;
5905 int frame = getAnimationFrame(g->anim_frames,
5908 g->anim_start_frame,
5911 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5913 g_em->bitmap = src_bitmap;
5914 g_em->src_x = src_x;
5915 g_em->src_y = src_y;
5916 g_em->src_offset_x = 0;
5917 g_em->src_offset_y = 0;
5918 g_em->dst_offset_x = 0;
5919 g_em->dst_offset_y = 0;
5920 g_em->width = TILEX;
5921 g_em->height = TILEY;
5926 /* skip check for EMC elements not contained in original EMC artwork */
5927 if (element == EL_PLAYER_3 ||
5928 element == EL_PLAYER_4)
5932 if (g_em->bitmap != debug_bitmap ||
5933 g_em->src_x != debug_src_x ||
5934 g_em->src_y != debug_src_y)
5936 static int last_i = -1;
5944 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5945 p, i, element, element_info[element].token_name,
5946 element_action_info[effective_action].suffix, direction);
5948 if (element != effective_element)
5949 printf(" [%d ('%s')]",
5951 element_info[effective_element].token_name);
5955 if (g_em->bitmap != debug_bitmap)
5956 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5957 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5959 if (g_em->src_x != debug_src_x ||
5960 g_em->src_y != debug_src_y)
5961 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5963 g_em->src_x, g_em->src_y,
5964 g_em->src_x / 32, g_em->src_y / 32,
5965 debug_src_x, debug_src_y,
5966 debug_src_x / 32, debug_src_y / 32);
5968 num_em_gfx_errors++;
5978 printf("::: [%d errors found]\n", num_em_gfx_errors);
5984 void PlayMenuSound()
5986 int sound = menu.sound[game_status];
5988 if (sound == SND_UNDEFINED)
5991 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5992 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5995 if (IS_LOOP_SOUND(sound))
5996 PlaySoundLoop(sound);
6001 void PlayMenuSoundStereo(int sound, int stereo_position)
6003 if (sound == SND_UNDEFINED)
6006 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6007 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6010 if (IS_LOOP_SOUND(sound))
6011 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6013 PlaySoundStereo(sound, stereo_position);
6016 void PlayMenuSoundIfLoop()
6018 int sound = menu.sound[game_status];
6020 if (sound == SND_UNDEFINED)
6023 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6024 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6027 if (IS_LOOP_SOUND(sound))
6028 PlaySoundLoop(sound);
6031 void PlayMenuMusic()
6033 int music = menu.music[game_status];
6035 if (music == MUS_UNDEFINED)
6041 void ToggleFullscreenIfNeeded()
6043 if (setup.fullscreen != video.fullscreen_enabled ||
6044 setup.fullscreen_mode != video.fullscreen_mode_current)
6046 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6048 /* save backbuffer content which gets lost when toggling fullscreen mode */
6049 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6051 if (setup.fullscreen && video.fullscreen_enabled)
6053 /* keep fullscreen mode, but change screen mode */
6054 video.fullscreen_mode_current = setup.fullscreen_mode;
6055 video.fullscreen_enabled = FALSE;
6058 /* toggle fullscreen */
6059 ChangeVideoModeIfNeeded(setup.fullscreen);
6060 setup.fullscreen = video.fullscreen_enabled;
6062 /* restore backbuffer content from temporary backbuffer backup bitmap */
6063 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6065 FreeBitmap(tmp_backbuffer);
6067 redraw_mask = REDRAW_ALL;