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 char *print_if_not_empty(int element)
49 static char *s = NULL;
50 char *token_name = element_info[element].token_name;
55 s = checked_malloc(strlen(token_name) + 10 + 1);
57 if (element != EL_EMPTY)
58 sprintf(s, "%d\t['%s']", element, token_name);
60 sprintf(s, "%d", element);
65 void DumpTile(int x, int y)
70 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
77 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80 if (!IN_LEV_FIELD(x, y))
82 printf("(not in level field)\n");
88 printf(" Feld: %d\t['%s']\n", Feld[x][y],
89 element_info[Feld[x][y]].token_name);
90 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
91 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
92 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
93 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94 printf(" MovPos: %d\n", MovPos[x][y]);
95 printf(" MovDir: %d\n", MovDir[x][y]);
96 printf(" MovDelay: %d\n", MovDelay[x][y]);
97 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
98 printf(" CustomValue: %d\n", CustomValue[x][y]);
99 printf(" GfxElement: %d\n", GfxElement[x][y]);
100 printf(" GfxAction: %d\n", GfxAction[x][y]);
101 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
105 void SetDrawtoField(int mode)
107 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
118 drawto_field = fieldbuffer;
120 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
126 BX2 = SCR_FIELDX - 1;
127 BY2 = SCR_FIELDY - 1;
131 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 if (game_status == GAME_MODE_PLAYING &&
138 level.game_engine_type == GAME_ENGINE_TYPE_EM)
140 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
150 width = gfx.sxsize + 2 * TILEX;
151 height = gfx.sysize + 2 * TILEY;
154 if (force_redraw || setup.direct_draw)
157 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
158 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
160 if (setup.direct_draw)
161 SetDrawtoField(DRAW_BACKBUFFER);
163 for (xx = BX1; xx <= BX2; xx++)
164 for (yy = BY1; yy <= BY2; yy++)
165 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
166 DrawScreenField(xx, yy);
169 if (setup.direct_draw)
170 SetDrawtoField(DRAW_DIRECT);
173 if (setup.soft_scrolling)
175 int fx = FX, fy = FY;
177 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
178 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
180 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
184 BlitBitmap(drawto, window, x, y, width, height, x, y);
190 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
192 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
193 redraw_mask &= ~REDRAW_MAIN;
195 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
196 redraw_mask |= REDRAW_FIELD;
198 if (redraw_mask & REDRAW_FIELD)
199 redraw_mask &= ~REDRAW_TILES;
201 if (redraw_mask == REDRAW_NONE)
204 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
206 static boolean last_frame_skipped = FALSE;
207 boolean skip_even_when_not_scrolling = TRUE;
208 boolean just_scrolling = (ScreenMovDir != 0);
209 boolean verbose = FALSE;
211 if (global.fps_slowdown_factor > 1 &&
212 (FrameCounter % global.fps_slowdown_factor) &&
213 (just_scrolling || skip_even_when_not_scrolling))
215 redraw_mask &= ~REDRAW_MAIN;
217 last_frame_skipped = TRUE;
220 printf("FRAME SKIPPED\n");
224 if (last_frame_skipped)
225 redraw_mask |= REDRAW_FIELD;
227 last_frame_skipped = FALSE;
230 printf("frame not skipped\n");
234 /* synchronize X11 graphics at this point; if we would synchronize the
235 display immediately after the buffer switching (after the XFlush),
236 this could mean that we have to wait for the graphics to complete,
237 although we could go on doing calculations for the next frame */
241 if (redraw_mask & REDRAW_ALL)
243 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
245 redraw_mask = REDRAW_NONE;
248 if (redraw_mask & REDRAW_FIELD)
250 if (game_status != GAME_MODE_PLAYING ||
251 redraw_mask & REDRAW_FROM_BACKBUFFER)
253 BlitBitmap(backbuffer, window,
254 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
258 int fx = FX, fy = FY;
260 if (setup.soft_scrolling)
262 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
263 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
266 if (setup.soft_scrolling ||
267 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
268 ABS(ScreenMovPos) == ScrollStepSize ||
269 redraw_tiles > REDRAWTILES_THRESHOLD)
271 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
275 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
277 (setup.soft_scrolling ?
278 "setup.soft_scrolling" :
279 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
280 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
281 ABS(ScreenGfxPos) == ScrollStepSize ?
282 "ABS(ScreenGfxPos) == ScrollStepSize" :
283 "redraw_tiles > REDRAWTILES_THRESHOLD"));
289 redraw_mask &= ~REDRAW_MAIN;
292 if (redraw_mask & REDRAW_DOORS)
294 if (redraw_mask & REDRAW_DOOR_1)
295 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
297 if (redraw_mask & REDRAW_DOOR_2)
298 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
300 if (redraw_mask & REDRAW_DOOR_3)
301 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
303 redraw_mask &= ~REDRAW_DOORS;
306 if (redraw_mask & REDRAW_MICROLEVEL)
308 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
309 SX, SY + 10 * TILEY);
311 redraw_mask &= ~REDRAW_MICROLEVEL;
314 if (redraw_mask & REDRAW_TILES)
316 for (x = 0; x < SCR_FIELDX; x++)
317 for (y = 0 ; y < SCR_FIELDY; y++)
318 if (redraw[redraw_x1 + x][redraw_y1 + y])
319 BlitBitmap(buffer, window,
320 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
321 SX + x * TILEX, SY + y * TILEY);
324 if (redraw_mask & REDRAW_FPS) /* display frames per second */
329 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
330 if (!global.fps_slowdown)
333 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
334 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
339 for (x = 0; x < MAX_BUF_XSIZE; x++)
340 for (y = 0; y < MAX_BUF_YSIZE; y++)
343 redraw_mask = REDRAW_NONE;
349 long fading_delay = 300;
351 if (setup.fading && (redraw_mask & REDRAW_FIELD))
358 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
361 for (i = 0; i < 2 * FULL_SYSIZE; i++)
363 for (y = 0; y < FULL_SYSIZE; y++)
365 BlitBitmap(backbuffer, window,
366 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
374 for (i = 1; i < FULL_SYSIZE; i+=2)
375 BlitBitmap(backbuffer, window,
376 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
382 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
383 BlitBitmapMasked(backbuffer, window,
384 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
389 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
390 BlitBitmapMasked(backbuffer, window,
391 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
396 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
397 BlitBitmapMasked(backbuffer, window,
398 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
403 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
404 BlitBitmapMasked(backbuffer, window,
405 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
410 redraw_mask &= ~REDRAW_MAIN;
417 void FadeIn(int fade_delay)
426 FadeScreen(NULL, FADE_MODE_FADE_IN, fade_delay, 0);
428 redraw_mask = REDRAW_NONE;
431 void FadeOut(int fade_delay, int post_delay)
435 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
441 FadeScreen(NULL, FADE_MODE_FADE_OUT, fade_delay, post_delay);
443 redraw_mask = REDRAW_NONE;
446 void FadeCross(int fade_delay)
450 BlitBitmap(bitmap_db_title, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
456 FadeScreen(bitmap_db_title, FADE_MODE_CROSSFADE, fade_delay, 0);
458 redraw_mask = REDRAW_NONE;
461 void SetMainBackgroundImageIfDefined(int graphic)
463 if (graphic_info[graphic].bitmap)
464 SetMainBackgroundImage(graphic);
467 void SetMainBackgroundImage(int graphic)
469 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
470 graphic_info[graphic].bitmap ?
471 graphic_info[graphic].bitmap :
472 graphic_info[IMG_BACKGROUND].bitmap);
475 void SetDoorBackgroundImage(int graphic)
477 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
478 graphic_info[graphic].bitmap ?
479 graphic_info[graphic].bitmap :
480 graphic_info[IMG_BACKGROUND].bitmap);
483 void SetPanelBackground()
485 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
486 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
488 SetDoorBackgroundBitmap(bitmap_db_panel);
491 void DrawBackground(int dst_x, int dst_y, int width, int height)
493 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
495 redraw_mask |= REDRAW_FIELD;
500 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
502 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
504 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
505 SetDrawtoField(DRAW_BUFFERED);
508 SetDrawtoField(DRAW_BACKBUFFER);
510 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
512 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
513 SetDrawtoField(DRAW_DIRECT);
517 void MarkTileDirty(int x, int y)
519 int xx = redraw_x1 + x;
520 int yy = redraw_y1 + y;
525 redraw[xx][yy] = TRUE;
526 redraw_mask |= REDRAW_TILES;
529 void SetBorderElement()
533 BorderElement = EL_EMPTY;
535 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
537 for (x = 0; x < lev_fieldx; x++)
539 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
540 BorderElement = EL_STEELWALL;
542 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
548 void SetRandomAnimationValue(int x, int y)
550 gfx.anim_random_frame = GfxRandom[x][y];
553 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
555 /* animation synchronized with global frame counter, not move position */
556 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
557 sync_frame = FrameCounter;
560 if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
566 printf("::: FOO!\n");
570 return getAnimationFrame(graphic_info[graphic].anim_frames,
571 graphic_info[graphic].anim_delay,
572 graphic_info[graphic].anim_mode,
573 graphic_info[graphic].anim_start_frame,
577 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
578 int *x, int *y, boolean get_backside)
580 struct GraphicInfo *g = &graphic_info[graphic];
581 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
582 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
586 if (g->offset_y == 0) /* frames are ordered horizontally */
588 int max_width = g->anim_frames_per_line * g->width;
589 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
591 *x = pos % max_width;
592 *y = src_y % g->height + pos / max_width * g->height;
594 else if (g->offset_x == 0) /* frames are ordered vertically */
596 int max_height = g->anim_frames_per_line * g->height;
597 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
599 *x = src_x % g->width + pos / max_height * g->width;
600 *y = pos % max_height;
602 else /* frames are ordered diagonally */
604 *x = src_x + frame * g->offset_x;
605 *y = src_y + frame * g->offset_y;
609 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
611 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
614 void DrawGraphic(int x, int y, int graphic, int frame)
617 if (!IN_SCR_FIELD(x, y))
619 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
620 printf("DrawGraphic(): This should never happen!\n");
625 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
629 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
635 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
636 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
639 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
642 if (!IN_SCR_FIELD(x, y))
644 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
645 printf("DrawGraphicThruMask(): This should never happen!\n");
650 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
655 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
661 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
663 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
664 dst_x - src_x, dst_y - src_y);
665 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
668 void DrawMiniGraphic(int x, int y, int graphic)
670 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
671 MarkTileDirty(x / 2, y / 2);
674 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
676 struct GraphicInfo *g = &graphic_info[graphic];
678 int mini_starty = g->bitmap->height * 2 / 3;
681 *x = mini_startx + g->src_x / 2;
682 *y = mini_starty + g->src_y / 2;
685 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
690 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
691 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
694 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
695 int graphic, int frame,
696 int cut_mode, int mask_mode)
701 int width = TILEX, height = TILEY;
704 if (dx || dy) /* shifted graphic */
706 if (x < BX1) /* object enters playfield from the left */
713 else if (x > BX2) /* object enters playfield from the right */
719 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
725 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
727 else if (dx) /* general horizontal movement */
728 MarkTileDirty(x + SIGN(dx), y);
730 if (y < BY1) /* object enters playfield from the top */
732 if (cut_mode==CUT_BELOW) /* object completely above top border */
740 else if (y > BY2) /* object enters playfield from the bottom */
746 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
752 else if (dy > 0 && cut_mode == CUT_ABOVE)
754 if (y == BY2) /* object completely above bottom border */
760 MarkTileDirty(x, y + 1);
761 } /* object leaves playfield to the bottom */
762 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
764 else if (dy) /* general vertical movement */
765 MarkTileDirty(x, y + SIGN(dy));
769 if (!IN_SCR_FIELD(x, y))
771 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
772 printf("DrawGraphicShifted(): This should never happen!\n");
777 if (width > 0 && height > 0)
779 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
784 dst_x = FX + x * TILEX + dx;
785 dst_y = FY + y * TILEY + dy;
787 if (mask_mode == USE_MASKING)
789 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
790 dst_x - src_x, dst_y - src_y);
791 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
795 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
802 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
803 int graphic, int frame,
804 int cut_mode, int mask_mode)
809 int width = TILEX, height = TILEY;
812 int x2 = x + SIGN(dx);
813 int y2 = y + SIGN(dy);
814 int anim_frames = graphic_info[graphic].anim_frames;
815 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
816 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
817 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
819 /* re-calculate animation frame for two-tile movement animation */
820 frame = getGraphicAnimationFrame(graphic, sync_frame);
822 /* check if movement start graphic inside screen area and should be drawn */
823 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
825 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
827 dst_x = FX + x1 * TILEX;
828 dst_y = FY + y1 * TILEY;
830 if (mask_mode == USE_MASKING)
832 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
833 dst_x - src_x, dst_y - src_y);
834 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
838 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
841 MarkTileDirty(x1, y1);
844 /* check if movement end graphic inside screen area and should be drawn */
845 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
847 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
849 dst_x = FX + x2 * TILEX;
850 dst_y = FY + y2 * TILEY;
852 if (mask_mode == USE_MASKING)
854 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
855 dst_x - src_x, dst_y - src_y);
856 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
860 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
863 MarkTileDirty(x2, y2);
867 static void DrawGraphicShifted(int x, int y, int dx, int dy,
868 int graphic, int frame,
869 int cut_mode, int mask_mode)
873 DrawGraphic(x, y, graphic, frame);
878 if (graphic_info[graphic].double_movement) /* EM style movement images */
879 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
881 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
884 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
885 int frame, int cut_mode)
887 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
890 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
891 int cut_mode, int mask_mode)
893 int lx = LEVELX(x), ly = LEVELY(y);
897 if (IN_LEV_FIELD(lx, ly))
899 SetRandomAnimationValue(lx, ly);
901 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
902 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
904 /* do not use double (EM style) movement graphic when not moving */
905 if (graphic_info[graphic].double_movement && !dx && !dy)
907 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
908 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
911 else /* border element */
913 graphic = el2img(element);
914 frame = getGraphicAnimationFrame(graphic, -1);
917 if (element == EL_EXPANDABLE_WALL)
919 boolean left_stopped = FALSE, right_stopped = FALSE;
921 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
923 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
924 right_stopped = TRUE;
926 if (left_stopped && right_stopped)
928 else if (left_stopped)
930 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
931 frame = graphic_info[graphic].anim_frames - 1;
933 else if (right_stopped)
935 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
936 frame = graphic_info[graphic].anim_frames - 1;
941 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
942 else if (mask_mode == USE_MASKING)
943 DrawGraphicThruMask(x, y, graphic, frame);
945 DrawGraphic(x, y, graphic, frame);
948 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
949 int cut_mode, int mask_mode)
951 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
952 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
953 cut_mode, mask_mode);
956 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
959 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
962 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
965 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
968 void DrawLevelElementThruMask(int x, int y, int element)
970 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
973 void DrawLevelFieldThruMask(int x, int y)
975 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
978 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
982 int sx = SCREENX(x), sy = SCREENY(y);
984 int width, height, cx, cy, i;
985 int crumbled_border_size = graphic_info[graphic].border_size;
986 static int xy[4][2] =
994 if (!IN_LEV_FIELD(x, y))
997 element = TILE_GFX_ELEMENT(x, y);
999 /* crumble field itself */
1000 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1002 if (!IN_SCR_FIELD(sx, sy))
1005 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1007 for (i = 0; i < 4; i++)
1009 int xx = x + xy[i][0];
1010 int yy = y + xy[i][1];
1012 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1015 /* check if neighbour field is of same type */
1016 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1019 if (i == 1 || i == 2)
1021 width = crumbled_border_size;
1023 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1029 height = crumbled_border_size;
1031 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1034 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1035 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1038 MarkTileDirty(sx, sy);
1040 else /* crumble neighbour fields */
1042 for (i = 0; i < 4; i++)
1044 int xx = x + xy[i][0];
1045 int yy = y + xy[i][1];
1046 int sxx = sx + xy[i][0];
1047 int syy = sy + xy[i][1];
1050 if (!IN_LEV_FIELD(xx, yy) ||
1051 !IN_SCR_FIELD(sxx, syy) ||
1056 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1060 element = TILE_GFX_ELEMENT(xx, yy);
1062 if (!GFX_CRUMBLED(element))
1065 if (!IN_LEV_FIELD(xx, yy) ||
1066 !IN_SCR_FIELD(sxx, syy) ||
1067 !GFX_CRUMBLED(Feld[xx][yy]) ||
1073 graphic = el_act2crm(element, ACTION_DEFAULT);
1075 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1077 crumbled_border_size = graphic_info[graphic].border_size;
1079 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1081 if (i == 1 || i == 2)
1083 width = crumbled_border_size;
1085 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1091 height = crumbled_border_size;
1093 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1096 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1097 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1099 MarkTileDirty(sxx, syy);
1104 void DrawLevelFieldCrumbledSand(int x, int y)
1108 if (!IN_LEV_FIELD(x, y))
1112 /* !!! CHECK THIS !!! */
1115 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1116 GFX_CRUMBLED(GfxElement[x][y]))
1119 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1120 GfxElement[x][y] != EL_UNDEFINED &&
1121 GFX_CRUMBLED(GfxElement[x][y]))
1123 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1130 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1132 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1135 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1138 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1141 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1142 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1143 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1144 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1145 int sx = SCREENX(x), sy = SCREENY(y);
1147 DrawGraphic(sx, sy, graphic1, frame1);
1148 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1151 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1153 int sx = SCREENX(x), sy = SCREENY(y);
1154 static int xy[4][2] =
1163 for (i = 0; i < 4; i++)
1165 int xx = x + xy[i][0];
1166 int yy = y + xy[i][1];
1167 int sxx = sx + xy[i][0];
1168 int syy = sy + xy[i][1];
1170 if (!IN_LEV_FIELD(xx, yy) ||
1171 !IN_SCR_FIELD(sxx, syy) ||
1172 !GFX_CRUMBLED(Feld[xx][yy]) ||
1176 DrawLevelField(xx, yy);
1180 static int getBorderElement(int x, int y)
1184 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1185 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1186 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1187 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1188 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1189 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1190 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1192 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1193 int steel_position = (x == -1 && y == -1 ? 0 :
1194 x == lev_fieldx && y == -1 ? 1 :
1195 x == -1 && y == lev_fieldy ? 2 :
1196 x == lev_fieldx && y == lev_fieldy ? 3 :
1197 x == -1 || x == lev_fieldx ? 4 :
1198 y == -1 || y == lev_fieldy ? 5 : 6);
1200 return border[steel_position][steel_type];
1203 void DrawScreenElement(int x, int y, int element)
1205 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1206 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1209 void DrawLevelElement(int x, int y, int element)
1211 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1212 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1215 void DrawScreenField(int x, int y)
1217 int lx = LEVELX(x), ly = LEVELY(y);
1218 int element, content;
1220 if (!IN_LEV_FIELD(lx, ly))
1222 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1225 element = getBorderElement(lx, ly);
1227 DrawScreenElement(x, y, element);
1231 element = Feld[lx][ly];
1232 content = Store[lx][ly];
1234 if (IS_MOVING(lx, ly))
1236 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1237 boolean cut_mode = NO_CUTTING;
1239 if (element == EL_QUICKSAND_EMPTYING ||
1240 element == EL_MAGIC_WALL_EMPTYING ||
1241 element == EL_BD_MAGIC_WALL_EMPTYING ||
1242 element == EL_AMOEBA_DROPPING)
1243 cut_mode = CUT_ABOVE;
1244 else if (element == EL_QUICKSAND_FILLING ||
1245 element == EL_MAGIC_WALL_FILLING ||
1246 element == EL_BD_MAGIC_WALL_FILLING)
1247 cut_mode = CUT_BELOW;
1249 if (cut_mode == CUT_ABOVE)
1250 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1252 DrawScreenElement(x, y, EL_EMPTY);
1255 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1256 else if (cut_mode == NO_CUTTING)
1257 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1259 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1261 if (content == EL_ACID)
1263 int dir = MovDir[lx][ly];
1264 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1265 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1267 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1270 else if (IS_BLOCKED(lx, ly))
1275 boolean cut_mode = NO_CUTTING;
1276 int element_old, content_old;
1278 Blocked2Moving(lx, ly, &oldx, &oldy);
1281 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1282 MovDir[oldx][oldy] == MV_RIGHT);
1284 element_old = Feld[oldx][oldy];
1285 content_old = Store[oldx][oldy];
1287 if (element_old == EL_QUICKSAND_EMPTYING ||
1288 element_old == EL_MAGIC_WALL_EMPTYING ||
1289 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1290 element_old == EL_AMOEBA_DROPPING)
1291 cut_mode = CUT_ABOVE;
1293 DrawScreenElement(x, y, EL_EMPTY);
1296 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1298 else if (cut_mode == NO_CUTTING)
1299 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1302 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1305 else if (IS_DRAWABLE(element))
1306 DrawScreenElement(x, y, element);
1308 DrawScreenElement(x, y, EL_EMPTY);
1311 void DrawLevelField(int x, int y)
1313 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1314 DrawScreenField(SCREENX(x), SCREENY(y));
1315 else if (IS_MOVING(x, y))
1319 Moving2Blocked(x, y, &newx, &newy);
1320 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1321 DrawScreenField(SCREENX(newx), SCREENY(newy));
1323 else if (IS_BLOCKED(x, y))
1327 Blocked2Moving(x, y, &oldx, &oldy);
1328 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1329 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1333 void DrawMiniElement(int x, int y, int element)
1337 graphic = el2edimg(element);
1338 DrawMiniGraphic(x, y, graphic);
1341 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1343 int x = sx + scroll_x, y = sy + scroll_y;
1345 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1346 DrawMiniElement(sx, sy, EL_EMPTY);
1347 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1348 DrawMiniElement(sx, sy, Feld[x][y]);
1350 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1353 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1354 int x, int y, int xsize, int ysize, int font_nr)
1356 int font_width = getFontWidth(font_nr);
1357 int font_height = getFontHeight(font_nr);
1358 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1361 int dst_x = SX + startx + x * font_width;
1362 int dst_y = SY + starty + y * font_height;
1363 int width = graphic_info[graphic].width;
1364 int height = graphic_info[graphic].height;
1365 int inner_width = MAX(width - 2 * font_width, font_width);
1366 int inner_height = MAX(height - 2 * font_height, font_height);
1367 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1368 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1369 boolean draw_masked = graphic_info[graphic].draw_masked;
1371 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1373 if (src_bitmap == NULL || width < font_width || height < font_height)
1375 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1379 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1380 inner_sx + (x - 1) * font_width % inner_width);
1381 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1382 inner_sy + (y - 1) * font_height % inner_height);
1386 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1387 dst_x - src_x, dst_y - src_y);
1388 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1392 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1396 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1398 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1399 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1400 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1401 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1402 boolean no_delay = (tape.warp_forward);
1403 unsigned long anim_delay = 0;
1404 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1405 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1406 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1407 int font_width = getFontWidth(font_nr);
1408 int font_height = getFontHeight(font_nr);
1409 int max_xsize = level.envelope[envelope_nr].xsize;
1410 int max_ysize = level.envelope[envelope_nr].ysize;
1411 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1412 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1413 int xend = max_xsize;
1414 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1415 int xstep = (xstart < xend ? 1 : 0);
1416 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1419 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1421 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1422 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1423 int sx = (SXSIZE - xsize * font_width) / 2;
1424 int sy = (SYSIZE - ysize * font_height) / 2;
1427 SetDrawtoField(DRAW_BUFFERED);
1429 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1431 SetDrawtoField(DRAW_BACKBUFFER);
1433 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1434 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1436 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1437 level.envelope[envelope_nr].text, font_nr, max_xsize,
1438 xsize - 2, ysize - 2, mask_mode);
1440 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1443 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1447 void ShowEnvelope(int envelope_nr)
1449 int element = EL_ENVELOPE_1 + envelope_nr;
1450 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1451 int sound_opening = element_info[element].sound[ACTION_OPENING];
1452 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1453 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1454 boolean no_delay = (tape.warp_forward);
1455 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1456 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1457 int anim_mode = graphic_info[graphic].anim_mode;
1458 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1459 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1461 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1463 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1465 if (anim_mode == ANIM_DEFAULT)
1466 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1468 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1471 Delay(wait_delay_value);
1473 WaitForEventToContinue();
1475 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1477 if (anim_mode != ANIM_NONE)
1478 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1480 if (anim_mode == ANIM_DEFAULT)
1481 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1483 game.envelope_active = FALSE;
1485 SetDrawtoField(DRAW_BUFFERED);
1487 redraw_mask |= REDRAW_FIELD;
1491 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1496 int width_mult, width_div;
1497 int height_mult, height_div;
1505 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1506 5 - log_2(tilesize));
1507 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1508 int width_mult = offset_calc[offset_calc_pos].width_mult;
1509 int width_div = offset_calc[offset_calc_pos].width_div;
1510 int height_mult = offset_calc[offset_calc_pos].height_mult;
1511 int height_div = offset_calc[offset_calc_pos].height_div;
1512 int mini_startx = src_bitmap->width * width_mult / width_div;
1513 int mini_starty = src_bitmap->height * height_mult / height_div;
1514 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1515 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1517 *bitmap = src_bitmap;
1522 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1526 int graphic = el2preimg(element);
1528 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1529 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1536 SetDrawBackgroundMask(REDRAW_NONE);
1539 for (x = BX1; x <= BX2; x++)
1540 for (y = BY1; y <= BY2; y++)
1541 DrawScreenField(x, y);
1543 redraw_mask |= REDRAW_FIELD;
1546 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1550 for (x = 0; x < size_x; x++)
1551 for (y = 0; y < size_y; y++)
1552 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1554 redraw_mask |= REDRAW_FIELD;
1557 static void DrawPreviewLevelExt(int from_x, int from_y)
1559 boolean show_level_border = (BorderElement != EL_EMPTY);
1560 int dst_x = preview.x;
1561 int dst_y = preview.y;
1562 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1563 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1564 int tile_size = preview.tile_size;
1565 int preview_width = preview.xsize * tile_size;
1566 int preview_height = preview.ysize * tile_size;
1567 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1568 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1571 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1573 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1574 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1576 for (x = 0; x < real_preview_xsize; x++)
1578 for (y = 0; y < real_preview_ysize; y++)
1580 int lx = from_x + x + (show_level_border ? -1 : 0);
1581 int ly = from_y + y + (show_level_border ? -1 : 0);
1582 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1583 getBorderElement(lx, ly));
1585 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1586 element, tile_size);
1590 redraw_mask |= REDRAW_MICROLEVEL;
1593 #define MICROLABEL_EMPTY 0
1594 #define MICROLABEL_LEVEL_NAME 1
1595 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1596 #define MICROLABEL_LEVEL_AUTHOR 3
1597 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1598 #define MICROLABEL_IMPORTED_FROM 5
1599 #define MICROLABEL_IMPORTED_BY_HEAD 6
1600 #define MICROLABEL_IMPORTED_BY 7
1602 static void DrawPreviewLevelLabelExt(int mode)
1604 char label_text[MAX_OUTPUT_LINESIZE + 1];
1605 int max_len_label_text;
1606 int font_nr = FONT_TEXT_2;
1609 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1610 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1611 mode == MICROLABEL_IMPORTED_BY_HEAD)
1612 font_nr = FONT_TEXT_3;
1614 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1616 for (i = 0; i < max_len_label_text; i++)
1617 label_text[i] = ' ';
1618 label_text[max_len_label_text] = '\0';
1620 if (strlen(label_text) > 0)
1622 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1623 int lypos = MICROLABEL2_YPOS;
1625 DrawText(lxpos, lypos, label_text, font_nr);
1629 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1630 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1631 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1632 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1633 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1634 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1635 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1636 max_len_label_text);
1637 label_text[max_len_label_text] = '\0';
1639 if (strlen(label_text) > 0)
1641 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1642 int lypos = MICROLABEL2_YPOS;
1644 DrawText(lxpos, lypos, label_text, font_nr);
1647 redraw_mask |= REDRAW_MICROLEVEL;
1650 void DrawPreviewLevel(boolean restart)
1652 static unsigned long scroll_delay = 0;
1653 static unsigned long label_delay = 0;
1654 static int from_x, from_y, scroll_direction;
1655 static int label_state, label_counter;
1656 unsigned long scroll_delay_value = preview.step_delay;
1657 boolean show_level_border = (BorderElement != EL_EMPTY);
1658 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1659 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1660 int last_game_status = game_status; /* save current game status */
1662 /* force PREVIEW font on preview level */
1663 game_status = GAME_MODE_PSEUDO_PREVIEW;
1667 from_x = from_y = 0;
1668 scroll_direction = MV_RIGHT;
1672 DrawPreviewLevelExt(from_x, from_y);
1673 DrawPreviewLevelLabelExt(label_state);
1675 /* initialize delay counters */
1676 DelayReached(&scroll_delay, 0);
1677 DelayReached(&label_delay, 0);
1679 if (leveldir_current->name)
1681 char label_text[MAX_OUTPUT_LINESIZE + 1];
1682 int font_nr = FONT_TEXT_1;
1683 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1686 strncpy(label_text, leveldir_current->name, max_len_label_text);
1687 label_text[max_len_label_text] = '\0';
1689 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1690 lypos = SY + MICROLABEL1_YPOS;
1692 DrawText(lxpos, lypos, label_text, font_nr);
1695 game_status = last_game_status; /* restore current game status */
1700 /* scroll preview level, if needed */
1701 if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1702 DelayReached(&scroll_delay, scroll_delay_value))
1704 switch (scroll_direction)
1709 from_x -= preview.step_offset;
1710 from_x = (from_x < 0 ? 0 : from_x);
1713 scroll_direction = MV_UP;
1717 if (from_x < level_xsize - preview.xsize)
1719 from_x += preview.step_offset;
1720 from_x = (from_x > level_xsize - preview.xsize ?
1721 level_xsize - preview.xsize : from_x);
1724 scroll_direction = MV_DOWN;
1730 from_y -= preview.step_offset;
1731 from_y = (from_y < 0 ? 0 : from_y);
1734 scroll_direction = MV_RIGHT;
1738 if (from_y < level_ysize - preview.ysize)
1740 from_y += preview.step_offset;
1741 from_y = (from_y > level_ysize - preview.ysize ?
1742 level_ysize - preview.ysize : from_y);
1745 scroll_direction = MV_LEFT;
1752 DrawPreviewLevelExt(from_x, from_y);
1755 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1756 /* redraw micro level label, if needed */
1757 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1758 !strEqual(level.author, ANONYMOUS_NAME) &&
1759 !strEqual(level.author, leveldir_current->name) &&
1760 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1762 int max_label_counter = 23;
1764 if (leveldir_current->imported_from != NULL &&
1765 strlen(leveldir_current->imported_from) > 0)
1766 max_label_counter += 14;
1767 if (leveldir_current->imported_by != NULL &&
1768 strlen(leveldir_current->imported_by) > 0)
1769 max_label_counter += 14;
1771 label_counter = (label_counter + 1) % max_label_counter;
1772 label_state = (label_counter >= 0 && label_counter <= 7 ?
1773 MICROLABEL_LEVEL_NAME :
1774 label_counter >= 9 && label_counter <= 12 ?
1775 MICROLABEL_LEVEL_AUTHOR_HEAD :
1776 label_counter >= 14 && label_counter <= 21 ?
1777 MICROLABEL_LEVEL_AUTHOR :
1778 label_counter >= 23 && label_counter <= 26 ?
1779 MICROLABEL_IMPORTED_FROM_HEAD :
1780 label_counter >= 28 && label_counter <= 35 ?
1781 MICROLABEL_IMPORTED_FROM :
1782 label_counter >= 37 && label_counter <= 40 ?
1783 MICROLABEL_IMPORTED_BY_HEAD :
1784 label_counter >= 42 && label_counter <= 49 ?
1785 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1787 if (leveldir_current->imported_from == NULL &&
1788 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1789 label_state == MICROLABEL_IMPORTED_FROM))
1790 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1791 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1793 DrawPreviewLevelLabelExt(label_state);
1796 game_status = last_game_status; /* restore current game status */
1799 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1800 int graphic, int sync_frame, int mask_mode)
1802 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1804 if (mask_mode == USE_MASKING)
1805 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1807 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1810 inline void DrawGraphicAnimation(int x, int y, int graphic)
1812 int lx = LEVELX(x), ly = LEVELY(y);
1814 if (!IN_SCR_FIELD(x, y))
1817 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1818 graphic, GfxFrame[lx][ly], NO_MASKING);
1819 MarkTileDirty(x, y);
1822 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1824 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1827 void DrawLevelElementAnimation(int x, int y, int element)
1829 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1831 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1834 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1836 int sx = SCREENX(x), sy = SCREENY(y);
1838 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1841 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1844 DrawGraphicAnimation(sx, sy, graphic);
1847 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1848 DrawLevelFieldCrumbledSand(x, y);
1850 if (GFX_CRUMBLED(Feld[x][y]))
1851 DrawLevelFieldCrumbledSand(x, y);
1855 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1857 int sx = SCREENX(x), sy = SCREENY(y);
1860 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1863 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1865 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1868 DrawGraphicAnimation(sx, sy, graphic);
1870 if (GFX_CRUMBLED(element))
1871 DrawLevelFieldCrumbledSand(x, y);
1874 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1876 if (player->use_murphy)
1878 /* this works only because currently only one player can be "murphy" ... */
1879 static int last_horizontal_dir = MV_LEFT;
1880 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1882 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1883 last_horizontal_dir = move_dir;
1885 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1887 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1889 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1895 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1898 static boolean equalGraphics(int graphic1, int graphic2)
1900 struct GraphicInfo *g1 = &graphic_info[graphic1];
1901 struct GraphicInfo *g2 = &graphic_info[graphic2];
1903 return (g1->bitmap == g2->bitmap &&
1904 g1->src_x == g2->src_x &&
1905 g1->src_y == g2->src_y &&
1906 g1->anim_frames == g2->anim_frames &&
1907 g1->anim_delay == g2->anim_delay &&
1908 g1->anim_mode == g2->anim_mode);
1911 void DrawAllPlayers()
1915 for (i = 0; i < MAX_PLAYERS; i++)
1916 if (stored_player[i].active)
1917 DrawPlayer(&stored_player[i]);
1920 void DrawPlayerField(int x, int y)
1922 if (!IS_PLAYER(x, y))
1925 DrawPlayer(PLAYERINFO(x, y));
1928 void DrawPlayer(struct PlayerInfo *player)
1930 int jx = player->jx;
1931 int jy = player->jy;
1932 int move_dir = player->MovDir;
1933 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1934 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1935 int last_jx = (player->is_moving ? jx - dx : jx);
1936 int last_jy = (player->is_moving ? jy - dy : jy);
1937 int next_jx = jx + dx;
1938 int next_jy = jy + dy;
1939 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1940 boolean player_is_opaque = FALSE;
1941 int sx = SCREENX(jx), sy = SCREENY(jy);
1942 int sxx = 0, syy = 0;
1943 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1945 int action = ACTION_DEFAULT;
1946 int last_player_graphic = getPlayerGraphic(player, move_dir);
1947 int last_player_frame = player->Frame;
1951 /* GfxElement[][] is set to the element the player is digging or collecting;
1952 remove also for off-screen player if the player is not moving anymore */
1953 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1954 GfxElement[jx][jy] = EL_UNDEFINED;
1957 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1961 if (!IN_LEV_FIELD(jx, jy))
1963 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1964 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1965 printf("DrawPlayerField(): This should never happen!\n");
1970 if (element == EL_EXPLOSION)
1973 action = (player->is_pushing ? ACTION_PUSHING :
1974 player->is_digging ? ACTION_DIGGING :
1975 player->is_collecting ? ACTION_COLLECTING :
1976 player->is_moving ? ACTION_MOVING :
1977 player->is_snapping ? ACTION_SNAPPING :
1978 player->is_dropping ? ACTION_DROPPING :
1979 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1982 if (player->is_waiting)
1983 move_dir = player->dir_waiting;
1986 InitPlayerGfxAnimation(player, action, move_dir);
1988 /* ----------------------------------------------------------------------- */
1989 /* draw things in the field the player is leaving, if needed */
1990 /* ----------------------------------------------------------------------- */
1992 if (player->is_moving)
1994 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1996 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1998 if (last_element == EL_DYNAMITE_ACTIVE ||
1999 last_element == EL_EM_DYNAMITE_ACTIVE ||
2000 last_element == EL_SP_DISK_RED_ACTIVE)
2001 DrawDynamite(last_jx, last_jy);
2003 DrawLevelFieldThruMask(last_jx, last_jy);
2005 else if (last_element == EL_DYNAMITE_ACTIVE ||
2006 last_element == EL_EM_DYNAMITE_ACTIVE ||
2007 last_element == EL_SP_DISK_RED_ACTIVE)
2008 DrawDynamite(last_jx, last_jy);
2010 /* !!! this is not enough to prevent flickering of players which are
2011 moving next to each others without a free tile between them -- this
2012 can only be solved by drawing all players layer by layer (first the
2013 background, then the foreground etc.) !!! => TODO */
2014 else if (!IS_PLAYER(last_jx, last_jy))
2015 DrawLevelField(last_jx, last_jy);
2018 DrawLevelField(last_jx, last_jy);
2021 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2022 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2025 if (!IN_SCR_FIELD(sx, sy))
2028 if (setup.direct_draw)
2029 SetDrawtoField(DRAW_BUFFERED);
2031 /* ----------------------------------------------------------------------- */
2032 /* draw things behind the player, if needed */
2033 /* ----------------------------------------------------------------------- */
2036 DrawLevelElement(jx, jy, Back[jx][jy]);
2037 else if (IS_ACTIVE_BOMB(element))
2038 DrawLevelElement(jx, jy, EL_EMPTY);
2041 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2043 int old_element = GfxElement[jx][jy];
2044 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2045 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2047 if (GFX_CRUMBLED(old_element))
2048 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2050 DrawGraphic(sx, sy, old_graphic, frame);
2052 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2053 player_is_opaque = TRUE;
2057 GfxElement[jx][jy] = EL_UNDEFINED;
2059 /* make sure that pushed elements are drawn with correct frame rate */
2060 if (player->is_pushing && player->is_moving)
2061 GfxFrame[jx][jy] = player->StepFrame;
2063 DrawLevelField(jx, jy);
2067 /* ----------------------------------------------------------------------- */
2068 /* draw player himself */
2069 /* ----------------------------------------------------------------------- */
2071 graphic = getPlayerGraphic(player, move_dir);
2073 /* in the case of changed player action or direction, prevent the current
2074 animation frame from being restarted for identical animations */
2075 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2076 player->Frame = last_player_frame;
2078 frame = getGraphicAnimationFrame(graphic, player->Frame);
2082 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2083 sxx = player->GfxPos;
2085 syy = player->GfxPos;
2088 if (!setup.soft_scrolling && ScreenMovPos)
2091 if (player_is_opaque)
2092 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2094 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2096 if (SHIELD_ON(player))
2098 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2099 IMG_SHIELD_NORMAL_ACTIVE);
2100 int frame = getGraphicAnimationFrame(graphic, -1);
2102 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2105 /* ----------------------------------------------------------------------- */
2106 /* draw things the player is pushing, if needed */
2107 /* ----------------------------------------------------------------------- */
2110 printf("::: %d, %d [%d, %d] [%d]\n",
2111 player->is_pushing, player_is_moving, player->GfxAction,
2112 player->is_moving, player_is_moving);
2116 if (player->is_pushing && player->is_moving)
2118 int px = SCREENX(jx), py = SCREENY(jy);
2119 int pxx = (TILEX - ABS(sxx)) * dx;
2120 int pyy = (TILEY - ABS(syy)) * dy;
2125 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2126 element = Feld[next_jx][next_jy];
2128 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2129 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2131 /* draw background element under pushed element (like the Sokoban field) */
2132 if (Back[next_jx][next_jy])
2133 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2135 /* masked drawing is needed for EMC style (double) movement graphics */
2136 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2140 /* ----------------------------------------------------------------------- */
2141 /* draw things in front of player (active dynamite or dynabombs) */
2142 /* ----------------------------------------------------------------------- */
2144 if (IS_ACTIVE_BOMB(element))
2146 graphic = el2img(element);
2147 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2149 if (game.emulation == EMU_SUPAPLEX)
2150 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2152 DrawGraphicThruMask(sx, sy, graphic, frame);
2155 if (player_is_moving && last_element == EL_EXPLOSION)
2157 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2158 GfxElement[last_jx][last_jy] : EL_EMPTY);
2159 int graphic = el_act2img(element, ACTION_EXPLODING);
2160 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2161 int phase = ExplodePhase[last_jx][last_jy] - 1;
2162 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2165 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2168 /* ----------------------------------------------------------------------- */
2169 /* draw elements the player is just walking/passing through/under */
2170 /* ----------------------------------------------------------------------- */
2172 if (player_is_moving)
2174 /* handle the field the player is leaving ... */
2175 if (IS_ACCESSIBLE_INSIDE(last_element))
2176 DrawLevelField(last_jx, last_jy);
2177 else if (IS_ACCESSIBLE_UNDER(last_element))
2178 DrawLevelFieldThruMask(last_jx, last_jy);
2181 /* do not redraw accessible elements if the player is just pushing them */
2182 if (!player_is_moving || !player->is_pushing)
2184 /* ... and the field the player is entering */
2185 if (IS_ACCESSIBLE_INSIDE(element))
2186 DrawLevelField(jx, jy);
2187 else if (IS_ACCESSIBLE_UNDER(element))
2188 DrawLevelFieldThruMask(jx, jy);
2191 if (setup.direct_draw)
2193 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2194 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2195 int x_size = TILEX * (1 + ABS(jx - last_jx));
2196 int y_size = TILEY * (1 + ABS(jy - last_jy));
2198 BlitBitmap(drawto_field, window,
2199 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2200 SetDrawtoField(DRAW_DIRECT);
2203 MarkTileDirty(sx, sy);
2206 /* ------------------------------------------------------------------------- */
2208 void WaitForEventToContinue()
2210 boolean still_wait = TRUE;
2212 /* simulate releasing mouse button over last gadget, if still pressed */
2214 HandleGadgets(-1, -1, 0);
2216 button_status = MB_RELEASED;
2228 case EVENT_BUTTONPRESS:
2229 case EVENT_KEYPRESS:
2233 case EVENT_KEYRELEASE:
2234 ClearPlayerAction();
2238 HandleOtherEvents(&event);
2242 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2249 /* don't eat all CPU time */
2254 #define MAX_REQUEST_LINES 13
2255 #define MAX_REQUEST_LINE_FONT1_LEN 7
2256 #define MAX_REQUEST_LINE_FONT2_LEN 10
2258 boolean Request(char *text, unsigned int req_state)
2260 int mx, my, ty, result = -1;
2261 unsigned int old_door_state;
2262 int last_game_status = game_status; /* save current game status */
2263 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2264 int font_nr = FONT_TEXT_2;
2265 int max_word_len = 0;
2268 for (text_ptr = text; *text_ptr; text_ptr++)
2270 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2272 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2274 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2275 font_nr = FONT_LEVEL_NUMBER;
2281 if (game_status == GAME_MODE_PLAYING &&
2282 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2283 BlitScreenToBitmap_EM(backbuffer);
2285 /* disable deactivated drawing when quick-loading level tape recording */
2286 if (tape.playing && tape.deactivate_display)
2287 TapeDeactivateDisplayOff(TRUE);
2289 SetMouseCursor(CURSOR_DEFAULT);
2291 #if defined(NETWORK_AVALIABLE)
2292 /* pause network game while waiting for request to answer */
2293 if (options.network &&
2294 game_status == GAME_MODE_PLAYING &&
2295 req_state & REQUEST_WAIT_FOR_INPUT)
2296 SendToServer_PausePlaying();
2299 old_door_state = GetDoorState();
2301 /* simulate releasing mouse button over last gadget, if still pressed */
2303 HandleGadgets(-1, -1, 0);
2307 if (old_door_state & DOOR_OPEN_1)
2309 CloseDoor(DOOR_CLOSE_1);
2311 /* save old door content */
2312 BlitBitmap(bitmap_db_door, bitmap_db_door,
2313 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2314 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2318 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2321 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2323 /* clear door drawing field */
2324 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2326 /* force DOOR font on preview level */
2327 game_status = GAME_MODE_PSEUDO_DOOR;
2329 /* write text for request */
2330 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2332 char text_line[max_request_line_len + 1];
2338 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2341 if (!tc || tc == ' ')
2352 strncpy(text_line, text, tl);
2355 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2356 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2357 text_line, font_nr);
2359 text += tl + (tc == ' ' ? 1 : 0);
2362 game_status = last_game_status; /* restore current game status */
2364 if (req_state & REQ_ASK)
2366 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2367 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2369 else if (req_state & REQ_CONFIRM)
2371 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2373 else if (req_state & REQ_PLAYER)
2375 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2376 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2377 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2378 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2381 /* copy request gadgets to door backbuffer */
2382 BlitBitmap(drawto, bitmap_db_door,
2383 DX, DY, DXSIZE, DYSIZE,
2384 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2386 OpenDoor(DOOR_OPEN_1);
2388 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2390 if (game_status == GAME_MODE_PLAYING)
2392 SetPanelBackground();
2393 SetDrawBackgroundMask(REDRAW_DOOR_1);
2397 SetDrawBackgroundMask(REDRAW_FIELD);
2403 if (game_status != GAME_MODE_MAIN)
2406 button_status = MB_RELEASED;
2408 request_gadget_id = -1;
2410 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2422 case EVENT_BUTTONPRESS:
2423 case EVENT_BUTTONRELEASE:
2424 case EVENT_MOTIONNOTIFY:
2426 if (event.type == EVENT_MOTIONNOTIFY)
2428 if (!PointerInWindow(window))
2429 continue; /* window and pointer are on different screens */
2434 motion_status = TRUE;
2435 mx = ((MotionEvent *) &event)->x;
2436 my = ((MotionEvent *) &event)->y;
2440 motion_status = FALSE;
2441 mx = ((ButtonEvent *) &event)->x;
2442 my = ((ButtonEvent *) &event)->y;
2443 if (event.type == EVENT_BUTTONPRESS)
2444 button_status = ((ButtonEvent *) &event)->button;
2446 button_status = MB_RELEASED;
2449 /* this sets 'request_gadget_id' */
2450 HandleGadgets(mx, my, button_status);
2452 switch(request_gadget_id)
2454 case TOOL_CTRL_ID_YES:
2457 case TOOL_CTRL_ID_NO:
2460 case TOOL_CTRL_ID_CONFIRM:
2461 result = TRUE | FALSE;
2464 case TOOL_CTRL_ID_PLAYER_1:
2467 case TOOL_CTRL_ID_PLAYER_2:
2470 case TOOL_CTRL_ID_PLAYER_3:
2473 case TOOL_CTRL_ID_PLAYER_4:
2484 case EVENT_KEYPRESS:
2485 switch(GetEventKey((KeyEvent *)&event, TRUE))
2498 if (req_state & REQ_PLAYER)
2502 case EVENT_KEYRELEASE:
2503 ClearPlayerAction();
2507 HandleOtherEvents(&event);
2511 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2513 int joy = AnyJoystick();
2515 if (joy & JOY_BUTTON_1)
2517 else if (joy & JOY_BUTTON_2)
2523 /* don't eat all CPU time */
2527 if (game_status != GAME_MODE_MAIN)
2532 if (!(req_state & REQ_STAY_OPEN))
2534 CloseDoor(DOOR_CLOSE_1);
2536 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2537 (req_state & REQ_REOPEN))
2538 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2543 if (game_status == GAME_MODE_PLAYING)
2545 SetPanelBackground();
2546 SetDrawBackgroundMask(REDRAW_DOOR_1);
2550 SetDrawBackgroundMask(REDRAW_FIELD);
2553 #if defined(NETWORK_AVALIABLE)
2554 /* continue network game after request */
2555 if (options.network &&
2556 game_status == GAME_MODE_PLAYING &&
2557 req_state & REQUEST_WAIT_FOR_INPUT)
2558 SendToServer_ContinuePlaying();
2561 /* restore deactivated drawing when quick-loading level tape recording */
2562 if (tape.playing && tape.deactivate_display)
2563 TapeDeactivateDisplayOn();
2568 unsigned int OpenDoor(unsigned int door_state)
2570 if (door_state & DOOR_COPY_BACK)
2572 if (door_state & DOOR_OPEN_1)
2573 BlitBitmap(bitmap_db_door, bitmap_db_door,
2574 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2575 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2577 if (door_state & DOOR_OPEN_2)
2578 BlitBitmap(bitmap_db_door, bitmap_db_door,
2579 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2580 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2582 door_state &= ~DOOR_COPY_BACK;
2585 return MoveDoor(door_state);
2588 unsigned int CloseDoor(unsigned int door_state)
2590 unsigned int old_door_state = GetDoorState();
2592 if (!(door_state & DOOR_NO_COPY_BACK))
2594 if (old_door_state & DOOR_OPEN_1)
2595 BlitBitmap(backbuffer, bitmap_db_door,
2596 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2598 if (old_door_state & DOOR_OPEN_2)
2599 BlitBitmap(backbuffer, bitmap_db_door,
2600 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2602 door_state &= ~DOOR_NO_COPY_BACK;
2605 return MoveDoor(door_state);
2608 unsigned int GetDoorState()
2610 return MoveDoor(DOOR_GET_STATE);
2613 unsigned int SetDoorState(unsigned int door_state)
2615 return MoveDoor(door_state | DOOR_SET_STATE);
2618 unsigned int MoveDoor(unsigned int door_state)
2620 static int door1 = DOOR_OPEN_1;
2621 static int door2 = DOOR_CLOSE_2;
2622 unsigned long door_delay = 0;
2623 unsigned long door_delay_value;
2626 if (door_1.width < 0 || door_1.width > DXSIZE)
2627 door_1.width = DXSIZE;
2628 if (door_1.height < 0 || door_1.height > DYSIZE)
2629 door_1.height = DYSIZE;
2630 if (door_2.width < 0 || door_2.width > VXSIZE)
2631 door_2.width = VXSIZE;
2632 if (door_2.height < 0 || door_2.height > VYSIZE)
2633 door_2.height = VYSIZE;
2635 if (door_state == DOOR_GET_STATE)
2636 return (door1 | door2);
2638 if (door_state & DOOR_SET_STATE)
2640 if (door_state & DOOR_ACTION_1)
2641 door1 = door_state & DOOR_ACTION_1;
2642 if (door_state & DOOR_ACTION_2)
2643 door2 = door_state & DOOR_ACTION_2;
2645 return (door1 | door2);
2648 if (!(door_state & DOOR_FORCE_REDRAW))
2650 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2651 door_state &= ~DOOR_OPEN_1;
2652 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2653 door_state &= ~DOOR_CLOSE_1;
2654 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2655 door_state &= ~DOOR_OPEN_2;
2656 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2657 door_state &= ~DOOR_CLOSE_2;
2660 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2663 if (setup.quick_doors)
2665 stepsize = 20; /* must be choosen to always draw last frame */
2666 door_delay_value = 0;
2669 if (global.autoplay_leveldir)
2671 door_state |= DOOR_NO_DELAY;
2672 door_state &= ~DOOR_CLOSE_ALL;
2675 if (door_state & DOOR_ACTION)
2677 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2678 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2679 boolean door_1_done = (!handle_door_1);
2680 boolean door_2_done = (!handle_door_2);
2681 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2682 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2683 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2684 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2685 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2686 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2687 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2688 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2689 int door_skip = max_door_size - door_size;
2691 int end = door_size;
2693 int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
2697 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2699 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2703 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2705 /* opening door sound has priority over simultaneously closing door */
2706 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2707 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2708 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2709 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2712 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2715 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2716 GC gc = bitmap->stored_clip_gc;
2718 if (door_state & DOOR_ACTION_1)
2720 int a = MIN(x * door_1.step_offset, end);
2721 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2722 int i = p + door_skip;
2724 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2726 BlitBitmap(bitmap_db_door, drawto,
2727 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2728 DXSIZE, DYSIZE, DX, DY);
2732 BlitBitmap(bitmap_db_door, drawto,
2733 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2734 DXSIZE, DYSIZE - p / 2, DX, DY);
2736 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2739 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2741 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2742 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2743 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2744 int dst2_x = DX, dst2_y = DY;
2745 int width = i, height = DYSIZE;
2747 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2748 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2751 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2752 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2755 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2757 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2758 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2759 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2760 int dst2_x = DX, dst2_y = DY;
2761 int width = DXSIZE, height = i;
2763 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2764 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2767 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2768 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2771 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2773 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2775 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2776 BlitBitmapMasked(bitmap, drawto,
2777 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2778 DX + DXSIZE - i, DY + j);
2779 BlitBitmapMasked(bitmap, drawto,
2780 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2781 DX + DXSIZE - i, DY + 140 + j);
2782 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2783 DY - (DOOR_GFX_PAGEY1 + j));
2784 BlitBitmapMasked(bitmap, drawto,
2785 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2787 BlitBitmapMasked(bitmap, drawto,
2788 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2791 BlitBitmapMasked(bitmap, drawto,
2792 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2794 BlitBitmapMasked(bitmap, drawto,
2795 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2797 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2798 BlitBitmapMasked(bitmap, drawto,
2799 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2800 DX + DXSIZE - i, DY + 77 + j);
2801 BlitBitmapMasked(bitmap, drawto,
2802 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2803 DX + DXSIZE - i, DY + 203 + j);
2806 redraw_mask |= REDRAW_DOOR_1;
2807 door_1_done = (a == end);
2810 if (door_state & DOOR_ACTION_2)
2813 int a = MIN(x * door_2.step_offset, door_size);
2814 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2815 int i = p + door_skip;
2817 int a = MIN(x * door_2.step_offset, door_size_2);
2818 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2819 int i = p + door_skip;
2822 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2824 BlitBitmap(bitmap_db_door, drawto,
2825 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2826 VXSIZE, VYSIZE, VX, VY);
2828 else if (x <= VYSIZE)
2830 BlitBitmap(bitmap_db_door, drawto,
2831 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2832 VXSIZE, VYSIZE - p / 2, VX, VY);
2834 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2837 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2839 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2840 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2841 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2842 int dst2_x = VX, dst2_y = VY;
2843 int width = i, height = VYSIZE;
2845 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2846 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2849 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2850 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2853 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2855 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2856 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2857 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2858 int dst2_x = VX, dst2_y = VY;
2859 int width = VXSIZE, height = i;
2861 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2862 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2865 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2866 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2869 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2871 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2873 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2874 BlitBitmapMasked(bitmap, drawto,
2875 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2876 VX + VXSIZE - i, VY + j);
2877 SetClipOrigin(bitmap, gc,
2878 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2879 BlitBitmapMasked(bitmap, drawto,
2880 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2883 BlitBitmapMasked(bitmap, drawto,
2884 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2885 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2886 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2887 BlitBitmapMasked(bitmap, drawto,
2888 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2890 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2893 redraw_mask |= REDRAW_DOOR_2;
2894 door_2_done = (a == VXSIZE);
2897 if (!(door_state & DOOR_NO_DELAY))
2901 if (game_status == GAME_MODE_MAIN)
2904 WaitUntilDelayReached(&door_delay, door_delay_value);
2909 if (door_state & DOOR_ACTION_1)
2910 door1 = door_state & DOOR_ACTION_1;
2911 if (door_state & DOOR_ACTION_2)
2912 door2 = door_state & DOOR_ACTION_2;
2914 return (door1 | door2);
2917 void DrawSpecialEditorDoor()
2919 /* draw bigger toolbox window */
2920 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2921 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2923 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2924 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2927 redraw_mask |= REDRAW_ALL;
2930 void UndrawSpecialEditorDoor()
2932 /* draw normal tape recorder window */
2933 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2934 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2937 redraw_mask |= REDRAW_ALL;
2941 /* ---------- new tool button stuff ---------------------------------------- */
2943 /* graphic position values for tool buttons */
2944 #define TOOL_BUTTON_YES_XPOS 2
2945 #define TOOL_BUTTON_YES_YPOS 250
2946 #define TOOL_BUTTON_YES_GFX_YPOS 0
2947 #define TOOL_BUTTON_YES_XSIZE 46
2948 #define TOOL_BUTTON_YES_YSIZE 28
2949 #define TOOL_BUTTON_NO_XPOS 52
2950 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2951 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2952 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2953 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2954 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2955 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2956 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2957 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2958 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2959 #define TOOL_BUTTON_PLAYER_XSIZE 30
2960 #define TOOL_BUTTON_PLAYER_YSIZE 30
2961 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2962 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2963 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2964 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2965 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2966 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2967 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2968 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2969 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2970 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2971 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2972 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2973 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2974 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2975 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2976 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2977 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2978 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2979 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2980 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2989 } toolbutton_info[NUM_TOOL_BUTTONS] =
2992 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2993 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2994 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2999 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3000 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3001 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3006 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3007 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3008 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3009 TOOL_CTRL_ID_CONFIRM,
3013 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3014 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3015 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3016 TOOL_CTRL_ID_PLAYER_1,
3020 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3021 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3022 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3023 TOOL_CTRL_ID_PLAYER_2,
3027 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3028 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3029 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3030 TOOL_CTRL_ID_PLAYER_3,
3034 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3035 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3036 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3037 TOOL_CTRL_ID_PLAYER_4,
3042 void CreateToolButtons()
3046 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3048 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3049 Bitmap *deco_bitmap = None;
3050 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3051 struct GadgetInfo *gi;
3052 unsigned long event_mask;
3053 int gd_xoffset, gd_yoffset;
3054 int gd_x1, gd_x2, gd_y;
3057 event_mask = GD_EVENT_RELEASED;
3059 gd_xoffset = toolbutton_info[i].xpos;
3060 gd_yoffset = toolbutton_info[i].ypos;
3061 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3062 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3063 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3065 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3067 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3069 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3070 &deco_bitmap, &deco_x, &deco_y);
3071 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3072 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3075 gi = CreateGadget(GDI_CUSTOM_ID, id,
3076 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3077 GDI_X, DX + toolbutton_info[i].x,
3078 GDI_Y, DY + toolbutton_info[i].y,
3079 GDI_WIDTH, toolbutton_info[i].width,
3080 GDI_HEIGHT, toolbutton_info[i].height,
3081 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3082 GDI_STATE, GD_BUTTON_UNPRESSED,
3083 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3084 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3085 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3086 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3087 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3088 GDI_DECORATION_SHIFTING, 1, 1,
3089 GDI_EVENT_MASK, event_mask,
3090 GDI_CALLBACK_ACTION, HandleToolButtons,
3094 Error(ERR_EXIT, "cannot create gadget");
3096 tool_gadget[id] = gi;
3100 void FreeToolButtons()
3104 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3105 FreeGadget(tool_gadget[i]);
3108 static void UnmapToolButtons()
3112 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3113 UnmapGadget(tool_gadget[i]);
3116 static void HandleToolButtons(struct GadgetInfo *gi)
3118 request_gadget_id = gi->custom_id;
3121 static struct Mapping_EM_to_RND_object
3124 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3125 boolean is_backside; /* backside of moving element */
3131 em_object_mapping_list[] =
3134 Xblank, TRUE, FALSE,
3138 Yacid_splash_eB, FALSE, FALSE,
3139 EL_ACID_SPLASH_RIGHT, -1, -1
3142 Yacid_splash_wB, FALSE, FALSE,
3143 EL_ACID_SPLASH_LEFT, -1, -1
3146 #ifdef EM_ENGINE_BAD_ROLL
3148 Xstone_force_e, FALSE, FALSE,
3149 EL_ROCK, -1, MV_BIT_RIGHT
3152 Xstone_force_w, FALSE, FALSE,
3153 EL_ROCK, -1, MV_BIT_LEFT
3156 Xnut_force_e, FALSE, FALSE,
3157 EL_NUT, -1, MV_BIT_RIGHT
3160 Xnut_force_w, FALSE, FALSE,
3161 EL_NUT, -1, MV_BIT_LEFT
3164 Xspring_force_e, FALSE, FALSE,
3165 EL_SPRING, -1, MV_BIT_RIGHT
3168 Xspring_force_w, FALSE, FALSE,
3169 EL_SPRING, -1, MV_BIT_LEFT
3172 Xemerald_force_e, FALSE, FALSE,
3173 EL_EMERALD, -1, MV_BIT_RIGHT
3176 Xemerald_force_w, FALSE, FALSE,
3177 EL_EMERALD, -1, MV_BIT_LEFT
3180 Xdiamond_force_e, FALSE, FALSE,
3181 EL_DIAMOND, -1, MV_BIT_RIGHT
3184 Xdiamond_force_w, FALSE, FALSE,
3185 EL_DIAMOND, -1, MV_BIT_LEFT
3188 Xbomb_force_e, FALSE, FALSE,
3189 EL_BOMB, -1, MV_BIT_RIGHT
3192 Xbomb_force_w, FALSE, FALSE,
3193 EL_BOMB, -1, MV_BIT_LEFT
3195 #endif /* EM_ENGINE_BAD_ROLL */
3198 Xstone, TRUE, FALSE,
3202 Xstone_pause, FALSE, FALSE,
3206 Xstone_fall, FALSE, FALSE,
3210 Ystone_s, FALSE, FALSE,
3211 EL_ROCK, ACTION_FALLING, -1
3214 Ystone_sB, FALSE, TRUE,
3215 EL_ROCK, ACTION_FALLING, -1
3218 Ystone_e, FALSE, FALSE,
3219 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3222 Ystone_eB, FALSE, TRUE,
3223 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3226 Ystone_w, FALSE, FALSE,
3227 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3230 Ystone_wB, FALSE, TRUE,
3231 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3238 Xnut_pause, FALSE, FALSE,
3242 Xnut_fall, FALSE, FALSE,
3246 Ynut_s, FALSE, FALSE,
3247 EL_NUT, ACTION_FALLING, -1
3250 Ynut_sB, FALSE, TRUE,
3251 EL_NUT, ACTION_FALLING, -1
3254 Ynut_e, FALSE, FALSE,
3255 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3258 Ynut_eB, FALSE, TRUE,
3259 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3262 Ynut_w, FALSE, FALSE,
3263 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3266 Ynut_wB, FALSE, TRUE,
3267 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3270 Xbug_n, TRUE, FALSE,
3274 Xbug_e, TRUE, FALSE,
3275 EL_BUG_RIGHT, -1, -1
3278 Xbug_s, TRUE, FALSE,
3282 Xbug_w, TRUE, FALSE,
3286 Xbug_gon, FALSE, FALSE,
3290 Xbug_goe, FALSE, FALSE,
3291 EL_BUG_RIGHT, -1, -1
3294 Xbug_gos, FALSE, FALSE,
3298 Xbug_gow, FALSE, FALSE,
3302 Ybug_n, FALSE, FALSE,
3303 EL_BUG, ACTION_MOVING, MV_BIT_UP
3306 Ybug_nB, FALSE, TRUE,
3307 EL_BUG, ACTION_MOVING, MV_BIT_UP
3310 Ybug_e, FALSE, FALSE,
3311 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3314 Ybug_eB, FALSE, TRUE,
3315 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3318 Ybug_s, FALSE, FALSE,
3319 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3322 Ybug_sB, FALSE, TRUE,
3323 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3326 Ybug_w, FALSE, FALSE,
3327 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3330 Ybug_wB, FALSE, TRUE,
3331 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3334 Ybug_w_n, FALSE, FALSE,
3335 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3338 Ybug_n_e, FALSE, FALSE,
3339 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3342 Ybug_e_s, FALSE, FALSE,
3343 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3346 Ybug_s_w, FALSE, FALSE,
3347 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3350 Ybug_e_n, FALSE, FALSE,
3351 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3354 Ybug_s_e, FALSE, FALSE,
3355 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3358 Ybug_w_s, FALSE, FALSE,
3359 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3362 Ybug_n_w, FALSE, FALSE,
3363 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3366 Ybug_stone, FALSE, FALSE,
3367 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3370 Ybug_spring, FALSE, FALSE,
3371 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3374 Xtank_n, TRUE, FALSE,
3375 EL_SPACESHIP_UP, -1, -1
3378 Xtank_e, TRUE, FALSE,
3379 EL_SPACESHIP_RIGHT, -1, -1
3382 Xtank_s, TRUE, FALSE,
3383 EL_SPACESHIP_DOWN, -1, -1
3386 Xtank_w, TRUE, FALSE,
3387 EL_SPACESHIP_LEFT, -1, -1
3390 Xtank_gon, FALSE, FALSE,
3391 EL_SPACESHIP_UP, -1, -1
3394 Xtank_goe, FALSE, FALSE,
3395 EL_SPACESHIP_RIGHT, -1, -1
3398 Xtank_gos, FALSE, FALSE,
3399 EL_SPACESHIP_DOWN, -1, -1
3402 Xtank_gow, FALSE, FALSE,
3403 EL_SPACESHIP_LEFT, -1, -1
3406 Ytank_n, FALSE, FALSE,
3407 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3410 Ytank_nB, FALSE, TRUE,
3411 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3414 Ytank_e, FALSE, FALSE,
3415 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3418 Ytank_eB, FALSE, TRUE,
3419 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3422 Ytank_s, FALSE, FALSE,
3423 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3426 Ytank_sB, FALSE, TRUE,
3427 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3430 Ytank_w, FALSE, FALSE,
3431 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3434 Ytank_wB, FALSE, TRUE,
3435 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3438 Ytank_w_n, FALSE, FALSE,
3439 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3442 Ytank_n_e, FALSE, FALSE,
3443 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3446 Ytank_e_s, FALSE, FALSE,
3447 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3450 Ytank_s_w, FALSE, FALSE,
3451 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3454 Ytank_e_n, FALSE, FALSE,
3455 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3458 Ytank_s_e, FALSE, FALSE,
3459 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3462 Ytank_w_s, FALSE, FALSE,
3463 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3466 Ytank_n_w, FALSE, FALSE,
3467 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3470 Ytank_stone, FALSE, FALSE,
3471 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3474 Ytank_spring, FALSE, FALSE,
3475 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3478 Xandroid, TRUE, FALSE,
3479 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3482 Xandroid_1_n, FALSE, FALSE,
3483 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3486 Xandroid_2_n, FALSE, FALSE,
3487 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3490 Xandroid_1_e, FALSE, FALSE,
3491 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3494 Xandroid_2_e, FALSE, FALSE,
3495 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3498 Xandroid_1_w, FALSE, FALSE,
3499 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3502 Xandroid_2_w, FALSE, FALSE,
3503 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3506 Xandroid_1_s, FALSE, FALSE,
3507 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3510 Xandroid_2_s, FALSE, FALSE,
3511 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3514 Yandroid_n, FALSE, FALSE,
3515 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3518 Yandroid_nB, FALSE, TRUE,
3519 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3522 Yandroid_ne, FALSE, FALSE,
3523 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3526 Yandroid_neB, FALSE, TRUE,
3527 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3530 Yandroid_e, FALSE, FALSE,
3531 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3534 Yandroid_eB, FALSE, TRUE,
3535 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3538 Yandroid_se, FALSE, FALSE,
3539 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3542 Yandroid_seB, FALSE, TRUE,
3543 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3546 Yandroid_s, FALSE, FALSE,
3547 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3550 Yandroid_sB, FALSE, TRUE,
3551 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3554 Yandroid_sw, FALSE, FALSE,
3555 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3558 Yandroid_swB, FALSE, TRUE,
3559 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3562 Yandroid_w, FALSE, FALSE,
3563 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3566 Yandroid_wB, FALSE, TRUE,
3567 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3570 Yandroid_nw, FALSE, FALSE,
3571 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3574 Yandroid_nwB, FALSE, TRUE,
3575 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3578 Xspring, TRUE, FALSE,
3582 Xspring_pause, FALSE, FALSE,
3586 Xspring_e, FALSE, FALSE,
3590 Xspring_w, FALSE, FALSE,
3594 Xspring_fall, FALSE, FALSE,
3598 Yspring_s, FALSE, FALSE,
3599 EL_SPRING, ACTION_FALLING, -1
3602 Yspring_sB, FALSE, TRUE,
3603 EL_SPRING, ACTION_FALLING, -1
3606 Yspring_e, FALSE, FALSE,
3607 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3610 Yspring_eB, FALSE, TRUE,
3611 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3614 Yspring_w, FALSE, FALSE,
3615 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3618 Yspring_wB, FALSE, TRUE,
3619 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3622 Yspring_kill_e, FALSE, FALSE,
3623 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3626 Yspring_kill_eB, FALSE, TRUE,
3627 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3630 Yspring_kill_w, FALSE, FALSE,
3631 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3634 Yspring_kill_wB, FALSE, TRUE,
3635 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3638 Xeater_n, TRUE, FALSE,
3639 EL_YAMYAM_UP, -1, -1
3642 Xeater_e, TRUE, FALSE,
3643 EL_YAMYAM_RIGHT, -1, -1
3646 Xeater_w, TRUE, FALSE,
3647 EL_YAMYAM_LEFT, -1, -1
3650 Xeater_s, TRUE, FALSE,
3651 EL_YAMYAM_DOWN, -1, -1
3654 Yeater_n, FALSE, FALSE,
3655 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3658 Yeater_nB, FALSE, TRUE,
3659 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3662 Yeater_e, FALSE, FALSE,
3663 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3666 Yeater_eB, FALSE, TRUE,
3667 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3670 Yeater_s, FALSE, FALSE,
3671 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3674 Yeater_sB, FALSE, TRUE,
3675 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3678 Yeater_w, FALSE, FALSE,
3679 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3682 Yeater_wB, FALSE, TRUE,
3683 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3686 Yeater_stone, FALSE, FALSE,
3687 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3690 Yeater_spring, FALSE, FALSE,
3691 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3694 Xalien, TRUE, FALSE,
3698 Xalien_pause, FALSE, FALSE,
3702 Yalien_n, FALSE, FALSE,
3703 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3706 Yalien_nB, FALSE, TRUE,
3707 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3710 Yalien_e, FALSE, FALSE,
3711 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3714 Yalien_eB, FALSE, TRUE,
3715 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3718 Yalien_s, FALSE, FALSE,
3719 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3722 Yalien_sB, FALSE, TRUE,
3723 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3726 Yalien_w, FALSE, FALSE,
3727 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3730 Yalien_wB, FALSE, TRUE,
3731 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3734 Yalien_stone, FALSE, FALSE,
3735 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3738 Yalien_spring, FALSE, FALSE,
3739 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3742 Xemerald, TRUE, FALSE,
3746 Xemerald_pause, FALSE, FALSE,
3750 Xemerald_fall, FALSE, FALSE,
3754 Xemerald_shine, FALSE, FALSE,
3755 EL_EMERALD, ACTION_TWINKLING, -1
3758 Yemerald_s, FALSE, FALSE,
3759 EL_EMERALD, ACTION_FALLING, -1
3762 Yemerald_sB, FALSE, TRUE,
3763 EL_EMERALD, ACTION_FALLING, -1
3766 Yemerald_e, FALSE, FALSE,
3767 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3770 Yemerald_eB, FALSE, TRUE,
3771 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3774 Yemerald_w, FALSE, FALSE,
3775 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3778 Yemerald_wB, FALSE, TRUE,
3779 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3782 Yemerald_eat, FALSE, FALSE,
3783 EL_EMERALD, ACTION_COLLECTING, -1
3786 Yemerald_stone, FALSE, FALSE,
3787 EL_NUT, ACTION_BREAKING, -1
3790 Xdiamond, TRUE, FALSE,
3794 Xdiamond_pause, FALSE, FALSE,
3798 Xdiamond_fall, FALSE, FALSE,
3802 Xdiamond_shine, FALSE, FALSE,
3803 EL_DIAMOND, ACTION_TWINKLING, -1
3806 Ydiamond_s, FALSE, FALSE,
3807 EL_DIAMOND, ACTION_FALLING, -1
3810 Ydiamond_sB, FALSE, TRUE,
3811 EL_DIAMOND, ACTION_FALLING, -1
3814 Ydiamond_e, FALSE, FALSE,
3815 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3818 Ydiamond_eB, FALSE, TRUE,
3819 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3822 Ydiamond_w, FALSE, FALSE,
3823 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3826 Ydiamond_wB, FALSE, TRUE,
3827 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3830 Ydiamond_eat, FALSE, FALSE,
3831 EL_DIAMOND, ACTION_COLLECTING, -1
3834 Ydiamond_stone, FALSE, FALSE,
3835 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3838 Xdrip_fall, TRUE, FALSE,
3839 EL_AMOEBA_DROP, -1, -1
3842 Xdrip_stretch, FALSE, FALSE,
3843 EL_AMOEBA_DROP, ACTION_FALLING, -1
3846 Xdrip_stretchB, FALSE, TRUE,
3847 EL_AMOEBA_DROP, ACTION_FALLING, -1
3850 Xdrip_eat, FALSE, FALSE,
3851 EL_AMOEBA_DROP, ACTION_GROWING, -1
3854 Ydrip_s1, FALSE, FALSE,
3855 EL_AMOEBA_DROP, ACTION_FALLING, -1
3858 Ydrip_s1B, FALSE, TRUE,
3859 EL_AMOEBA_DROP, ACTION_FALLING, -1
3862 Ydrip_s2, FALSE, FALSE,
3863 EL_AMOEBA_DROP, ACTION_FALLING, -1
3866 Ydrip_s2B, FALSE, TRUE,
3867 EL_AMOEBA_DROP, ACTION_FALLING, -1
3874 Xbomb_pause, FALSE, FALSE,
3878 Xbomb_fall, FALSE, FALSE,
3882 Ybomb_s, FALSE, FALSE,
3883 EL_BOMB, ACTION_FALLING, -1
3886 Ybomb_sB, FALSE, TRUE,
3887 EL_BOMB, ACTION_FALLING, -1
3890 Ybomb_e, FALSE, FALSE,
3891 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3894 Ybomb_eB, FALSE, TRUE,
3895 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3898 Ybomb_w, FALSE, FALSE,
3899 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3902 Ybomb_wB, FALSE, TRUE,
3903 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3906 Ybomb_eat, FALSE, FALSE,
3907 EL_BOMB, ACTION_ACTIVATING, -1
3910 Xballoon, TRUE, FALSE,
3914 Yballoon_n, FALSE, FALSE,
3915 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3918 Yballoon_nB, FALSE, TRUE,
3919 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3922 Yballoon_e, FALSE, FALSE,
3923 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3926 Yballoon_eB, FALSE, TRUE,
3927 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3930 Yballoon_s, FALSE, FALSE,
3931 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3934 Yballoon_sB, FALSE, TRUE,
3935 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3938 Yballoon_w, FALSE, FALSE,
3939 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3942 Yballoon_wB, FALSE, TRUE,
3943 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3946 Xgrass, TRUE, FALSE,
3947 EL_EMC_GRASS, -1, -1
3950 Ygrass_nB, FALSE, FALSE,
3951 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3954 Ygrass_eB, FALSE, FALSE,
3955 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3958 Ygrass_sB, FALSE, FALSE,
3959 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3962 Ygrass_wB, FALSE, FALSE,
3963 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3970 Ydirt_nB, FALSE, FALSE,
3971 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3974 Ydirt_eB, FALSE, FALSE,
3975 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3978 Ydirt_sB, FALSE, FALSE,
3979 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3982 Ydirt_wB, FALSE, FALSE,
3983 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3986 Xacid_ne, TRUE, FALSE,
3987 EL_ACID_POOL_TOPRIGHT, -1, -1
3990 Xacid_se, TRUE, FALSE,
3991 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3994 Xacid_s, TRUE, FALSE,
3995 EL_ACID_POOL_BOTTOM, -1, -1
3998 Xacid_sw, TRUE, FALSE,
3999 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4002 Xacid_nw, TRUE, FALSE,
4003 EL_ACID_POOL_TOPLEFT, -1, -1
4006 Xacid_1, TRUE, FALSE,
4010 Xacid_2, FALSE, FALSE,
4014 Xacid_3, FALSE, FALSE,
4018 Xacid_4, FALSE, FALSE,
4022 Xacid_5, FALSE, FALSE,
4026 Xacid_6, FALSE, FALSE,
4030 Xacid_7, FALSE, FALSE,
4034 Xacid_8, FALSE, FALSE,
4038 Xball_1, TRUE, FALSE,
4039 EL_EMC_MAGIC_BALL, -1, -1
4042 Xball_1B, FALSE, FALSE,
4043 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4046 Xball_2, FALSE, FALSE,
4047 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4050 Xball_2B, FALSE, FALSE,
4051 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4054 Yball_eat, FALSE, FALSE,
4055 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4058 Ykey_1_eat, FALSE, FALSE,
4059 EL_EM_KEY_1, ACTION_COLLECTING, -1
4062 Ykey_2_eat, FALSE, FALSE,
4063 EL_EM_KEY_2, ACTION_COLLECTING, -1
4066 Ykey_3_eat, FALSE, FALSE,
4067 EL_EM_KEY_3, ACTION_COLLECTING, -1
4070 Ykey_4_eat, FALSE, FALSE,
4071 EL_EM_KEY_4, ACTION_COLLECTING, -1
4074 Ykey_5_eat, FALSE, FALSE,
4075 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4078 Ykey_6_eat, FALSE, FALSE,
4079 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4082 Ykey_7_eat, FALSE, FALSE,
4083 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4086 Ykey_8_eat, FALSE, FALSE,
4087 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4090 Ylenses_eat, FALSE, FALSE,
4091 EL_EMC_LENSES, ACTION_COLLECTING, -1
4094 Ymagnify_eat, FALSE, FALSE,
4095 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4098 Ygrass_eat, FALSE, FALSE,
4099 EL_EMC_GRASS, ACTION_SNAPPING, -1
4102 Ydirt_eat, FALSE, FALSE,
4103 EL_SAND, ACTION_SNAPPING, -1
4106 Xgrow_ns, TRUE, FALSE,
4107 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4110 Ygrow_ns_eat, FALSE, FALSE,
4111 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4114 Xgrow_ew, TRUE, FALSE,
4115 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4118 Ygrow_ew_eat, FALSE, FALSE,
4119 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4122 Xwonderwall, TRUE, FALSE,
4123 EL_MAGIC_WALL, -1, -1
4126 XwonderwallB, FALSE, FALSE,
4127 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4130 Xamoeba_1, TRUE, FALSE,
4131 EL_AMOEBA_DRY, ACTION_OTHER, -1
4134 Xamoeba_2, FALSE, FALSE,
4135 EL_AMOEBA_DRY, ACTION_OTHER, -1
4138 Xamoeba_3, FALSE, FALSE,
4139 EL_AMOEBA_DRY, ACTION_OTHER, -1
4142 Xamoeba_4, FALSE, FALSE,
4143 EL_AMOEBA_DRY, ACTION_OTHER, -1
4146 Xamoeba_5, TRUE, FALSE,
4147 EL_AMOEBA_WET, ACTION_OTHER, -1
4150 Xamoeba_6, FALSE, FALSE,
4151 EL_AMOEBA_WET, ACTION_OTHER, -1
4154 Xamoeba_7, FALSE, FALSE,
4155 EL_AMOEBA_WET, ACTION_OTHER, -1
4158 Xamoeba_8, FALSE, FALSE,
4159 EL_AMOEBA_WET, ACTION_OTHER, -1
4162 Xdoor_1, TRUE, FALSE,
4163 EL_EM_GATE_1, -1, -1
4166 Xdoor_2, TRUE, FALSE,
4167 EL_EM_GATE_2, -1, -1
4170 Xdoor_3, TRUE, FALSE,
4171 EL_EM_GATE_3, -1, -1
4174 Xdoor_4, TRUE, FALSE,
4175 EL_EM_GATE_4, -1, -1
4178 Xdoor_5, TRUE, FALSE,
4179 EL_EMC_GATE_5, -1, -1
4182 Xdoor_6, TRUE, FALSE,
4183 EL_EMC_GATE_6, -1, -1
4186 Xdoor_7, TRUE, FALSE,
4187 EL_EMC_GATE_7, -1, -1
4190 Xdoor_8, TRUE, FALSE,
4191 EL_EMC_GATE_8, -1, -1
4194 Xkey_1, TRUE, FALSE,
4198 Xkey_2, TRUE, FALSE,
4202 Xkey_3, TRUE, FALSE,
4206 Xkey_4, TRUE, FALSE,
4210 Xkey_5, TRUE, FALSE,
4211 EL_EMC_KEY_5, -1, -1
4214 Xkey_6, TRUE, FALSE,
4215 EL_EMC_KEY_6, -1, -1
4218 Xkey_7, TRUE, FALSE,
4219 EL_EMC_KEY_7, -1, -1
4222 Xkey_8, TRUE, FALSE,
4223 EL_EMC_KEY_8, -1, -1
4226 Xwind_n, TRUE, FALSE,
4227 EL_BALLOON_SWITCH_UP, -1, -1
4230 Xwind_e, TRUE, FALSE,
4231 EL_BALLOON_SWITCH_RIGHT, -1, -1
4234 Xwind_s, TRUE, FALSE,
4235 EL_BALLOON_SWITCH_DOWN, -1, -1
4238 Xwind_w, TRUE, FALSE,
4239 EL_BALLOON_SWITCH_LEFT, -1, -1
4242 Xwind_nesw, TRUE, FALSE,
4243 EL_BALLOON_SWITCH_ANY, -1, -1
4246 Xwind_stop, TRUE, FALSE,
4247 EL_BALLOON_SWITCH_NONE, -1, -1
4251 EL_EXIT_CLOSED, -1, -1
4254 Xexit_1, TRUE, FALSE,
4255 EL_EXIT_OPEN, -1, -1
4258 Xexit_2, FALSE, FALSE,
4259 EL_EXIT_OPEN, -1, -1
4262 Xexit_3, FALSE, FALSE,
4263 EL_EXIT_OPEN, -1, -1
4266 Xdynamite, TRUE, FALSE,
4267 EL_EM_DYNAMITE, -1, -1
4270 Ydynamite_eat, FALSE, FALSE,
4271 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4274 Xdynamite_1, TRUE, FALSE,
4275 EL_EM_DYNAMITE_ACTIVE, -1, -1
4278 Xdynamite_2, FALSE, FALSE,
4279 EL_EM_DYNAMITE_ACTIVE, -1, -1
4282 Xdynamite_3, FALSE, FALSE,
4283 EL_EM_DYNAMITE_ACTIVE, -1, -1
4286 Xdynamite_4, FALSE, FALSE,
4287 EL_EM_DYNAMITE_ACTIVE, -1, -1
4290 Xbumper, TRUE, FALSE,
4291 EL_EMC_SPRING_BUMPER, -1, -1
4294 XbumperB, FALSE, FALSE,
4295 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4298 Xwheel, TRUE, FALSE,
4299 EL_ROBOT_WHEEL, -1, -1
4302 XwheelB, FALSE, FALSE,
4303 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4306 Xswitch, TRUE, FALSE,
4307 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4310 XswitchB, FALSE, FALSE,
4311 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4315 EL_QUICKSAND_EMPTY, -1, -1
4318 Xsand_stone, TRUE, FALSE,
4319 EL_QUICKSAND_FULL, -1, -1
4322 Xsand_stonein_1, FALSE, TRUE,
4323 EL_ROCK, ACTION_FILLING, -1
4326 Xsand_stonein_2, FALSE, TRUE,
4327 EL_ROCK, ACTION_FILLING, -1
4330 Xsand_stonein_3, FALSE, TRUE,
4331 EL_ROCK, ACTION_FILLING, -1
4334 Xsand_stonein_4, FALSE, TRUE,
4335 EL_ROCK, ACTION_FILLING, -1
4338 Xsand_stonesand_1, FALSE, FALSE,
4339 EL_QUICKSAND_FULL, -1, -1
4342 Xsand_stonesand_2, FALSE, FALSE,
4343 EL_QUICKSAND_FULL, -1, -1
4346 Xsand_stonesand_3, FALSE, FALSE,
4347 EL_QUICKSAND_FULL, -1, -1
4350 Xsand_stonesand_4, FALSE, FALSE,
4351 EL_QUICKSAND_FULL, -1, -1
4354 Xsand_stoneout_1, FALSE, FALSE,
4355 EL_ROCK, ACTION_EMPTYING, -1
4358 Xsand_stoneout_2, FALSE, FALSE,
4359 EL_ROCK, ACTION_EMPTYING, -1
4362 Xsand_sandstone_1, FALSE, FALSE,
4363 EL_QUICKSAND_FULL, -1, -1
4366 Xsand_sandstone_2, FALSE, FALSE,
4367 EL_QUICKSAND_FULL, -1, -1
4370 Xsand_sandstone_3, FALSE, FALSE,
4371 EL_QUICKSAND_FULL, -1, -1
4374 Xsand_sandstone_4, FALSE, FALSE,
4375 EL_QUICKSAND_FULL, -1, -1
4378 Xplant, TRUE, FALSE,
4379 EL_EMC_PLANT, -1, -1
4382 Yplant, FALSE, FALSE,
4383 EL_EMC_PLANT, -1, -1
4386 Xlenses, TRUE, FALSE,
4387 EL_EMC_LENSES, -1, -1
4390 Xmagnify, TRUE, FALSE,
4391 EL_EMC_MAGNIFIER, -1, -1
4394 Xdripper, TRUE, FALSE,
4395 EL_EMC_DRIPPER, -1, -1
4398 XdripperB, FALSE, FALSE,
4399 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4402 Xfake_blank, TRUE, FALSE,
4403 EL_INVISIBLE_WALL, -1, -1
4406 Xfake_blankB, FALSE, FALSE,
4407 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4410 Xfake_grass, TRUE, FALSE,
4411 EL_EMC_FAKE_GRASS, -1, -1
4414 Xfake_grassB, FALSE, FALSE,
4415 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4418 Xfake_door_1, TRUE, FALSE,
4419 EL_EM_GATE_1_GRAY, -1, -1
4422 Xfake_door_2, TRUE, FALSE,
4423 EL_EM_GATE_2_GRAY, -1, -1
4426 Xfake_door_3, TRUE, FALSE,
4427 EL_EM_GATE_3_GRAY, -1, -1
4430 Xfake_door_4, TRUE, FALSE,
4431 EL_EM_GATE_4_GRAY, -1, -1
4434 Xfake_door_5, TRUE, FALSE,
4435 EL_EMC_GATE_5_GRAY, -1, -1
4438 Xfake_door_6, TRUE, FALSE,
4439 EL_EMC_GATE_6_GRAY, -1, -1
4442 Xfake_door_7, TRUE, FALSE,
4443 EL_EMC_GATE_7_GRAY, -1, -1
4446 Xfake_door_8, TRUE, FALSE,
4447 EL_EMC_GATE_8_GRAY, -1, -1
4450 Xfake_acid_1, TRUE, FALSE,
4451 EL_EMC_FAKE_ACID, -1, -1
4454 Xfake_acid_2, FALSE, FALSE,
4455 EL_EMC_FAKE_ACID, -1, -1
4458 Xfake_acid_3, FALSE, FALSE,
4459 EL_EMC_FAKE_ACID, -1, -1
4462 Xfake_acid_4, FALSE, FALSE,
4463 EL_EMC_FAKE_ACID, -1, -1
4466 Xfake_acid_5, FALSE, FALSE,
4467 EL_EMC_FAKE_ACID, -1, -1
4470 Xfake_acid_6, FALSE, FALSE,
4471 EL_EMC_FAKE_ACID, -1, -1
4474 Xfake_acid_7, FALSE, FALSE,
4475 EL_EMC_FAKE_ACID, -1, -1
4478 Xfake_acid_8, FALSE, FALSE,
4479 EL_EMC_FAKE_ACID, -1, -1
4482 Xsteel_1, TRUE, FALSE,
4483 EL_STEELWALL, -1, -1
4486 Xsteel_2, TRUE, FALSE,
4487 EL_EMC_STEELWALL_2, -1, -1
4490 Xsteel_3, TRUE, FALSE,
4491 EL_EMC_STEELWALL_3, -1, -1
4494 Xsteel_4, TRUE, FALSE,
4495 EL_EMC_STEELWALL_4, -1, -1
4498 Xwall_1, TRUE, FALSE,
4502 Xwall_2, TRUE, FALSE,
4503 EL_EMC_WALL_14, -1, -1
4506 Xwall_3, TRUE, FALSE,
4507 EL_EMC_WALL_15, -1, -1
4510 Xwall_4, TRUE, FALSE,
4511 EL_EMC_WALL_16, -1, -1
4514 Xround_wall_1, TRUE, FALSE,
4515 EL_WALL_SLIPPERY, -1, -1
4518 Xround_wall_2, TRUE, FALSE,
4519 EL_EMC_WALL_SLIPPERY_2, -1, -1
4522 Xround_wall_3, TRUE, FALSE,
4523 EL_EMC_WALL_SLIPPERY_3, -1, -1
4526 Xround_wall_4, TRUE, FALSE,
4527 EL_EMC_WALL_SLIPPERY_4, -1, -1
4530 Xdecor_1, TRUE, FALSE,
4531 EL_EMC_WALL_8, -1, -1
4534 Xdecor_2, TRUE, FALSE,
4535 EL_EMC_WALL_6, -1, -1
4538 Xdecor_3, TRUE, FALSE,
4539 EL_EMC_WALL_4, -1, -1
4542 Xdecor_4, TRUE, FALSE,
4543 EL_EMC_WALL_7, -1, -1
4546 Xdecor_5, TRUE, FALSE,
4547 EL_EMC_WALL_5, -1, -1
4550 Xdecor_6, TRUE, FALSE,
4551 EL_EMC_WALL_9, -1, -1
4554 Xdecor_7, TRUE, FALSE,
4555 EL_EMC_WALL_10, -1, -1
4558 Xdecor_8, TRUE, FALSE,
4559 EL_EMC_WALL_1, -1, -1
4562 Xdecor_9, TRUE, FALSE,
4563 EL_EMC_WALL_2, -1, -1
4566 Xdecor_10, TRUE, FALSE,
4567 EL_EMC_WALL_3, -1, -1
4570 Xdecor_11, TRUE, FALSE,
4571 EL_EMC_WALL_11, -1, -1
4574 Xdecor_12, TRUE, FALSE,
4575 EL_EMC_WALL_12, -1, -1
4578 Xalpha_0, TRUE, FALSE,
4579 EL_CHAR('0'), -1, -1
4582 Xalpha_1, TRUE, FALSE,
4583 EL_CHAR('1'), -1, -1
4586 Xalpha_2, TRUE, FALSE,
4587 EL_CHAR('2'), -1, -1
4590 Xalpha_3, TRUE, FALSE,
4591 EL_CHAR('3'), -1, -1
4594 Xalpha_4, TRUE, FALSE,
4595 EL_CHAR('4'), -1, -1
4598 Xalpha_5, TRUE, FALSE,
4599 EL_CHAR('5'), -1, -1
4602 Xalpha_6, TRUE, FALSE,
4603 EL_CHAR('6'), -1, -1
4606 Xalpha_7, TRUE, FALSE,
4607 EL_CHAR('7'), -1, -1
4610 Xalpha_8, TRUE, FALSE,
4611 EL_CHAR('8'), -1, -1
4614 Xalpha_9, TRUE, FALSE,
4615 EL_CHAR('9'), -1, -1
4618 Xalpha_excla, TRUE, FALSE,
4619 EL_CHAR('!'), -1, -1
4622 Xalpha_quote, TRUE, FALSE,
4623 EL_CHAR('"'), -1, -1
4626 Xalpha_comma, TRUE, FALSE,
4627 EL_CHAR(','), -1, -1
4630 Xalpha_minus, TRUE, FALSE,
4631 EL_CHAR('-'), -1, -1
4634 Xalpha_perio, TRUE, FALSE,
4635 EL_CHAR('.'), -1, -1
4638 Xalpha_colon, TRUE, FALSE,
4639 EL_CHAR(':'), -1, -1
4642 Xalpha_quest, TRUE, FALSE,
4643 EL_CHAR('?'), -1, -1
4646 Xalpha_a, TRUE, FALSE,
4647 EL_CHAR('A'), -1, -1
4650 Xalpha_b, TRUE, FALSE,
4651 EL_CHAR('B'), -1, -1
4654 Xalpha_c, TRUE, FALSE,
4655 EL_CHAR('C'), -1, -1
4658 Xalpha_d, TRUE, FALSE,
4659 EL_CHAR('D'), -1, -1
4662 Xalpha_e, TRUE, FALSE,
4663 EL_CHAR('E'), -1, -1
4666 Xalpha_f, TRUE, FALSE,
4667 EL_CHAR('F'), -1, -1
4670 Xalpha_g, TRUE, FALSE,
4671 EL_CHAR('G'), -1, -1
4674 Xalpha_h, TRUE, FALSE,
4675 EL_CHAR('H'), -1, -1
4678 Xalpha_i, TRUE, FALSE,
4679 EL_CHAR('I'), -1, -1
4682 Xalpha_j, TRUE, FALSE,
4683 EL_CHAR('J'), -1, -1
4686 Xalpha_k, TRUE, FALSE,
4687 EL_CHAR('K'), -1, -1
4690 Xalpha_l, TRUE, FALSE,
4691 EL_CHAR('L'), -1, -1
4694 Xalpha_m, TRUE, FALSE,
4695 EL_CHAR('M'), -1, -1
4698 Xalpha_n, TRUE, FALSE,
4699 EL_CHAR('N'), -1, -1
4702 Xalpha_o, TRUE, FALSE,
4703 EL_CHAR('O'), -1, -1
4706 Xalpha_p, TRUE, FALSE,
4707 EL_CHAR('P'), -1, -1
4710 Xalpha_q, TRUE, FALSE,
4711 EL_CHAR('Q'), -1, -1
4714 Xalpha_r, TRUE, FALSE,
4715 EL_CHAR('R'), -1, -1
4718 Xalpha_s, TRUE, FALSE,
4719 EL_CHAR('S'), -1, -1
4722 Xalpha_t, TRUE, FALSE,
4723 EL_CHAR('T'), -1, -1
4726 Xalpha_u, TRUE, FALSE,
4727 EL_CHAR('U'), -1, -1
4730 Xalpha_v, TRUE, FALSE,
4731 EL_CHAR('V'), -1, -1
4734 Xalpha_w, TRUE, FALSE,
4735 EL_CHAR('W'), -1, -1
4738 Xalpha_x, TRUE, FALSE,
4739 EL_CHAR('X'), -1, -1
4742 Xalpha_y, TRUE, FALSE,
4743 EL_CHAR('Y'), -1, -1
4746 Xalpha_z, TRUE, FALSE,
4747 EL_CHAR('Z'), -1, -1
4750 Xalpha_arrow_e, TRUE, FALSE,
4751 EL_CHAR('>'), -1, -1
4754 Xalpha_arrow_w, TRUE, FALSE,
4755 EL_CHAR('<'), -1, -1
4758 Xalpha_copyr, TRUE, FALSE,
4759 EL_CHAR('©'), -1, -1
4763 Xboom_bug, FALSE, FALSE,
4764 EL_BUG, ACTION_EXPLODING, -1
4767 Xboom_bomb, FALSE, FALSE,
4768 EL_BOMB, ACTION_EXPLODING, -1
4771 Xboom_android, FALSE, FALSE,
4772 EL_EMC_ANDROID, ACTION_OTHER, -1
4775 Xboom_1, FALSE, FALSE,
4776 EL_DEFAULT, ACTION_EXPLODING, -1
4779 Xboom_2, FALSE, FALSE,
4780 EL_DEFAULT, ACTION_EXPLODING, -1
4783 Znormal, FALSE, FALSE,
4787 Zdynamite, FALSE, FALSE,
4791 Zplayer, FALSE, FALSE,
4795 ZBORDER, FALSE, FALSE,
4805 static struct Mapping_EM_to_RND_player
4814 em_player_mapping_list[] =
4818 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4822 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4826 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4830 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4834 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4838 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4842 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4846 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4850 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4854 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4858 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4862 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4866 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4870 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4874 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4878 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4882 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4886 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4890 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4894 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4898 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4902 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4906 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4910 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4914 EL_PLAYER_1, ACTION_DEFAULT, -1,
4918 EL_PLAYER_2, ACTION_DEFAULT, -1,
4922 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4926 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4930 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4934 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4938 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4942 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4946 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4950 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4954 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4958 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4962 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4966 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4970 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4974 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4978 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4982 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4986 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4990 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4994 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4998 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5002 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5006 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5010 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5014 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5018 EL_PLAYER_3, ACTION_DEFAULT, -1,
5022 EL_PLAYER_4, ACTION_DEFAULT, -1,
5031 int map_element_RND_to_EM(int element_rnd)
5033 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5034 static boolean mapping_initialized = FALSE;
5036 if (!mapping_initialized)
5040 /* return "Xalpha_quest" for all undefined elements in mapping array */
5041 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5042 mapping_RND_to_EM[i] = Xalpha_quest;
5044 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5045 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5046 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5047 em_object_mapping_list[i].element_em;
5049 mapping_initialized = TRUE;
5052 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5053 return mapping_RND_to_EM[element_rnd];
5055 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5060 int map_element_EM_to_RND(int element_em)
5062 static unsigned short mapping_EM_to_RND[TILE_MAX];
5063 static boolean mapping_initialized = FALSE;
5065 if (!mapping_initialized)
5069 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5070 for (i = 0; i < TILE_MAX; i++)
5071 mapping_EM_to_RND[i] = EL_UNKNOWN;
5073 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5074 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5075 em_object_mapping_list[i].element_rnd;
5077 mapping_initialized = TRUE;
5080 if (element_em >= 0 && element_em < TILE_MAX)
5081 return mapping_EM_to_RND[element_em];
5083 Error(ERR_WARN, "invalid EM level element %d", element_em);
5088 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5090 struct LevelInfo_EM *level_em = level->native_em_level;
5091 struct LEVEL *lev = level_em->lev;
5094 for (i = 0; i < TILE_MAX; i++)
5095 lev->android_array[i] = Xblank;
5097 for (i = 0; i < level->num_android_clone_elements; i++)
5099 int element_rnd = level->android_clone_element[i];
5100 int element_em = map_element_RND_to_EM(element_rnd);
5102 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5103 if (em_object_mapping_list[j].element_rnd == element_rnd)
5104 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5108 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5110 struct LevelInfo_EM *level_em = level->native_em_level;
5111 struct LEVEL *lev = level_em->lev;
5114 level->num_android_clone_elements = 0;
5116 for (i = 0; i < TILE_MAX; i++)
5118 int element_em = lev->android_array[i];
5120 boolean element_found = FALSE;
5122 if (element_em == Xblank)
5125 element_rnd = map_element_EM_to_RND(element_em);
5127 for (j = 0; j < level->num_android_clone_elements; j++)
5128 if (level->android_clone_element[j] == element_rnd)
5129 element_found = TRUE;
5133 level->android_clone_element[level->num_android_clone_elements++] =
5136 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5141 if (level->num_android_clone_elements == 0)
5143 level->num_android_clone_elements = 1;
5144 level->android_clone_element[0] = EL_EMPTY;
5148 int map_direction_RND_to_EM(int direction)
5150 return (direction == MV_UP ? 0 :
5151 direction == MV_RIGHT ? 1 :
5152 direction == MV_DOWN ? 2 :
5153 direction == MV_LEFT ? 3 :
5157 int map_direction_EM_to_RND(int direction)
5159 return (direction == 0 ? MV_UP :
5160 direction == 1 ? MV_RIGHT :
5161 direction == 2 ? MV_DOWN :
5162 direction == 3 ? MV_LEFT :
5166 int get_next_element(int element)
5170 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5171 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5172 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5173 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5174 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5175 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5176 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5178 default: return element;
5183 int el_act_dir2img(int element, int action, int direction)
5185 element = GFX_ELEMENT(element);
5187 if (direction == MV_NONE)
5188 return element_info[element].graphic[action];
5190 direction = MV_DIR_TO_BIT(direction);
5192 return element_info[element].direction_graphic[action][direction];
5195 int el_act_dir2img(int element, int action, int direction)
5197 element = GFX_ELEMENT(element);
5198 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5200 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5201 return element_info[element].direction_graphic[action][direction];
5206 static int el_act_dir2crm(int element, int action, int direction)
5208 element = GFX_ELEMENT(element);
5210 if (direction == MV_NONE)
5211 return element_info[element].crumbled[action];
5213 direction = MV_DIR_TO_BIT(direction);
5215 return element_info[element].direction_crumbled[action][direction];
5218 static int el_act_dir2crm(int element, int action, int direction)
5220 element = GFX_ELEMENT(element);
5221 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5223 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5224 return element_info[element].direction_crumbled[action][direction];
5228 int el_act2img(int element, int action)
5230 element = GFX_ELEMENT(element);
5232 return element_info[element].graphic[action];
5235 int el_act2crm(int element, int action)
5237 element = GFX_ELEMENT(element);
5239 return element_info[element].crumbled[action];
5242 int el_dir2img(int element, int direction)
5244 element = GFX_ELEMENT(element);
5246 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5249 int el2baseimg(int element)
5251 return element_info[element].graphic[ACTION_DEFAULT];
5254 int el2img(int element)
5256 element = GFX_ELEMENT(element);
5258 return element_info[element].graphic[ACTION_DEFAULT];
5261 int el2edimg(int element)
5263 element = GFX_ELEMENT(element);
5265 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5268 int el2preimg(int element)
5270 element = GFX_ELEMENT(element);
5272 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5275 int font2baseimg(int font_nr)
5277 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5281 void setCenteredPlayerNr_EM(int centered_player_nr)
5283 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5286 int getCenteredPlayerNr_EM()
5289 if (game.centered_player_nr_next >= 0 &&
5290 !native_em_level.ply[game.centered_player_nr_next]->alive)
5291 game.centered_player_nr_next = game.centered_player_nr;
5294 if (game.centered_player_nr != game.centered_player_nr_next)
5295 game.centered_player_nr = game.centered_player_nr_next;
5297 return game.centered_player_nr;
5300 void setSetCenteredPlayer_EM(boolean set_centered_player)
5302 game.set_centered_player = set_centered_player;
5305 boolean getSetCenteredPlayer_EM()
5307 return game.set_centered_player;
5311 int getNumActivePlayers_EM()
5313 int num_players = 0;
5319 for (i = 0; i < MAX_PLAYERS; i++)
5320 if (tape.player_participates[i])
5327 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5329 int game_frame_delay_value;
5331 game_frame_delay_value =
5332 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5333 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5336 if (tape.playing && tape.warp_forward && !tape.pausing)
5337 game_frame_delay_value = 0;
5339 return game_frame_delay_value;
5343 unsigned int InitRND(long seed)
5345 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5346 return InitEngineRND_EM(seed);
5348 return InitEngineRND(seed);
5351 void InitGraphicInfo_EM(void)
5353 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5354 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5358 int num_em_gfx_errors = 0;
5360 if (graphic_info_em_object[0][0].bitmap == NULL)
5362 /* EM graphics not yet initialized in em_open_all() */
5367 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5370 /* always start with reliable default values */
5371 for (i = 0; i < TILE_MAX; i++)
5373 object_mapping[i].element_rnd = EL_UNKNOWN;
5374 object_mapping[i].is_backside = FALSE;
5375 object_mapping[i].action = ACTION_DEFAULT;
5376 object_mapping[i].direction = MV_NONE;
5379 /* always start with reliable default values */
5380 for (p = 0; p < MAX_PLAYERS; p++)
5382 for (i = 0; i < SPR_MAX; i++)
5384 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5385 player_mapping[p][i].action = ACTION_DEFAULT;
5386 player_mapping[p][i].direction = MV_NONE;
5390 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5392 int e = em_object_mapping_list[i].element_em;
5394 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5395 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5397 if (em_object_mapping_list[i].action != -1)
5398 object_mapping[e].action = em_object_mapping_list[i].action;
5400 if (em_object_mapping_list[i].direction != -1)
5401 object_mapping[e].direction =
5402 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5405 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5407 int a = em_player_mapping_list[i].action_em;
5408 int p = em_player_mapping_list[i].player_nr;
5410 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5412 if (em_player_mapping_list[i].action != -1)
5413 player_mapping[p][a].action = em_player_mapping_list[i].action;
5415 if (em_player_mapping_list[i].direction != -1)
5416 player_mapping[p][a].direction =
5417 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5420 for (i = 0; i < TILE_MAX; i++)
5422 int element = object_mapping[i].element_rnd;
5423 int action = object_mapping[i].action;
5424 int direction = object_mapping[i].direction;
5425 boolean is_backside = object_mapping[i].is_backside;
5426 boolean action_removing = (action == ACTION_DIGGING ||
5427 action == ACTION_SNAPPING ||
5428 action == ACTION_COLLECTING);
5429 boolean action_exploding = ((action == ACTION_EXPLODING ||
5430 action == ACTION_SMASHED_BY_ROCK ||
5431 action == ACTION_SMASHED_BY_SPRING) &&
5432 element != EL_DIAMOND);
5433 boolean action_active = (action == ACTION_ACTIVE);
5434 boolean action_other = (action == ACTION_OTHER);
5436 for (j = 0; j < 8; j++)
5438 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5439 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5441 i == Xdrip_stretch ? element :
5442 i == Xdrip_stretchB ? element :
5443 i == Ydrip_s1 ? element :
5444 i == Ydrip_s1B ? element :
5445 i == Xball_1B ? element :
5446 i == Xball_2 ? element :
5447 i == Xball_2B ? element :
5448 i == Yball_eat ? element :
5449 i == Ykey_1_eat ? element :
5450 i == Ykey_2_eat ? element :
5451 i == Ykey_3_eat ? element :
5452 i == Ykey_4_eat ? element :
5453 i == Ykey_5_eat ? element :
5454 i == Ykey_6_eat ? element :
5455 i == Ykey_7_eat ? element :
5456 i == Ykey_8_eat ? element :
5457 i == Ylenses_eat ? element :
5458 i == Ymagnify_eat ? element :
5459 i == Ygrass_eat ? element :
5460 i == Ydirt_eat ? element :
5461 i == Yemerald_stone ? EL_EMERALD :
5462 i == Ydiamond_stone ? EL_ROCK :
5463 i == Xsand_stonein_1 ? element :
5464 i == Xsand_stonein_2 ? element :
5465 i == Xsand_stonein_3 ? element :
5466 i == Xsand_stonein_4 ? element :
5467 is_backside ? EL_EMPTY :
5468 action_removing ? EL_EMPTY :
5470 int effective_action = (j < 7 ? action :
5471 i == Xdrip_stretch ? action :
5472 i == Xdrip_stretchB ? action :
5473 i == Ydrip_s1 ? action :
5474 i == Ydrip_s1B ? action :
5475 i == Xball_1B ? action :
5476 i == Xball_2 ? action :
5477 i == Xball_2B ? action :
5478 i == Yball_eat ? action :
5479 i == Ykey_1_eat ? action :
5480 i == Ykey_2_eat ? action :
5481 i == Ykey_3_eat ? action :
5482 i == Ykey_4_eat ? action :
5483 i == Ykey_5_eat ? action :
5484 i == Ykey_6_eat ? action :
5485 i == Ykey_7_eat ? action :
5486 i == Ykey_8_eat ? action :
5487 i == Ylenses_eat ? action :
5488 i == Ymagnify_eat ? action :
5489 i == Ygrass_eat ? action :
5490 i == Ydirt_eat ? action :
5491 i == Xsand_stonein_1 ? action :
5492 i == Xsand_stonein_2 ? action :
5493 i == Xsand_stonein_3 ? action :
5494 i == Xsand_stonein_4 ? action :
5495 i == Xsand_stoneout_1 ? action :
5496 i == Xsand_stoneout_2 ? action :
5497 i == Xboom_android ? ACTION_EXPLODING :
5498 action_exploding ? ACTION_EXPLODING :
5499 action_active ? action :
5500 action_other ? action :
5502 int graphic = (el_act_dir2img(effective_element, effective_action,
5504 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5506 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5507 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5508 boolean has_action_graphics = (graphic != base_graphic);
5509 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5510 struct GraphicInfo *g = &graphic_info[graphic];
5511 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5514 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5515 boolean special_animation = (action != ACTION_DEFAULT &&
5516 g->anim_frames == 3 &&
5517 g->anim_delay == 2 &&
5518 g->anim_mode & ANIM_LINEAR);
5519 int sync_frame = (i == Xdrip_stretch ? 7 :
5520 i == Xdrip_stretchB ? 7 :
5521 i == Ydrip_s2 ? j + 8 :
5522 i == Ydrip_s2B ? j + 8 :
5531 i == Xfake_acid_1 ? 0 :
5532 i == Xfake_acid_2 ? 10 :
5533 i == Xfake_acid_3 ? 20 :
5534 i == Xfake_acid_4 ? 30 :
5535 i == Xfake_acid_5 ? 40 :
5536 i == Xfake_acid_6 ? 50 :
5537 i == Xfake_acid_7 ? 60 :
5538 i == Xfake_acid_8 ? 70 :
5540 i == Xball_2B ? j + 8 :
5541 i == Yball_eat ? j + 1 :
5542 i == Ykey_1_eat ? j + 1 :
5543 i == Ykey_2_eat ? j + 1 :
5544 i == Ykey_3_eat ? j + 1 :
5545 i == Ykey_4_eat ? j + 1 :
5546 i == Ykey_5_eat ? j + 1 :
5547 i == Ykey_6_eat ? j + 1 :
5548 i == Ykey_7_eat ? j + 1 :
5549 i == Ykey_8_eat ? j + 1 :
5550 i == Ylenses_eat ? j + 1 :
5551 i == Ymagnify_eat ? j + 1 :
5552 i == Ygrass_eat ? j + 1 :
5553 i == Ydirt_eat ? j + 1 :
5554 i == Xamoeba_1 ? 0 :
5555 i == Xamoeba_2 ? 1 :
5556 i == Xamoeba_3 ? 2 :
5557 i == Xamoeba_4 ? 3 :
5558 i == Xamoeba_5 ? 0 :
5559 i == Xamoeba_6 ? 1 :
5560 i == Xamoeba_7 ? 2 :
5561 i == Xamoeba_8 ? 3 :
5562 i == Xexit_2 ? j + 8 :
5563 i == Xexit_3 ? j + 16 :
5564 i == Xdynamite_1 ? 0 :
5565 i == Xdynamite_2 ? 8 :
5566 i == Xdynamite_3 ? 16 :
5567 i == Xdynamite_4 ? 24 :
5568 i == Xsand_stonein_1 ? j + 1 :
5569 i == Xsand_stonein_2 ? j + 9 :
5570 i == Xsand_stonein_3 ? j + 17 :
5571 i == Xsand_stonein_4 ? j + 25 :
5572 i == Xsand_stoneout_1 && j == 0 ? 0 :
5573 i == Xsand_stoneout_1 && j == 1 ? 0 :
5574 i == Xsand_stoneout_1 && j == 2 ? 1 :
5575 i == Xsand_stoneout_1 && j == 3 ? 2 :
5576 i == Xsand_stoneout_1 && j == 4 ? 2 :
5577 i == Xsand_stoneout_1 && j == 5 ? 3 :
5578 i == Xsand_stoneout_1 && j == 6 ? 4 :
5579 i == Xsand_stoneout_1 && j == 7 ? 4 :
5580 i == Xsand_stoneout_2 && j == 0 ? 5 :
5581 i == Xsand_stoneout_2 && j == 1 ? 6 :
5582 i == Xsand_stoneout_2 && j == 2 ? 7 :
5583 i == Xsand_stoneout_2 && j == 3 ? 8 :
5584 i == Xsand_stoneout_2 && j == 4 ? 9 :
5585 i == Xsand_stoneout_2 && j == 5 ? 11 :
5586 i == Xsand_stoneout_2 && j == 6 ? 13 :
5587 i == Xsand_stoneout_2 && j == 7 ? 15 :
5588 i == Xboom_bug && j == 1 ? 2 :
5589 i == Xboom_bug && j == 2 ? 2 :
5590 i == Xboom_bug && j == 3 ? 4 :
5591 i == Xboom_bug && j == 4 ? 4 :
5592 i == Xboom_bug && j == 5 ? 2 :
5593 i == Xboom_bug && j == 6 ? 2 :
5594 i == Xboom_bug && j == 7 ? 0 :
5595 i == Xboom_bomb && j == 1 ? 2 :
5596 i == Xboom_bomb && j == 2 ? 2 :
5597 i == Xboom_bomb && j == 3 ? 4 :
5598 i == Xboom_bomb && j == 4 ? 4 :
5599 i == Xboom_bomb && j == 5 ? 2 :
5600 i == Xboom_bomb && j == 6 ? 2 :
5601 i == Xboom_bomb && j == 7 ? 0 :
5602 i == Xboom_android && j == 7 ? 6 :
5603 i == Xboom_1 && j == 1 ? 2 :
5604 i == Xboom_1 && j == 2 ? 2 :
5605 i == Xboom_1 && j == 3 ? 4 :
5606 i == Xboom_1 && j == 4 ? 4 :
5607 i == Xboom_1 && j == 5 ? 6 :
5608 i == Xboom_1 && j == 6 ? 6 :
5609 i == Xboom_1 && j == 7 ? 8 :
5610 i == Xboom_2 && j == 0 ? 8 :
5611 i == Xboom_2 && j == 1 ? 8 :
5612 i == Xboom_2 && j == 2 ? 10 :
5613 i == Xboom_2 && j == 3 ? 10 :
5614 i == Xboom_2 && j == 4 ? 10 :
5615 i == Xboom_2 && j == 5 ? 12 :
5616 i == Xboom_2 && j == 6 ? 12 :
5617 i == Xboom_2 && j == 7 ? 12 :
5618 special_animation && j == 4 ? 3 :
5619 effective_action != action ? 0 :
5623 Bitmap *debug_bitmap = g_em->bitmap;
5624 int debug_src_x = g_em->src_x;
5625 int debug_src_y = g_em->src_y;
5628 int frame = getAnimationFrame(g->anim_frames,
5631 g->anim_start_frame,
5634 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5635 g->double_movement && is_backside);
5637 g_em->bitmap = src_bitmap;
5638 g_em->src_x = src_x;
5639 g_em->src_y = src_y;
5640 g_em->src_offset_x = 0;
5641 g_em->src_offset_y = 0;
5642 g_em->dst_offset_x = 0;
5643 g_em->dst_offset_y = 0;
5644 g_em->width = TILEX;
5645 g_em->height = TILEY;
5647 g_em->crumbled_bitmap = NULL;
5648 g_em->crumbled_src_x = 0;
5649 g_em->crumbled_src_y = 0;
5650 g_em->crumbled_border_size = 0;
5652 g_em->has_crumbled_graphics = FALSE;
5653 g_em->preserve_background = FALSE;
5656 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5657 printf("::: empty crumbled: %d [%s], %d, %d\n",
5658 effective_element, element_info[effective_element].token_name,
5659 effective_action, direction);
5662 /* if element can be crumbled, but certain action graphics are just empty
5663 space (like snapping sand with the original R'n'D graphics), do not
5664 treat these empty space graphics as crumbled graphics in EMC engine */
5665 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5667 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5669 g_em->has_crumbled_graphics = TRUE;
5670 g_em->crumbled_bitmap = src_bitmap;
5671 g_em->crumbled_src_x = src_x;
5672 g_em->crumbled_src_y = src_y;
5673 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5677 if (element == EL_ROCK &&
5678 effective_action == ACTION_FILLING)
5679 printf("::: has_action_graphics == %d\n", has_action_graphics);
5682 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5683 effective_action == ACTION_MOVING ||
5684 effective_action == ACTION_PUSHING ||
5685 effective_action == ACTION_EATING)) ||
5686 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5687 effective_action == ACTION_EMPTYING)))
5690 (effective_action == ACTION_FALLING ||
5691 effective_action == ACTION_FILLING ||
5692 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5693 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5694 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5695 int num_steps = (i == Ydrip_s1 ? 16 :
5696 i == Ydrip_s1B ? 16 :
5697 i == Ydrip_s2 ? 16 :
5698 i == Ydrip_s2B ? 16 :
5699 i == Xsand_stonein_1 ? 32 :
5700 i == Xsand_stonein_2 ? 32 :
5701 i == Xsand_stonein_3 ? 32 :
5702 i == Xsand_stonein_4 ? 32 :
5703 i == Xsand_stoneout_1 ? 16 :
5704 i == Xsand_stoneout_2 ? 16 : 8);
5705 int cx = ABS(dx) * (TILEX / num_steps);
5706 int cy = ABS(dy) * (TILEY / num_steps);
5707 int step_frame = (i == Ydrip_s2 ? j + 8 :
5708 i == Ydrip_s2B ? j + 8 :
5709 i == Xsand_stonein_2 ? j + 8 :
5710 i == Xsand_stonein_3 ? j + 16 :
5711 i == Xsand_stonein_4 ? j + 24 :
5712 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5713 int step = (is_backside ? step_frame : num_steps - step_frame);
5715 if (is_backside) /* tile where movement starts */
5717 if (dx < 0 || dy < 0)
5719 g_em->src_offset_x = cx * step;
5720 g_em->src_offset_y = cy * step;
5724 g_em->dst_offset_x = cx * step;
5725 g_em->dst_offset_y = cy * step;
5728 else /* tile where movement ends */
5730 if (dx < 0 || dy < 0)
5732 g_em->dst_offset_x = cx * step;
5733 g_em->dst_offset_y = cy * step;
5737 g_em->src_offset_x = cx * step;
5738 g_em->src_offset_y = cy * step;
5742 g_em->width = TILEX - cx * step;
5743 g_em->height = TILEY - cy * step;
5747 /* create unique graphic identifier to decide if tile must be redrawn */
5748 /* bit 31 - 16 (16 bit): EM style graphic
5749 bit 15 - 12 ( 4 bit): EM style frame
5750 bit 11 - 6 ( 6 bit): graphic width
5751 bit 5 - 0 ( 6 bit): graphic height */
5752 g_em->unique_identifier =
5753 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5755 /* create unique graphic identifier to decide if tile must be redrawn */
5756 /* bit 31 - 16 (16 bit): EM style element
5757 bit 15 - 12 ( 4 bit): EM style frame
5758 bit 11 - 6 ( 6 bit): graphic width
5759 bit 5 - 0 ( 6 bit): graphic height */
5760 g_em->unique_identifier =
5761 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5765 if (effective_element == EL_ROCK)
5766 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5767 effective_action, j, graphic, frame, g_em->unique_identifier);
5773 /* skip check for EMC elements not contained in original EMC artwork */
5774 if (element == EL_EMC_FAKE_ACID)
5778 if (g_em->bitmap != debug_bitmap ||
5779 g_em->src_x != debug_src_x ||
5780 g_em->src_y != debug_src_y ||
5781 g_em->src_offset_x != 0 ||
5782 g_em->src_offset_y != 0 ||
5783 g_em->dst_offset_x != 0 ||
5784 g_em->dst_offset_y != 0 ||
5785 g_em->width != TILEX ||
5786 g_em->height != TILEY)
5788 static int last_i = -1;
5796 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5797 i, element, element_info[element].token_name,
5798 element_action_info[effective_action].suffix, direction);
5800 if (element != effective_element)
5801 printf(" [%d ('%s')]",
5803 element_info[effective_element].token_name);
5807 if (g_em->bitmap != debug_bitmap)
5808 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5809 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5811 if (g_em->src_x != debug_src_x ||
5812 g_em->src_y != debug_src_y)
5813 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5814 j, (is_backside ? 'B' : 'F'),
5815 g_em->src_x, g_em->src_y,
5816 g_em->src_x / 32, g_em->src_y / 32,
5817 debug_src_x, debug_src_y,
5818 debug_src_x / 32, debug_src_y / 32);
5820 if (g_em->src_offset_x != 0 ||
5821 g_em->src_offset_y != 0 ||
5822 g_em->dst_offset_x != 0 ||
5823 g_em->dst_offset_y != 0)
5824 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5826 g_em->src_offset_x, g_em->src_offset_y,
5827 g_em->dst_offset_x, g_em->dst_offset_y);
5829 if (g_em->width != TILEX ||
5830 g_em->height != TILEY)
5831 printf(" %d (%d): size %d,%d should be %d,%d\n",
5833 g_em->width, g_em->height, TILEX, TILEY);
5835 num_em_gfx_errors++;
5842 for (i = 0; i < TILE_MAX; i++)
5844 for (j = 0; j < 8; j++)
5846 int element = object_mapping[i].element_rnd;
5847 int action = object_mapping[i].action;
5848 int direction = object_mapping[i].direction;
5849 boolean is_backside = object_mapping[i].is_backside;
5851 int graphic_action = el_act_dir2img(element, action, direction);
5852 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5854 int graphic_action = element_info[element].graphic[action];
5855 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5858 if ((action == ACTION_SMASHED_BY_ROCK ||
5859 action == ACTION_SMASHED_BY_SPRING ||
5860 action == ACTION_EATING) &&
5861 graphic_action == graphic_default)
5863 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5864 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5865 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5866 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5869 /* no separate animation for "smashed by rock" -- use rock instead */
5870 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5871 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5873 g_em->bitmap = g_xx->bitmap;
5874 g_em->src_x = g_xx->src_x;
5875 g_em->src_y = g_xx->src_y;
5876 g_em->src_offset_x = g_xx->src_offset_x;
5877 g_em->src_offset_y = g_xx->src_offset_y;
5878 g_em->dst_offset_x = g_xx->dst_offset_x;
5879 g_em->dst_offset_y = g_xx->dst_offset_y;
5880 g_em->width = g_xx->width;
5881 g_em->height = g_xx->height;
5883 g_em->unique_identifier = g_xx->unique_identifier;
5887 g_em->preserve_background = TRUE;
5892 for (p = 0; p < MAX_PLAYERS; p++)
5894 for (i = 0; i < SPR_MAX; i++)
5896 int element = player_mapping[p][i].element_rnd;
5897 int action = player_mapping[p][i].action;
5898 int direction = player_mapping[p][i].direction;
5900 for (j = 0; j < 8; j++)
5902 int effective_element = element;
5903 int effective_action = action;
5904 int graphic = (direction == MV_NONE ?
5905 el_act2img(effective_element, effective_action) :
5906 el_act_dir2img(effective_element, effective_action,
5908 struct GraphicInfo *g = &graphic_info[graphic];
5909 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5915 Bitmap *debug_bitmap = g_em->bitmap;
5916 int debug_src_x = g_em->src_x;
5917 int debug_src_y = g_em->src_y;
5920 int frame = getAnimationFrame(g->anim_frames,
5923 g->anim_start_frame,
5926 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5928 g_em->bitmap = src_bitmap;
5929 g_em->src_x = src_x;
5930 g_em->src_y = src_y;
5931 g_em->src_offset_x = 0;
5932 g_em->src_offset_y = 0;
5933 g_em->dst_offset_x = 0;
5934 g_em->dst_offset_y = 0;
5935 g_em->width = TILEX;
5936 g_em->height = TILEY;
5941 /* skip check for EMC elements not contained in original EMC artwork */
5942 if (element == EL_PLAYER_3 ||
5943 element == EL_PLAYER_4)
5947 if (g_em->bitmap != debug_bitmap ||
5948 g_em->src_x != debug_src_x ||
5949 g_em->src_y != debug_src_y)
5951 static int last_i = -1;
5959 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5960 p, i, element, element_info[element].token_name,
5961 element_action_info[effective_action].suffix, direction);
5963 if (element != effective_element)
5964 printf(" [%d ('%s')]",
5966 element_info[effective_element].token_name);
5970 if (g_em->bitmap != debug_bitmap)
5971 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5972 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5974 if (g_em->src_x != debug_src_x ||
5975 g_em->src_y != debug_src_y)
5976 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5978 g_em->src_x, g_em->src_y,
5979 g_em->src_x / 32, g_em->src_y / 32,
5980 debug_src_x, debug_src_y,
5981 debug_src_x / 32, debug_src_y / 32);
5983 num_em_gfx_errors++;
5993 printf("::: [%d errors found]\n", num_em_gfx_errors);
5999 void PlayMenuSound()
6001 int sound = menu.sound[game_status];
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 PlaySoundLoop(sound);
6016 void PlayMenuSoundStereo(int sound, int stereo_position)
6018 if (sound == SND_UNDEFINED)
6021 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6022 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6025 if (IS_LOOP_SOUND(sound))
6026 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6028 PlaySoundStereo(sound, stereo_position);
6031 void PlayMenuSoundIfLoop()
6033 int sound = menu.sound[game_status];
6035 if (sound == SND_UNDEFINED)
6038 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6039 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6042 if (IS_LOOP_SOUND(sound))
6043 PlaySoundLoop(sound);
6046 void PlayMenuMusic()
6048 int music = menu.music[game_status];
6050 if (music == MUS_UNDEFINED)
6056 void ToggleFullscreenIfNeeded()
6058 if (setup.fullscreen != video.fullscreen_enabled ||
6059 setup.fullscreen_mode != video.fullscreen_mode_current)
6061 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6063 /* save backbuffer content which gets lost when toggling fullscreen mode */
6064 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6066 if (setup.fullscreen && video.fullscreen_enabled)
6068 /* keep fullscreen mode, but change screen mode */
6069 video.fullscreen_mode_current = setup.fullscreen_mode;
6070 video.fullscreen_enabled = FALSE;
6073 /* toggle fullscreen */
6074 ChangeVideoModeIfNeeded(setup.fullscreen);
6075 setup.fullscreen = video.fullscreen_enabled;
6077 /* restore backbuffer content from temporary backbuffer backup bitmap */
6078 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6080 FreeBitmap(tmp_backbuffer);
6082 redraw_mask = REDRAW_ALL;