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 #define FADE_MODE_FADE_IN 0
418 #define FADE_MODE_FADE_OUT 1
419 #define FADE_MODE_CROSSFADE 2
421 static void FadeExt(Bitmap *bitmap_cross, int fade_ms, int fade_mode)
423 static boolean initialization_needed = TRUE;
424 static SDL_Surface *surface_screen_copy = NULL;
425 static SDL_Surface *surface_black = NULL;
426 SDL_Surface *surface_screen = backbuffer->surface;
427 SDL_Surface *surface_cross; /* initialized later */
428 boolean fade_reverse; /* initialized later */
429 unsigned int time_last, time_current;
433 if (initialization_needed)
435 unsigned int flags = SDL_SRCALPHA;
437 /* use same surface type as screen surface */
438 if ((surface_screen->flags & SDL_HWSURFACE))
439 flags |= SDL_HWSURFACE;
441 flags |= SDL_SWSURFACE;
443 /* create surface for temporary copy of screen buffer */
444 if ((surface_screen_copy =
445 SDL_CreateRGBSurface(flags,
448 surface_screen->format->BitsPerPixel,
449 surface_screen->format->Rmask,
450 surface_screen->format->Gmask,
451 surface_screen->format->Bmask,
452 surface_screen->format->Amask)) == NULL)
453 Error(ERR_EXIT, "SDL_CreateRGBSurface( ) failed: %s", SDL_GetError());
455 /* create black surface for fading from/to black */
457 SDL_CreateRGBSurface(flags,
460 surface_screen->format->BitsPerPixel,
461 surface_screen->format->Rmask,
462 surface_screen->format->Gmask,
463 surface_screen->format->Bmask,
464 surface_screen->format->Amask)) == NULL)
465 Error(ERR_EXIT, "SDL_CreateRGBSurface( ) failed: %s", SDL_GetError());
467 /* completely fill the surface with black color pixels */
468 SDL_FillRect(surface_black, NULL,
469 SDL_MapRGB(surface_screen->format, 0, 0, 0));
471 initialization_needed = FALSE;
474 /* copy the current screen backbuffer to the temporary screen copy buffer */
475 SDL_BlitSurface(surface_screen, NULL, surface_screen_copy, NULL);
477 fade_reverse = (fade_mode == FADE_MODE_FADE_IN ? TRUE : FALSE);
478 surface_cross = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_cross->surface :
481 time_current = SDL_GetTicks();
483 for (alpha = 0.0; alpha < 255.0;)
485 time_last = time_current;
486 time_current = SDL_GetTicks();
487 alpha += 255 * ((float)(time_current - time_last) / fade_ms);
488 alpha_final = (int)(fade_reverse ? 255.0 - alpha : alpha);
489 alpha_final = MIN(MAX(0, alpha_final), 255);
491 /* draw existing image to screen buffer */
492 SDL_BlitSurface(surface_screen_copy, NULL, surface_screen, NULL);
494 /* draw new image to screen buffer using alpha blending */
495 SDL_SetAlpha(surface_cross, SDL_SRCALPHA, alpha_final);
496 SDL_BlitSurface(surface_cross, NULL, surface_screen, NULL);
498 /* draw screen buffer to visible display */
499 SDL_Flip(surface_screen);
502 redraw_mask = REDRAW_NONE;
505 void FadeIn(int fade_ms)
508 FadeExt(NULL, fade_ms, FADE_MODE_FADE_IN);
514 void FadeOut(int fade_ms)
517 FadeExt(NULL, fade_ms, FADE_MODE_FADE_OUT);
523 void FadeCross(Bitmap *bitmap, int fade_ms)
526 FadeExt(bitmap, fade_ms, FADE_MODE_CROSSFADE);
532 void SetMainBackgroundImageIfDefined(int graphic)
534 if (graphic_info[graphic].bitmap)
535 SetMainBackgroundImage(graphic);
538 void SetMainBackgroundImage(int graphic)
540 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
541 graphic_info[graphic].bitmap ?
542 graphic_info[graphic].bitmap :
543 graphic_info[IMG_BACKGROUND].bitmap);
546 void SetDoorBackgroundImage(int graphic)
548 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
549 graphic_info[graphic].bitmap ?
550 graphic_info[graphic].bitmap :
551 graphic_info[IMG_BACKGROUND].bitmap);
554 void DrawBackground(int dst_x, int dst_y, int width, int height)
556 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
558 redraw_mask |= REDRAW_FIELD;
563 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
565 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
567 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
568 SetDrawtoField(DRAW_BUFFERED);
571 SetDrawtoField(DRAW_BACKBUFFER);
573 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
575 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
576 SetDrawtoField(DRAW_DIRECT);
580 void MarkTileDirty(int x, int y)
582 int xx = redraw_x1 + x;
583 int yy = redraw_y1 + y;
588 redraw[xx][yy] = TRUE;
589 redraw_mask |= REDRAW_TILES;
592 void SetBorderElement()
596 BorderElement = EL_EMPTY;
598 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
600 for (x = 0; x < lev_fieldx; x++)
602 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
603 BorderElement = EL_STEELWALL;
605 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
611 void SetRandomAnimationValue(int x, int y)
613 gfx.anim_random_frame = GfxRandom[x][y];
616 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
618 /* animation synchronized with global frame counter, not move position */
619 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
620 sync_frame = FrameCounter;
623 if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
629 printf("::: FOO!\n");
633 return getAnimationFrame(graphic_info[graphic].anim_frames,
634 graphic_info[graphic].anim_delay,
635 graphic_info[graphic].anim_mode,
636 graphic_info[graphic].anim_start_frame,
640 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
641 int *x, int *y, boolean get_backside)
643 struct GraphicInfo *g = &graphic_info[graphic];
644 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
645 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
649 if (g->offset_y == 0) /* frames are ordered horizontally */
651 int max_width = g->anim_frames_per_line * g->width;
652 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
654 *x = pos % max_width;
655 *y = src_y % g->height + pos / max_width * g->height;
657 else if (g->offset_x == 0) /* frames are ordered vertically */
659 int max_height = g->anim_frames_per_line * g->height;
660 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
662 *x = src_x % g->width + pos / max_height * g->width;
663 *y = pos % max_height;
665 else /* frames are ordered diagonally */
667 *x = src_x + frame * g->offset_x;
668 *y = src_y + frame * g->offset_y;
672 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
674 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
677 void DrawGraphic(int x, int y, int graphic, int frame)
680 if (!IN_SCR_FIELD(x, y))
682 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
683 printf("DrawGraphic(): This should never happen!\n");
688 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
692 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
698 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
699 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
702 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
705 if (!IN_SCR_FIELD(x, y))
707 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
708 printf("DrawGraphicThruMask(): This should never happen!\n");
713 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
718 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
724 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
726 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
727 dst_x - src_x, dst_y - src_y);
728 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
731 void DrawMiniGraphic(int x, int y, int graphic)
733 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
734 MarkTileDirty(x / 2, y / 2);
737 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
739 struct GraphicInfo *g = &graphic_info[graphic];
741 int mini_starty = g->bitmap->height * 2 / 3;
744 *x = mini_startx + g->src_x / 2;
745 *y = mini_starty + g->src_y / 2;
748 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
753 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
754 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
757 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
758 int graphic, int frame,
759 int cut_mode, int mask_mode)
764 int width = TILEX, height = TILEY;
767 if (dx || dy) /* shifted graphic */
769 if (x < BX1) /* object enters playfield from the left */
776 else if (x > BX2) /* object enters playfield from the right */
782 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
788 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
790 else if (dx) /* general horizontal movement */
791 MarkTileDirty(x + SIGN(dx), y);
793 if (y < BY1) /* object enters playfield from the top */
795 if (cut_mode==CUT_BELOW) /* object completely above top border */
803 else if (y > BY2) /* object enters playfield from the bottom */
809 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
815 else if (dy > 0 && cut_mode == CUT_ABOVE)
817 if (y == BY2) /* object completely above bottom border */
823 MarkTileDirty(x, y + 1);
824 } /* object leaves playfield to the bottom */
825 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
827 else if (dy) /* general vertical movement */
828 MarkTileDirty(x, y + SIGN(dy));
832 if (!IN_SCR_FIELD(x, y))
834 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
835 printf("DrawGraphicShifted(): This should never happen!\n");
840 if (width > 0 && height > 0)
842 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
847 dst_x = FX + x * TILEX + dx;
848 dst_y = FY + y * TILEY + dy;
850 if (mask_mode == USE_MASKING)
852 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
853 dst_x - src_x, dst_y - src_y);
854 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
858 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
865 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
866 int graphic, int frame,
867 int cut_mode, int mask_mode)
872 int width = TILEX, height = TILEY;
875 int x2 = x + SIGN(dx);
876 int y2 = y + SIGN(dy);
877 int anim_frames = graphic_info[graphic].anim_frames;
878 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
879 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
880 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
882 /* re-calculate animation frame for two-tile movement animation */
883 frame = getGraphicAnimationFrame(graphic, sync_frame);
885 /* check if movement start graphic inside screen area and should be drawn */
886 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
888 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
890 dst_x = FX + x1 * TILEX;
891 dst_y = FY + y1 * TILEY;
893 if (mask_mode == USE_MASKING)
895 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
896 dst_x - src_x, dst_y - src_y);
897 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
901 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
904 MarkTileDirty(x1, y1);
907 /* check if movement end graphic inside screen area and should be drawn */
908 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
910 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
912 dst_x = FX + x2 * TILEX;
913 dst_y = FY + y2 * TILEY;
915 if (mask_mode == USE_MASKING)
917 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
918 dst_x - src_x, dst_y - src_y);
919 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
923 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
926 MarkTileDirty(x2, y2);
930 static void DrawGraphicShifted(int x, int y, int dx, int dy,
931 int graphic, int frame,
932 int cut_mode, int mask_mode)
936 DrawGraphic(x, y, graphic, frame);
941 if (graphic_info[graphic].double_movement) /* EM style movement images */
942 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
944 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
947 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
948 int frame, int cut_mode)
950 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
953 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
954 int cut_mode, int mask_mode)
956 int lx = LEVELX(x), ly = LEVELY(y);
960 if (IN_LEV_FIELD(lx, ly))
962 SetRandomAnimationValue(lx, ly);
964 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
965 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
967 /* do not use double (EM style) movement graphic when not moving */
968 if (graphic_info[graphic].double_movement && !dx && !dy)
970 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
971 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
974 else /* border element */
976 graphic = el2img(element);
977 frame = getGraphicAnimationFrame(graphic, -1);
980 if (element == EL_EXPANDABLE_WALL)
982 boolean left_stopped = FALSE, right_stopped = FALSE;
984 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
986 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
987 right_stopped = TRUE;
989 if (left_stopped && right_stopped)
991 else if (left_stopped)
993 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
994 frame = graphic_info[graphic].anim_frames - 1;
996 else if (right_stopped)
998 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
999 frame = graphic_info[graphic].anim_frames - 1;
1004 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1005 else if (mask_mode == USE_MASKING)
1006 DrawGraphicThruMask(x, y, graphic, frame);
1008 DrawGraphic(x, y, graphic, frame);
1011 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1012 int cut_mode, int mask_mode)
1014 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1015 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1016 cut_mode, mask_mode);
1019 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1022 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1025 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1028 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1031 void DrawLevelElementThruMask(int x, int y, int element)
1033 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1036 void DrawLevelFieldThruMask(int x, int y)
1038 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1041 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1045 int sx = SCREENX(x), sy = SCREENY(y);
1047 int width, height, cx, cy, i;
1048 int crumbled_border_size = graphic_info[graphic].border_size;
1049 static int xy[4][2] =
1057 if (!IN_LEV_FIELD(x, y))
1060 element = TILE_GFX_ELEMENT(x, y);
1062 /* crumble field itself */
1063 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1065 if (!IN_SCR_FIELD(sx, sy))
1068 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1070 for (i = 0; i < 4; i++)
1072 int xx = x + xy[i][0];
1073 int yy = y + xy[i][1];
1075 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1078 /* check if neighbour field is of same type */
1079 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1082 if (i == 1 || i == 2)
1084 width = crumbled_border_size;
1086 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1092 height = crumbled_border_size;
1094 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1097 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1098 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1101 MarkTileDirty(sx, sy);
1103 else /* crumble neighbour fields */
1105 for (i = 0; i < 4; i++)
1107 int xx = x + xy[i][0];
1108 int yy = y + xy[i][1];
1109 int sxx = sx + xy[i][0];
1110 int syy = sy + xy[i][1];
1113 if (!IN_LEV_FIELD(xx, yy) ||
1114 !IN_SCR_FIELD(sxx, syy) ||
1119 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1123 element = TILE_GFX_ELEMENT(xx, yy);
1125 if (!GFX_CRUMBLED(element))
1128 if (!IN_LEV_FIELD(xx, yy) ||
1129 !IN_SCR_FIELD(sxx, syy) ||
1130 !GFX_CRUMBLED(Feld[xx][yy]) ||
1136 graphic = el_act2crm(element, ACTION_DEFAULT);
1138 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1140 crumbled_border_size = graphic_info[graphic].border_size;
1142 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1144 if (i == 1 || i == 2)
1146 width = crumbled_border_size;
1148 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1154 height = crumbled_border_size;
1156 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1159 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1160 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1162 MarkTileDirty(sxx, syy);
1167 void DrawLevelFieldCrumbledSand(int x, int y)
1171 if (!IN_LEV_FIELD(x, y))
1175 /* !!! CHECK THIS !!! */
1178 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1179 GFX_CRUMBLED(GfxElement[x][y]))
1182 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1183 GfxElement[x][y] != EL_UNDEFINED &&
1184 GFX_CRUMBLED(GfxElement[x][y]))
1186 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1193 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1195 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1198 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1201 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1204 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1205 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1206 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1207 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1208 int sx = SCREENX(x), sy = SCREENY(y);
1210 DrawGraphic(sx, sy, graphic1, frame1);
1211 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1214 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1216 int sx = SCREENX(x), sy = SCREENY(y);
1217 static int xy[4][2] =
1226 for (i = 0; i < 4; i++)
1228 int xx = x + xy[i][0];
1229 int yy = y + xy[i][1];
1230 int sxx = sx + xy[i][0];
1231 int syy = sy + xy[i][1];
1233 if (!IN_LEV_FIELD(xx, yy) ||
1234 !IN_SCR_FIELD(sxx, syy) ||
1235 !GFX_CRUMBLED(Feld[xx][yy]) ||
1239 DrawLevelField(xx, yy);
1243 static int getBorderElement(int x, int y)
1247 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1248 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1249 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1250 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1251 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1252 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1253 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1255 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1256 int steel_position = (x == -1 && y == -1 ? 0 :
1257 x == lev_fieldx && y == -1 ? 1 :
1258 x == -1 && y == lev_fieldy ? 2 :
1259 x == lev_fieldx && y == lev_fieldy ? 3 :
1260 x == -1 || x == lev_fieldx ? 4 :
1261 y == -1 || y == lev_fieldy ? 5 : 6);
1263 return border[steel_position][steel_type];
1266 void DrawScreenElement(int x, int y, int element)
1268 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1269 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1272 void DrawLevelElement(int x, int y, int element)
1274 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1275 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1278 void DrawScreenField(int x, int y)
1280 int lx = LEVELX(x), ly = LEVELY(y);
1281 int element, content;
1283 if (!IN_LEV_FIELD(lx, ly))
1285 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1288 element = getBorderElement(lx, ly);
1290 DrawScreenElement(x, y, element);
1294 element = Feld[lx][ly];
1295 content = Store[lx][ly];
1297 if (IS_MOVING(lx, ly))
1299 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1300 boolean cut_mode = NO_CUTTING;
1302 if (element == EL_QUICKSAND_EMPTYING ||
1303 element == EL_MAGIC_WALL_EMPTYING ||
1304 element == EL_BD_MAGIC_WALL_EMPTYING ||
1305 element == EL_AMOEBA_DROPPING)
1306 cut_mode = CUT_ABOVE;
1307 else if (element == EL_QUICKSAND_FILLING ||
1308 element == EL_MAGIC_WALL_FILLING ||
1309 element == EL_BD_MAGIC_WALL_FILLING)
1310 cut_mode = CUT_BELOW;
1312 if (cut_mode == CUT_ABOVE)
1313 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1315 DrawScreenElement(x, y, EL_EMPTY);
1318 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1319 else if (cut_mode == NO_CUTTING)
1320 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1322 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1324 if (content == EL_ACID)
1326 int dir = MovDir[lx][ly];
1327 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1328 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1330 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1333 else if (IS_BLOCKED(lx, ly))
1338 boolean cut_mode = NO_CUTTING;
1339 int element_old, content_old;
1341 Blocked2Moving(lx, ly, &oldx, &oldy);
1344 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1345 MovDir[oldx][oldy] == MV_RIGHT);
1347 element_old = Feld[oldx][oldy];
1348 content_old = Store[oldx][oldy];
1350 if (element_old == EL_QUICKSAND_EMPTYING ||
1351 element_old == EL_MAGIC_WALL_EMPTYING ||
1352 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1353 element_old == EL_AMOEBA_DROPPING)
1354 cut_mode = CUT_ABOVE;
1356 DrawScreenElement(x, y, EL_EMPTY);
1359 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1361 else if (cut_mode == NO_CUTTING)
1362 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1365 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1368 else if (IS_DRAWABLE(element))
1369 DrawScreenElement(x, y, element);
1371 DrawScreenElement(x, y, EL_EMPTY);
1374 void DrawLevelField(int x, int y)
1376 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1377 DrawScreenField(SCREENX(x), SCREENY(y));
1378 else if (IS_MOVING(x, y))
1382 Moving2Blocked(x, y, &newx, &newy);
1383 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1384 DrawScreenField(SCREENX(newx), SCREENY(newy));
1386 else if (IS_BLOCKED(x, y))
1390 Blocked2Moving(x, y, &oldx, &oldy);
1391 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1392 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1396 void DrawMiniElement(int x, int y, int element)
1400 graphic = el2edimg(element);
1401 DrawMiniGraphic(x, y, graphic);
1404 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1406 int x = sx + scroll_x, y = sy + scroll_y;
1408 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1409 DrawMiniElement(sx, sy, EL_EMPTY);
1410 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1411 DrawMiniElement(sx, sy, Feld[x][y]);
1413 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1416 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1417 int x, int y, int xsize, int ysize, int font_nr)
1419 int font_width = getFontWidth(font_nr);
1420 int font_height = getFontHeight(font_nr);
1421 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1424 int dst_x = SX + startx + x * font_width;
1425 int dst_y = SY + starty + y * font_height;
1426 int width = graphic_info[graphic].width;
1427 int height = graphic_info[graphic].height;
1428 int inner_width = MAX(width - 2 * font_width, font_width);
1429 int inner_height = MAX(height - 2 * font_height, font_height);
1430 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1431 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1432 boolean draw_masked = graphic_info[graphic].draw_masked;
1434 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1436 if (src_bitmap == NULL || width < font_width || height < font_height)
1438 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1442 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1443 inner_sx + (x - 1) * font_width % inner_width);
1444 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1445 inner_sy + (y - 1) * font_height % inner_height);
1449 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1450 dst_x - src_x, dst_y - src_y);
1451 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1455 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1459 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1461 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1462 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1463 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1464 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1465 boolean no_delay = (tape.warp_forward);
1466 unsigned long anim_delay = 0;
1467 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1468 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1469 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1470 int font_width = getFontWidth(font_nr);
1471 int font_height = getFontHeight(font_nr);
1472 int max_xsize = level.envelope_xsize[envelope_nr];
1473 int max_ysize = level.envelope_ysize[envelope_nr];
1474 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1475 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1476 int xend = max_xsize;
1477 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1478 int xstep = (xstart < xend ? 1 : 0);
1479 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1482 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1484 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1485 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1486 int sx = (SXSIZE - xsize * font_width) / 2;
1487 int sy = (SYSIZE - ysize * font_height) / 2;
1490 SetDrawtoField(DRAW_BUFFERED);
1492 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1494 SetDrawtoField(DRAW_BACKBUFFER);
1496 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1497 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1499 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1500 level.envelope_text[envelope_nr], font_nr, max_xsize,
1501 xsize - 2, ysize - 2, mask_mode);
1503 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1506 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1510 void ShowEnvelope(int envelope_nr)
1512 int element = EL_ENVELOPE_1 + envelope_nr;
1513 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1514 int sound_opening = element_info[element].sound[ACTION_OPENING];
1515 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1516 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1517 boolean no_delay = (tape.warp_forward);
1518 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1519 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1520 int anim_mode = graphic_info[graphic].anim_mode;
1521 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1522 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1524 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1526 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1528 if (anim_mode == ANIM_DEFAULT)
1529 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1531 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1534 Delay(wait_delay_value);
1536 WaitForEventToContinue();
1538 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1540 if (anim_mode != ANIM_NONE)
1541 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1543 if (anim_mode == ANIM_DEFAULT)
1544 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1546 game.envelope_active = FALSE;
1548 SetDrawtoField(DRAW_BUFFERED);
1550 redraw_mask |= REDRAW_FIELD;
1554 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1556 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1557 int mini_startx = src_bitmap->width * 3 / 4;
1558 int mini_starty = src_bitmap->height * 2 / 3;
1559 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1560 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1562 *bitmap = src_bitmap;
1567 void DrawMicroElement(int xpos, int ypos, int element)
1571 int graphic = el2preimg(element);
1573 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1574 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1582 SetDrawBackgroundMask(REDRAW_NONE);
1585 for (x = BX1; x <= BX2; x++)
1586 for (y = BY1; y <= BY2; y++)
1587 DrawScreenField(x, y);
1589 redraw_mask |= REDRAW_FIELD;
1592 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1596 for (x = 0; x < size_x; x++)
1597 for (y = 0; y < size_y; y++)
1598 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1600 redraw_mask |= REDRAW_FIELD;
1603 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1607 DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
1609 if (lev_fieldx < STD_LEV_FIELDX)
1610 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1611 if (lev_fieldy < STD_LEV_FIELDY)
1612 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1614 xpos += MICRO_TILEX;
1615 ypos += MICRO_TILEY;
1617 for (x = -1; x <= STD_LEV_FIELDX; x++)
1619 for (y = -1; y <= STD_LEV_FIELDY; y++)
1621 int lx = from_x + x, ly = from_y + y;
1623 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1624 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1625 level.field[lx][ly]);
1626 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1627 && BorderElement != EL_EMPTY)
1628 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1629 getBorderElement(lx, ly));
1633 redraw_mask |= REDRAW_MICROLEVEL;
1636 #define MICROLABEL_EMPTY 0
1637 #define MICROLABEL_LEVEL_NAME 1
1638 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1639 #define MICROLABEL_LEVEL_AUTHOR 3
1640 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1641 #define MICROLABEL_IMPORTED_FROM 5
1642 #define MICROLABEL_IMPORTED_BY_HEAD 6
1643 #define MICROLABEL_IMPORTED_BY 7
1645 static void DrawMicroLevelLabelExt(int mode)
1647 char label_text[MAX_OUTPUT_LINESIZE + 1];
1648 int max_len_label_text;
1649 int font_nr = FONT_TEXT_2;
1652 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1653 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1654 mode == MICROLABEL_IMPORTED_BY_HEAD)
1655 font_nr = FONT_TEXT_3;
1657 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1659 for (i = 0; i < max_len_label_text; i++)
1660 label_text[i] = ' ';
1661 label_text[max_len_label_text] = '\0';
1663 if (strlen(label_text) > 0)
1665 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1666 int lypos = MICROLABEL2_YPOS;
1668 DrawText(lxpos, lypos, label_text, font_nr);
1672 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1673 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1674 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1675 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1676 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1677 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1678 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1679 max_len_label_text);
1680 label_text[max_len_label_text] = '\0';
1682 if (strlen(label_text) > 0)
1684 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1685 int lypos = MICROLABEL2_YPOS;
1687 DrawText(lxpos, lypos, label_text, font_nr);
1690 redraw_mask |= REDRAW_MICROLEVEL;
1693 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1695 static unsigned long scroll_delay = 0;
1696 static unsigned long label_delay = 0;
1697 static int from_x, from_y, scroll_direction;
1698 static int label_state, label_counter;
1699 int last_game_status = game_status; /* save current game status */
1701 /* force PREVIEW font on preview level */
1702 game_status = GAME_MODE_PSEUDO_PREVIEW;
1706 from_x = from_y = 0;
1707 scroll_direction = MV_RIGHT;
1711 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1712 DrawMicroLevelLabelExt(label_state);
1714 /* initialize delay counters */
1715 DelayReached(&scroll_delay, 0);
1716 DelayReached(&label_delay, 0);
1718 if (leveldir_current->name)
1720 char label_text[MAX_OUTPUT_LINESIZE + 1];
1721 int font_nr = FONT_TEXT_1;
1722 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1725 strncpy(label_text, leveldir_current->name, max_len_label_text);
1726 label_text[max_len_label_text] = '\0';
1728 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1729 lypos = SY + MICROLABEL1_YPOS;
1731 DrawText(lxpos, lypos, label_text, font_nr);
1734 game_status = last_game_status; /* restore current game status */
1739 /* scroll micro level, if needed */
1740 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1741 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1743 switch (scroll_direction)
1749 scroll_direction = MV_UP;
1753 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1756 scroll_direction = MV_DOWN;
1763 scroll_direction = MV_RIGHT;
1767 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1770 scroll_direction = MV_LEFT;
1777 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1780 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1781 /* redraw micro level label, if needed */
1782 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1783 !strEqual(level.author, ANONYMOUS_NAME) &&
1784 !strEqual(level.author, leveldir_current->name) &&
1785 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1787 int max_label_counter = 23;
1789 if (leveldir_current->imported_from != NULL &&
1790 strlen(leveldir_current->imported_from) > 0)
1791 max_label_counter += 14;
1792 if (leveldir_current->imported_by != NULL &&
1793 strlen(leveldir_current->imported_by) > 0)
1794 max_label_counter += 14;
1796 label_counter = (label_counter + 1) % max_label_counter;
1797 label_state = (label_counter >= 0 && label_counter <= 7 ?
1798 MICROLABEL_LEVEL_NAME :
1799 label_counter >= 9 && label_counter <= 12 ?
1800 MICROLABEL_LEVEL_AUTHOR_HEAD :
1801 label_counter >= 14 && label_counter <= 21 ?
1802 MICROLABEL_LEVEL_AUTHOR :
1803 label_counter >= 23 && label_counter <= 26 ?
1804 MICROLABEL_IMPORTED_FROM_HEAD :
1805 label_counter >= 28 && label_counter <= 35 ?
1806 MICROLABEL_IMPORTED_FROM :
1807 label_counter >= 37 && label_counter <= 40 ?
1808 MICROLABEL_IMPORTED_BY_HEAD :
1809 label_counter >= 42 && label_counter <= 49 ?
1810 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1812 if (leveldir_current->imported_from == NULL &&
1813 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1814 label_state == MICROLABEL_IMPORTED_FROM))
1815 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1816 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1818 DrawMicroLevelLabelExt(label_state);
1821 game_status = last_game_status; /* restore current game status */
1824 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1825 int graphic, int sync_frame, int mask_mode)
1827 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1829 if (mask_mode == USE_MASKING)
1830 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1832 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1835 inline void DrawGraphicAnimation(int x, int y, int graphic)
1837 int lx = LEVELX(x), ly = LEVELY(y);
1839 if (!IN_SCR_FIELD(x, y))
1842 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1843 graphic, GfxFrame[lx][ly], NO_MASKING);
1844 MarkTileDirty(x, y);
1847 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1849 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1852 void DrawLevelElementAnimation(int x, int y, int element)
1854 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1856 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1859 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1861 int sx = SCREENX(x), sy = SCREENY(y);
1863 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1866 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1869 DrawGraphicAnimation(sx, sy, graphic);
1872 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1873 DrawLevelFieldCrumbledSand(x, y);
1875 if (GFX_CRUMBLED(Feld[x][y]))
1876 DrawLevelFieldCrumbledSand(x, y);
1880 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1882 int sx = SCREENX(x), sy = SCREENY(y);
1885 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1888 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1890 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1893 DrawGraphicAnimation(sx, sy, graphic);
1895 if (GFX_CRUMBLED(element))
1896 DrawLevelFieldCrumbledSand(x, y);
1899 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1901 if (player->use_murphy)
1903 /* this works only because currently only one player can be "murphy" ... */
1904 static int last_horizontal_dir = MV_LEFT;
1905 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1907 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1908 last_horizontal_dir = move_dir;
1910 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1912 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1914 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1920 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1923 static boolean equalGraphics(int graphic1, int graphic2)
1925 struct GraphicInfo *g1 = &graphic_info[graphic1];
1926 struct GraphicInfo *g2 = &graphic_info[graphic2];
1928 return (g1->bitmap == g2->bitmap &&
1929 g1->src_x == g2->src_x &&
1930 g1->src_y == g2->src_y &&
1931 g1->anim_frames == g2->anim_frames &&
1932 g1->anim_delay == g2->anim_delay &&
1933 g1->anim_mode == g2->anim_mode);
1936 void DrawAllPlayers()
1940 for (i = 0; i < MAX_PLAYERS; i++)
1941 if (stored_player[i].active)
1942 DrawPlayer(&stored_player[i]);
1945 void DrawPlayerField(int x, int y)
1947 if (!IS_PLAYER(x, y))
1950 DrawPlayer(PLAYERINFO(x, y));
1953 void DrawPlayer(struct PlayerInfo *player)
1955 int jx = player->jx;
1956 int jy = player->jy;
1957 int move_dir = player->MovDir;
1958 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1959 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1960 int last_jx = (player->is_moving ? jx - dx : jx);
1961 int last_jy = (player->is_moving ? jy - dy : jy);
1962 int next_jx = jx + dx;
1963 int next_jy = jy + dy;
1964 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1965 boolean player_is_opaque = FALSE;
1966 int sx = SCREENX(jx), sy = SCREENY(jy);
1967 int sxx = 0, syy = 0;
1968 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1970 int action = ACTION_DEFAULT;
1971 int last_player_graphic = getPlayerGraphic(player, move_dir);
1972 int last_player_frame = player->Frame;
1976 /* GfxElement[][] is set to the element the player is digging or collecting;
1977 remove also for off-screen player if the player is not moving anymore */
1978 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1979 GfxElement[jx][jy] = EL_UNDEFINED;
1982 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1986 if (!IN_LEV_FIELD(jx, jy))
1988 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1989 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1990 printf("DrawPlayerField(): This should never happen!\n");
1995 if (element == EL_EXPLOSION)
1998 action = (player->is_pushing ? ACTION_PUSHING :
1999 player->is_digging ? ACTION_DIGGING :
2000 player->is_collecting ? ACTION_COLLECTING :
2001 player->is_moving ? ACTION_MOVING :
2002 player->is_snapping ? ACTION_SNAPPING :
2003 player->is_dropping ? ACTION_DROPPING :
2004 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2007 if (player->is_waiting)
2008 move_dir = player->dir_waiting;
2011 InitPlayerGfxAnimation(player, action, move_dir);
2013 /* ----------------------------------------------------------------------- */
2014 /* draw things in the field the player is leaving, if needed */
2015 /* ----------------------------------------------------------------------- */
2017 if (player->is_moving)
2019 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2021 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2023 if (last_element == EL_DYNAMITE_ACTIVE ||
2024 last_element == EL_EM_DYNAMITE_ACTIVE ||
2025 last_element == EL_SP_DISK_RED_ACTIVE)
2026 DrawDynamite(last_jx, last_jy);
2028 DrawLevelFieldThruMask(last_jx, last_jy);
2030 else if (last_element == EL_DYNAMITE_ACTIVE ||
2031 last_element == EL_EM_DYNAMITE_ACTIVE ||
2032 last_element == EL_SP_DISK_RED_ACTIVE)
2033 DrawDynamite(last_jx, last_jy);
2035 DrawLevelField(last_jx, last_jy);
2037 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2038 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2041 if (!IN_SCR_FIELD(sx, sy))
2044 if (setup.direct_draw)
2045 SetDrawtoField(DRAW_BUFFERED);
2047 /* ----------------------------------------------------------------------- */
2048 /* draw things behind the player, if needed */
2049 /* ----------------------------------------------------------------------- */
2052 DrawLevelElement(jx, jy, Back[jx][jy]);
2053 else if (IS_ACTIVE_BOMB(element))
2054 DrawLevelElement(jx, jy, EL_EMPTY);
2057 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2059 int old_element = GfxElement[jx][jy];
2060 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2061 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2063 if (GFX_CRUMBLED(old_element))
2064 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2066 DrawGraphic(sx, sy, old_graphic, frame);
2068 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2069 player_is_opaque = TRUE;
2073 GfxElement[jx][jy] = EL_UNDEFINED;
2075 /* make sure that pushed elements are drawn with correct frame rate */
2076 if (player->is_pushing && player->is_moving)
2077 GfxFrame[jx][jy] = player->StepFrame;
2079 DrawLevelField(jx, jy);
2083 /* ----------------------------------------------------------------------- */
2084 /* draw player himself */
2085 /* ----------------------------------------------------------------------- */
2087 graphic = getPlayerGraphic(player, move_dir);
2089 /* in the case of changed player action or direction, prevent the current
2090 animation frame from being restarted for identical animations */
2091 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2092 player->Frame = last_player_frame;
2094 frame = getGraphicAnimationFrame(graphic, player->Frame);
2098 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2099 sxx = player->GfxPos;
2101 syy = player->GfxPos;
2104 if (!setup.soft_scrolling && ScreenMovPos)
2107 if (player_is_opaque)
2108 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2110 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2112 if (SHIELD_ON(player))
2114 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2115 IMG_SHIELD_NORMAL_ACTIVE);
2116 int frame = getGraphicAnimationFrame(graphic, -1);
2118 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2121 /* ----------------------------------------------------------------------- */
2122 /* draw things the player is pushing, if needed */
2123 /* ----------------------------------------------------------------------- */
2126 printf("::: %d, %d [%d, %d] [%d]\n",
2127 player->is_pushing, player_is_moving, player->GfxAction,
2128 player->is_moving, player_is_moving);
2132 if (player->is_pushing && player->is_moving)
2134 int px = SCREENX(jx), py = SCREENY(jy);
2135 int pxx = (TILEX - ABS(sxx)) * dx;
2136 int pyy = (TILEY - ABS(syy)) * dy;
2141 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2142 element = Feld[next_jx][next_jy];
2144 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2145 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2147 /* draw background element under pushed element (like the Sokoban field) */
2148 if (Back[next_jx][next_jy])
2149 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2151 /* masked drawing is needed for EMC style (double) movement graphics */
2152 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2156 /* ----------------------------------------------------------------------- */
2157 /* draw things in front of player (active dynamite or dynabombs) */
2158 /* ----------------------------------------------------------------------- */
2160 if (IS_ACTIVE_BOMB(element))
2162 graphic = el2img(element);
2163 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2165 if (game.emulation == EMU_SUPAPLEX)
2166 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2168 DrawGraphicThruMask(sx, sy, graphic, frame);
2171 if (player_is_moving && last_element == EL_EXPLOSION)
2173 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2174 GfxElement[last_jx][last_jy] : EL_EMPTY);
2175 int graphic = el_act2img(element, ACTION_EXPLODING);
2176 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2177 int phase = ExplodePhase[last_jx][last_jy] - 1;
2178 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2181 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2184 /* ----------------------------------------------------------------------- */
2185 /* draw elements the player is just walking/passing through/under */
2186 /* ----------------------------------------------------------------------- */
2188 if (player_is_moving)
2190 /* handle the field the player is leaving ... */
2191 if (IS_ACCESSIBLE_INSIDE(last_element))
2192 DrawLevelField(last_jx, last_jy);
2193 else if (IS_ACCESSIBLE_UNDER(last_element))
2194 DrawLevelFieldThruMask(last_jx, last_jy);
2197 /* do not redraw accessible elements if the player is just pushing them */
2198 if (!player_is_moving || !player->is_pushing)
2200 /* ... and the field the player is entering */
2201 if (IS_ACCESSIBLE_INSIDE(element))
2202 DrawLevelField(jx, jy);
2203 else if (IS_ACCESSIBLE_UNDER(element))
2204 DrawLevelFieldThruMask(jx, jy);
2207 if (setup.direct_draw)
2209 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2210 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2211 int x_size = TILEX * (1 + ABS(jx - last_jx));
2212 int y_size = TILEY * (1 + ABS(jy - last_jy));
2214 BlitBitmap(drawto_field, window,
2215 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2216 SetDrawtoField(DRAW_DIRECT);
2219 MarkTileDirty(sx, sy);
2222 /* ------------------------------------------------------------------------- */
2224 void WaitForEventToContinue()
2226 boolean still_wait = TRUE;
2228 /* simulate releasing mouse button over last gadget, if still pressed */
2230 HandleGadgets(-1, -1, 0);
2232 button_status = MB_RELEASED;
2244 case EVENT_BUTTONPRESS:
2245 case EVENT_KEYPRESS:
2249 case EVENT_KEYRELEASE:
2250 ClearPlayerAction();
2254 HandleOtherEvents(&event);
2258 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2265 /* don't eat all CPU time */
2270 #define MAX_REQUEST_LINES 13
2271 #define MAX_REQUEST_LINE_FONT1_LEN 7
2272 #define MAX_REQUEST_LINE_FONT2_LEN 10
2274 boolean Request(char *text, unsigned int req_state)
2276 int mx, my, ty, result = -1;
2277 unsigned int old_door_state;
2278 int last_game_status = game_status; /* save current game status */
2279 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2280 int font_nr = FONT_TEXT_2;
2281 int max_word_len = 0;
2284 for (text_ptr = text; *text_ptr; text_ptr++)
2286 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2288 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2290 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2291 font_nr = FONT_LEVEL_NUMBER;
2297 if (game_status == GAME_MODE_PLAYING &&
2298 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2299 BlitScreenToBitmap_EM(backbuffer);
2301 /* disable deactivated drawing when quick-loading level tape recording */
2302 if (tape.playing && tape.deactivate_display)
2303 TapeDeactivateDisplayOff(TRUE);
2305 SetMouseCursor(CURSOR_DEFAULT);
2307 #if defined(NETWORK_AVALIABLE)
2308 /* pause network game while waiting for request to answer */
2309 if (options.network &&
2310 game_status == GAME_MODE_PLAYING &&
2311 req_state & REQUEST_WAIT_FOR_INPUT)
2312 SendToServer_PausePlaying();
2315 old_door_state = GetDoorState();
2317 /* simulate releasing mouse button over last gadget, if still pressed */
2319 HandleGadgets(-1, -1, 0);
2323 if (old_door_state & DOOR_OPEN_1)
2325 CloseDoor(DOOR_CLOSE_1);
2327 /* save old door content */
2328 BlitBitmap(bitmap_db_door, bitmap_db_door,
2329 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2330 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2333 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2335 /* clear door drawing field */
2336 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2338 /* force DOOR font on preview level */
2339 game_status = GAME_MODE_PSEUDO_DOOR;
2341 /* write text for request */
2342 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2344 char text_line[max_request_line_len + 1];
2350 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2353 if (!tc || tc == ' ')
2364 strncpy(text_line, text, tl);
2367 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2368 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2369 text_line, font_nr);
2371 text += tl + (tc == ' ' ? 1 : 0);
2374 game_status = last_game_status; /* restore current game status */
2376 if (req_state & REQ_ASK)
2378 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2379 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2381 else if (req_state & REQ_CONFIRM)
2383 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2385 else if (req_state & REQ_PLAYER)
2387 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2388 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2389 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2390 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2393 /* copy request gadgets to door backbuffer */
2394 BlitBitmap(drawto, bitmap_db_door,
2395 DX, DY, DXSIZE, DYSIZE,
2396 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2398 OpenDoor(DOOR_OPEN_1);
2400 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2402 SetDrawBackgroundMask(REDRAW_FIELD);
2407 if (game_status != GAME_MODE_MAIN)
2410 button_status = MB_RELEASED;
2412 request_gadget_id = -1;
2414 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2426 case EVENT_BUTTONPRESS:
2427 case EVENT_BUTTONRELEASE:
2428 case EVENT_MOTIONNOTIFY:
2430 if (event.type == EVENT_MOTIONNOTIFY)
2432 if (!PointerInWindow(window))
2433 continue; /* window and pointer are on different screens */
2438 motion_status = TRUE;
2439 mx = ((MotionEvent *) &event)->x;
2440 my = ((MotionEvent *) &event)->y;
2444 motion_status = FALSE;
2445 mx = ((ButtonEvent *) &event)->x;
2446 my = ((ButtonEvent *) &event)->y;
2447 if (event.type == EVENT_BUTTONPRESS)
2448 button_status = ((ButtonEvent *) &event)->button;
2450 button_status = MB_RELEASED;
2453 /* this sets 'request_gadget_id' */
2454 HandleGadgets(mx, my, button_status);
2456 switch(request_gadget_id)
2458 case TOOL_CTRL_ID_YES:
2461 case TOOL_CTRL_ID_NO:
2464 case TOOL_CTRL_ID_CONFIRM:
2465 result = TRUE | FALSE;
2468 case TOOL_CTRL_ID_PLAYER_1:
2471 case TOOL_CTRL_ID_PLAYER_2:
2474 case TOOL_CTRL_ID_PLAYER_3:
2477 case TOOL_CTRL_ID_PLAYER_4:
2488 case EVENT_KEYPRESS:
2489 switch(GetEventKey((KeyEvent *)&event, TRUE))
2502 if (req_state & REQ_PLAYER)
2506 case EVENT_KEYRELEASE:
2507 ClearPlayerAction();
2511 HandleOtherEvents(&event);
2515 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2517 int joy = AnyJoystick();
2519 if (joy & JOY_BUTTON_1)
2521 else if (joy & JOY_BUTTON_2)
2527 /* don't eat all CPU time */
2531 if (game_status != GAME_MODE_MAIN)
2536 if (!(req_state & REQ_STAY_OPEN))
2538 CloseDoor(DOOR_CLOSE_1);
2540 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2541 (req_state & REQ_REOPEN))
2542 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2547 SetDrawBackgroundMask(REDRAW_FIELD);
2549 #if defined(NETWORK_AVALIABLE)
2550 /* continue network game after request */
2551 if (options.network &&
2552 game_status == GAME_MODE_PLAYING &&
2553 req_state & REQUEST_WAIT_FOR_INPUT)
2554 SendToServer_ContinuePlaying();
2557 /* restore deactivated drawing when quick-loading level tape recording */
2558 if (tape.playing && tape.deactivate_display)
2559 TapeDeactivateDisplayOn();
2564 unsigned int OpenDoor(unsigned int door_state)
2566 if (door_state & DOOR_COPY_BACK)
2568 if (door_state & DOOR_OPEN_1)
2569 BlitBitmap(bitmap_db_door, bitmap_db_door,
2570 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2571 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2573 if (door_state & DOOR_OPEN_2)
2574 BlitBitmap(bitmap_db_door, bitmap_db_door,
2575 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2576 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2578 door_state &= ~DOOR_COPY_BACK;
2581 return MoveDoor(door_state);
2584 unsigned int CloseDoor(unsigned int door_state)
2586 unsigned int old_door_state = GetDoorState();
2588 if (!(door_state & DOOR_NO_COPY_BACK))
2590 if (old_door_state & DOOR_OPEN_1)
2591 BlitBitmap(backbuffer, bitmap_db_door,
2592 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2594 if (old_door_state & DOOR_OPEN_2)
2595 BlitBitmap(backbuffer, bitmap_db_door,
2596 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2598 door_state &= ~DOOR_NO_COPY_BACK;
2601 return MoveDoor(door_state);
2604 unsigned int GetDoorState()
2606 return MoveDoor(DOOR_GET_STATE);
2609 unsigned int SetDoorState(unsigned int door_state)
2611 return MoveDoor(door_state | DOOR_SET_STATE);
2614 unsigned int MoveDoor(unsigned int door_state)
2616 static int door1 = DOOR_OPEN_1;
2617 static int door2 = DOOR_CLOSE_2;
2618 unsigned long door_delay = 0;
2619 unsigned long door_delay_value;
2622 if (door_1.width < 0 || door_1.width > DXSIZE)
2623 door_1.width = DXSIZE;
2624 if (door_1.height < 0 || door_1.height > DYSIZE)
2625 door_1.height = DYSIZE;
2626 if (door_2.width < 0 || door_2.width > VXSIZE)
2627 door_2.width = VXSIZE;
2628 if (door_2.height < 0 || door_2.height > VYSIZE)
2629 door_2.height = VYSIZE;
2631 if (door_state == DOOR_GET_STATE)
2632 return (door1 | door2);
2634 if (door_state & DOOR_SET_STATE)
2636 if (door_state & DOOR_ACTION_1)
2637 door1 = door_state & DOOR_ACTION_1;
2638 if (door_state & DOOR_ACTION_2)
2639 door2 = door_state & DOOR_ACTION_2;
2641 return (door1 | door2);
2644 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2645 door_state &= ~DOOR_OPEN_1;
2646 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2647 door_state &= ~DOOR_CLOSE_1;
2648 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2649 door_state &= ~DOOR_OPEN_2;
2650 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2651 door_state &= ~DOOR_CLOSE_2;
2653 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2656 if (setup.quick_doors)
2658 stepsize = 20; /* must be choosen to always draw last frame */
2659 door_delay_value = 0;
2662 if (global.autoplay_leveldir)
2664 door_state |= DOOR_NO_DELAY;
2665 door_state &= ~DOOR_CLOSE_ALL;
2668 if (door_state & DOOR_ACTION)
2670 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2671 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2672 boolean door_1_done = (!handle_door_1);
2673 boolean door_2_done = (!handle_door_2);
2674 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2675 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2676 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2677 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2678 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2679 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2680 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2681 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2682 int door_skip = max_door_size - door_size;
2684 int end = door_size;
2686 int end = (door_state & DOOR_ACTION_1 &&
2687 door_1.anim_mode & ANIM_VERTICAL ? DYSIZE : DXSIZE);
2690 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2692 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2696 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2698 /* opening door sound has priority over simultaneously closing door */
2699 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2700 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2701 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2702 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2705 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2708 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2709 GC gc = bitmap->stored_clip_gc;
2711 if (door_state & DOOR_ACTION_1)
2713 int a = MIN(x * door_1.step_offset, end);
2714 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2715 int i = p + door_skip;
2717 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2719 BlitBitmap(bitmap_db_door, drawto,
2720 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2721 DXSIZE, DYSIZE, DX, DY);
2725 BlitBitmap(bitmap_db_door, drawto,
2726 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2727 DXSIZE, DYSIZE - p / 2, DX, DY);
2729 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2732 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2734 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2735 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2736 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2737 int dst2_x = DX, dst2_y = DY;
2738 int width = i, height = DYSIZE;
2740 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2741 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2744 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2745 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2748 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2750 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2751 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2752 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2753 int dst2_x = DX, dst2_y = DY;
2754 int width = DXSIZE, height = i;
2756 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2757 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2760 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2761 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2764 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2766 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2768 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2769 BlitBitmapMasked(bitmap, drawto,
2770 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2771 DX + DXSIZE - i, DY + j);
2772 BlitBitmapMasked(bitmap, drawto,
2773 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2774 DX + DXSIZE - i, DY + 140 + j);
2775 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2776 DY - (DOOR_GFX_PAGEY1 + j));
2777 BlitBitmapMasked(bitmap, drawto,
2778 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2780 BlitBitmapMasked(bitmap, drawto,
2781 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2784 BlitBitmapMasked(bitmap, drawto,
2785 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2787 BlitBitmapMasked(bitmap, drawto,
2788 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2790 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2791 BlitBitmapMasked(bitmap, drawto,
2792 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2793 DX + DXSIZE - i, DY + 77 + j);
2794 BlitBitmapMasked(bitmap, drawto,
2795 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2796 DX + DXSIZE - i, DY + 203 + j);
2799 redraw_mask |= REDRAW_DOOR_1;
2800 door_1_done = (a == end);
2803 if (door_state & DOOR_ACTION_2)
2805 int a = MIN(x * door_2.step_offset, door_size_2);
2806 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2807 int i = p + door_skip;
2809 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2811 BlitBitmap(bitmap_db_door, drawto,
2812 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2813 VXSIZE, VYSIZE, VX, VY);
2815 else if (x <= VYSIZE)
2817 BlitBitmap(bitmap_db_door, drawto,
2818 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2819 VXSIZE, VYSIZE - p / 2, VX, VY);
2821 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2824 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2826 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2827 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2828 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2829 int dst2_x = VX, dst2_y = VY;
2830 int width = i, height = VYSIZE;
2832 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2833 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2836 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2837 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2840 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2842 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2843 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2844 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2845 int dst2_x = VX, dst2_y = VY;
2846 int width = VXSIZE, height = i;
2848 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2849 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2852 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2853 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2856 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2858 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2860 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2861 BlitBitmapMasked(bitmap, drawto,
2862 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2863 VX + VXSIZE - i, VY + j);
2864 SetClipOrigin(bitmap, gc,
2865 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2866 BlitBitmapMasked(bitmap, drawto,
2867 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2870 BlitBitmapMasked(bitmap, drawto,
2871 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2872 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2873 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2874 BlitBitmapMasked(bitmap, drawto,
2875 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2877 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2880 redraw_mask |= REDRAW_DOOR_2;
2881 door_2_done = (a == VXSIZE);
2884 if (!(door_state & DOOR_NO_DELAY))
2888 if (game_status == GAME_MODE_MAIN)
2891 WaitUntilDelayReached(&door_delay, door_delay_value);
2896 if (door_state & DOOR_ACTION_1)
2897 door1 = door_state & DOOR_ACTION_1;
2898 if (door_state & DOOR_ACTION_2)
2899 door2 = door_state & DOOR_ACTION_2;
2901 return (door1 | door2);
2904 void DrawSpecialEditorDoor()
2906 /* draw bigger toolbox window */
2907 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2908 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2910 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2911 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2914 redraw_mask |= REDRAW_ALL;
2917 void UndrawSpecialEditorDoor()
2919 /* draw normal tape recorder window */
2920 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2921 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2924 redraw_mask |= REDRAW_ALL;
2928 /* ---------- new tool button stuff ---------------------------------------- */
2930 /* graphic position values for tool buttons */
2931 #define TOOL_BUTTON_YES_XPOS 2
2932 #define TOOL_BUTTON_YES_YPOS 250
2933 #define TOOL_BUTTON_YES_GFX_YPOS 0
2934 #define TOOL_BUTTON_YES_XSIZE 46
2935 #define TOOL_BUTTON_YES_YSIZE 28
2936 #define TOOL_BUTTON_NO_XPOS 52
2937 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2938 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2939 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2940 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2941 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2942 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2943 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2944 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2945 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2946 #define TOOL_BUTTON_PLAYER_XSIZE 30
2947 #define TOOL_BUTTON_PLAYER_YSIZE 30
2948 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2949 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2950 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2951 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2952 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2953 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2954 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2955 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2956 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2957 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2958 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2959 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2960 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2961 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2962 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2963 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2964 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2965 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2966 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2967 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2976 } toolbutton_info[NUM_TOOL_BUTTONS] =
2979 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2980 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2981 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2986 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2987 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2988 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2993 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2994 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2995 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2996 TOOL_CTRL_ID_CONFIRM,
3000 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3001 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3002 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3003 TOOL_CTRL_ID_PLAYER_1,
3007 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3008 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3009 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3010 TOOL_CTRL_ID_PLAYER_2,
3014 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3015 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3016 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3017 TOOL_CTRL_ID_PLAYER_3,
3021 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3022 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3023 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3024 TOOL_CTRL_ID_PLAYER_4,
3029 void CreateToolButtons()
3033 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3035 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3036 Bitmap *deco_bitmap = None;
3037 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3038 struct GadgetInfo *gi;
3039 unsigned long event_mask;
3040 int gd_xoffset, gd_yoffset;
3041 int gd_x1, gd_x2, gd_y;
3044 event_mask = GD_EVENT_RELEASED;
3046 gd_xoffset = toolbutton_info[i].xpos;
3047 gd_yoffset = toolbutton_info[i].ypos;
3048 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3049 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3050 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3052 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3054 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3056 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3057 &deco_bitmap, &deco_x, &deco_y);
3058 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3059 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3062 gi = CreateGadget(GDI_CUSTOM_ID, id,
3063 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3064 GDI_X, DX + toolbutton_info[i].x,
3065 GDI_Y, DY + toolbutton_info[i].y,
3066 GDI_WIDTH, toolbutton_info[i].width,
3067 GDI_HEIGHT, toolbutton_info[i].height,
3068 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3069 GDI_STATE, GD_BUTTON_UNPRESSED,
3070 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3071 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3072 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3073 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3074 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3075 GDI_DECORATION_SHIFTING, 1, 1,
3076 GDI_EVENT_MASK, event_mask,
3077 GDI_CALLBACK_ACTION, HandleToolButtons,
3081 Error(ERR_EXIT, "cannot create gadget");
3083 tool_gadget[id] = gi;
3087 void FreeToolButtons()
3091 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3092 FreeGadget(tool_gadget[i]);
3095 static void UnmapToolButtons()
3099 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3100 UnmapGadget(tool_gadget[i]);
3103 static void HandleToolButtons(struct GadgetInfo *gi)
3105 request_gadget_id = gi->custom_id;
3108 static struct Mapping_EM_to_RND_object
3111 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3112 boolean is_backside; /* backside of moving element */
3118 em_object_mapping_list[] =
3121 Xblank, TRUE, FALSE,
3125 Yacid_splash_eB, FALSE, FALSE,
3126 EL_ACID_SPLASH_RIGHT, -1, -1
3129 Yacid_splash_wB, FALSE, FALSE,
3130 EL_ACID_SPLASH_LEFT, -1, -1
3133 #ifdef EM_ENGINE_BAD_ROLL
3135 Xstone_force_e, FALSE, FALSE,
3136 EL_ROCK, -1, MV_BIT_RIGHT
3139 Xstone_force_w, FALSE, FALSE,
3140 EL_ROCK, -1, MV_BIT_LEFT
3143 Xnut_force_e, FALSE, FALSE,
3144 EL_NUT, -1, MV_BIT_RIGHT
3147 Xnut_force_w, FALSE, FALSE,
3148 EL_NUT, -1, MV_BIT_LEFT
3151 Xspring_force_e, FALSE, FALSE,
3152 EL_SPRING, -1, MV_BIT_RIGHT
3155 Xspring_force_w, FALSE, FALSE,
3156 EL_SPRING, -1, MV_BIT_LEFT
3159 Xemerald_force_e, FALSE, FALSE,
3160 EL_EMERALD, -1, MV_BIT_RIGHT
3163 Xemerald_force_w, FALSE, FALSE,
3164 EL_EMERALD, -1, MV_BIT_LEFT
3167 Xdiamond_force_e, FALSE, FALSE,
3168 EL_DIAMOND, -1, MV_BIT_RIGHT
3171 Xdiamond_force_w, FALSE, FALSE,
3172 EL_DIAMOND, -1, MV_BIT_LEFT
3175 Xbomb_force_e, FALSE, FALSE,
3176 EL_BOMB, -1, MV_BIT_RIGHT
3179 Xbomb_force_w, FALSE, FALSE,
3180 EL_BOMB, -1, MV_BIT_LEFT
3182 #endif /* EM_ENGINE_BAD_ROLL */
3185 Xstone, TRUE, FALSE,
3189 Xstone_pause, FALSE, FALSE,
3193 Xstone_fall, FALSE, FALSE,
3197 Ystone_s, FALSE, FALSE,
3198 EL_ROCK, ACTION_FALLING, -1
3201 Ystone_sB, FALSE, TRUE,
3202 EL_ROCK, ACTION_FALLING, -1
3205 Ystone_e, FALSE, FALSE,
3206 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3209 Ystone_eB, FALSE, TRUE,
3210 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3213 Ystone_w, FALSE, FALSE,
3214 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3217 Ystone_wB, FALSE, TRUE,
3218 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3225 Xnut_pause, FALSE, FALSE,
3229 Xnut_fall, FALSE, FALSE,
3233 Ynut_s, FALSE, FALSE,
3234 EL_NUT, ACTION_FALLING, -1
3237 Ynut_sB, FALSE, TRUE,
3238 EL_NUT, ACTION_FALLING, -1
3241 Ynut_e, FALSE, FALSE,
3242 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3245 Ynut_eB, FALSE, TRUE,
3246 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3249 Ynut_w, FALSE, FALSE,
3250 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3253 Ynut_wB, FALSE, TRUE,
3254 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3257 Xbug_n, TRUE, FALSE,
3261 Xbug_e, TRUE, FALSE,
3262 EL_BUG_RIGHT, -1, -1
3265 Xbug_s, TRUE, FALSE,
3269 Xbug_w, TRUE, FALSE,
3273 Xbug_gon, FALSE, FALSE,
3277 Xbug_goe, FALSE, FALSE,
3278 EL_BUG_RIGHT, -1, -1
3281 Xbug_gos, FALSE, FALSE,
3285 Xbug_gow, FALSE, FALSE,
3289 Ybug_n, FALSE, FALSE,
3290 EL_BUG, ACTION_MOVING, MV_BIT_UP
3293 Ybug_nB, FALSE, TRUE,
3294 EL_BUG, ACTION_MOVING, MV_BIT_UP
3297 Ybug_e, FALSE, FALSE,
3298 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3301 Ybug_eB, FALSE, TRUE,
3302 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3305 Ybug_s, FALSE, FALSE,
3306 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3309 Ybug_sB, FALSE, TRUE,
3310 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3313 Ybug_w, FALSE, FALSE,
3314 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3317 Ybug_wB, FALSE, TRUE,
3318 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3321 Ybug_w_n, FALSE, FALSE,
3322 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3325 Ybug_n_e, FALSE, FALSE,
3326 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3329 Ybug_e_s, FALSE, FALSE,
3330 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3333 Ybug_s_w, FALSE, FALSE,
3334 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3337 Ybug_e_n, FALSE, FALSE,
3338 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3341 Ybug_s_e, FALSE, FALSE,
3342 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3345 Ybug_w_s, FALSE, FALSE,
3346 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3349 Ybug_n_w, FALSE, FALSE,
3350 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3353 Ybug_stone, FALSE, FALSE,
3354 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3357 Ybug_spring, FALSE, FALSE,
3358 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3361 Xtank_n, TRUE, FALSE,
3362 EL_SPACESHIP_UP, -1, -1
3365 Xtank_e, TRUE, FALSE,
3366 EL_SPACESHIP_RIGHT, -1, -1
3369 Xtank_s, TRUE, FALSE,
3370 EL_SPACESHIP_DOWN, -1, -1
3373 Xtank_w, TRUE, FALSE,
3374 EL_SPACESHIP_LEFT, -1, -1
3377 Xtank_gon, FALSE, FALSE,
3378 EL_SPACESHIP_UP, -1, -1
3381 Xtank_goe, FALSE, FALSE,
3382 EL_SPACESHIP_RIGHT, -1, -1
3385 Xtank_gos, FALSE, FALSE,
3386 EL_SPACESHIP_DOWN, -1, -1
3389 Xtank_gow, FALSE, FALSE,
3390 EL_SPACESHIP_LEFT, -1, -1
3393 Ytank_n, FALSE, FALSE,
3394 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3397 Ytank_nB, FALSE, TRUE,
3398 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3401 Ytank_e, FALSE, FALSE,
3402 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3405 Ytank_eB, FALSE, TRUE,
3406 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3409 Ytank_s, FALSE, FALSE,
3410 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3413 Ytank_sB, FALSE, TRUE,
3414 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3417 Ytank_w, FALSE, FALSE,
3418 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3421 Ytank_wB, FALSE, TRUE,
3422 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3425 Ytank_w_n, FALSE, FALSE,
3426 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3429 Ytank_n_e, FALSE, FALSE,
3430 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3433 Ytank_e_s, FALSE, FALSE,
3434 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3437 Ytank_s_w, FALSE, FALSE,
3438 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3441 Ytank_e_n, FALSE, FALSE,
3442 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3445 Ytank_s_e, FALSE, FALSE,
3446 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3449 Ytank_w_s, FALSE, FALSE,
3450 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3453 Ytank_n_w, FALSE, FALSE,
3454 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3457 Ytank_stone, FALSE, FALSE,
3458 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3461 Ytank_spring, FALSE, FALSE,
3462 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3465 Xandroid, TRUE, FALSE,
3466 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3469 Xandroid_1_n, FALSE, FALSE,
3470 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3473 Xandroid_2_n, FALSE, FALSE,
3474 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3477 Xandroid_1_e, FALSE, FALSE,
3478 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3481 Xandroid_2_e, FALSE, FALSE,
3482 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3485 Xandroid_1_w, FALSE, FALSE,
3486 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3489 Xandroid_2_w, FALSE, FALSE,
3490 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3493 Xandroid_1_s, FALSE, FALSE,
3494 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3497 Xandroid_2_s, FALSE, FALSE,
3498 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3501 Yandroid_n, FALSE, FALSE,
3502 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3505 Yandroid_nB, FALSE, TRUE,
3506 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3509 Yandroid_ne, FALSE, FALSE,
3510 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3513 Yandroid_neB, FALSE, TRUE,
3514 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3517 Yandroid_e, FALSE, FALSE,
3518 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3521 Yandroid_eB, FALSE, TRUE,
3522 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3525 Yandroid_se, FALSE, FALSE,
3526 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3529 Yandroid_seB, FALSE, TRUE,
3530 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3533 Yandroid_s, FALSE, FALSE,
3534 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3537 Yandroid_sB, FALSE, TRUE,
3538 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3541 Yandroid_sw, FALSE, FALSE,
3542 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3545 Yandroid_swB, FALSE, TRUE,
3546 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3549 Yandroid_w, FALSE, FALSE,
3550 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3553 Yandroid_wB, FALSE, TRUE,
3554 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3557 Yandroid_nw, FALSE, FALSE,
3558 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3561 Yandroid_nwB, FALSE, TRUE,
3562 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3565 Xspring, TRUE, FALSE,
3569 Xspring_pause, FALSE, FALSE,
3573 Xspring_e, FALSE, FALSE,
3577 Xspring_w, FALSE, FALSE,
3581 Xspring_fall, FALSE, FALSE,
3585 Yspring_s, FALSE, FALSE,
3586 EL_SPRING, ACTION_FALLING, -1
3589 Yspring_sB, FALSE, TRUE,
3590 EL_SPRING, ACTION_FALLING, -1
3593 Yspring_e, FALSE, FALSE,
3594 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3597 Yspring_eB, FALSE, TRUE,
3598 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3601 Yspring_w, FALSE, FALSE,
3602 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3605 Yspring_wB, FALSE, TRUE,
3606 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3609 Yspring_kill_e, FALSE, FALSE,
3610 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3613 Yspring_kill_eB, FALSE, TRUE,
3614 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3617 Yspring_kill_w, FALSE, FALSE,
3618 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3621 Yspring_kill_wB, FALSE, TRUE,
3622 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3625 Xeater_n, TRUE, FALSE,
3626 EL_YAMYAM_UP, -1, -1
3629 Xeater_e, TRUE, FALSE,
3630 EL_YAMYAM_RIGHT, -1, -1
3633 Xeater_w, TRUE, FALSE,
3634 EL_YAMYAM_LEFT, -1, -1
3637 Xeater_s, TRUE, FALSE,
3638 EL_YAMYAM_DOWN, -1, -1
3641 Yeater_n, FALSE, FALSE,
3642 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3645 Yeater_nB, FALSE, TRUE,
3646 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3649 Yeater_e, FALSE, FALSE,
3650 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3653 Yeater_eB, FALSE, TRUE,
3654 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3657 Yeater_s, FALSE, FALSE,
3658 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3661 Yeater_sB, FALSE, TRUE,
3662 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3665 Yeater_w, FALSE, FALSE,
3666 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3669 Yeater_wB, FALSE, TRUE,
3670 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3673 Yeater_stone, FALSE, FALSE,
3674 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3677 Yeater_spring, FALSE, FALSE,
3678 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3681 Xalien, TRUE, FALSE,
3685 Xalien_pause, FALSE, FALSE,
3689 Yalien_n, FALSE, FALSE,
3690 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3693 Yalien_nB, FALSE, TRUE,
3694 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3697 Yalien_e, FALSE, FALSE,
3698 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3701 Yalien_eB, FALSE, TRUE,
3702 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3705 Yalien_s, FALSE, FALSE,
3706 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3709 Yalien_sB, FALSE, TRUE,
3710 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3713 Yalien_w, FALSE, FALSE,
3714 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3717 Yalien_wB, FALSE, TRUE,
3718 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3721 Yalien_stone, FALSE, FALSE,
3722 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3725 Yalien_spring, FALSE, FALSE,
3726 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3729 Xemerald, TRUE, FALSE,
3733 Xemerald_pause, FALSE, FALSE,
3737 Xemerald_fall, FALSE, FALSE,
3741 Xemerald_shine, FALSE, FALSE,
3742 EL_EMERALD, ACTION_TWINKLING, -1
3745 Yemerald_s, FALSE, FALSE,
3746 EL_EMERALD, ACTION_FALLING, -1
3749 Yemerald_sB, FALSE, TRUE,
3750 EL_EMERALD, ACTION_FALLING, -1
3753 Yemerald_e, FALSE, FALSE,
3754 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3757 Yemerald_eB, FALSE, TRUE,
3758 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3761 Yemerald_w, FALSE, FALSE,
3762 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3765 Yemerald_wB, FALSE, TRUE,
3766 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3769 Yemerald_eat, FALSE, FALSE,
3770 EL_EMERALD, ACTION_COLLECTING, -1
3773 Yemerald_stone, FALSE, FALSE,
3774 EL_NUT, ACTION_BREAKING, -1
3777 Xdiamond, TRUE, FALSE,
3781 Xdiamond_pause, FALSE, FALSE,
3785 Xdiamond_fall, FALSE, FALSE,
3789 Xdiamond_shine, FALSE, FALSE,
3790 EL_DIAMOND, ACTION_TWINKLING, -1
3793 Ydiamond_s, FALSE, FALSE,
3794 EL_DIAMOND, ACTION_FALLING, -1
3797 Ydiamond_sB, FALSE, TRUE,
3798 EL_DIAMOND, ACTION_FALLING, -1
3801 Ydiamond_e, FALSE, FALSE,
3802 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3805 Ydiamond_eB, FALSE, TRUE,
3806 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3809 Ydiamond_w, FALSE, FALSE,
3810 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3813 Ydiamond_wB, FALSE, TRUE,
3814 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3817 Ydiamond_eat, FALSE, FALSE,
3818 EL_DIAMOND, ACTION_COLLECTING, -1
3821 Ydiamond_stone, FALSE, FALSE,
3822 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3825 Xdrip_fall, TRUE, FALSE,
3826 EL_AMOEBA_DROP, -1, -1
3829 Xdrip_stretch, FALSE, FALSE,
3830 EL_AMOEBA_DROP, ACTION_FALLING, -1
3833 Xdrip_stretchB, FALSE, TRUE,
3834 EL_AMOEBA_DROP, ACTION_FALLING, -1
3837 Xdrip_eat, FALSE, FALSE,
3838 EL_AMOEBA_DROP, ACTION_GROWING, -1
3841 Ydrip_s1, FALSE, FALSE,
3842 EL_AMOEBA_DROP, ACTION_FALLING, -1
3845 Ydrip_s1B, FALSE, TRUE,
3846 EL_AMOEBA_DROP, ACTION_FALLING, -1
3849 Ydrip_s2, FALSE, FALSE,
3850 EL_AMOEBA_DROP, ACTION_FALLING, -1
3853 Ydrip_s2B, FALSE, TRUE,
3854 EL_AMOEBA_DROP, ACTION_FALLING, -1
3861 Xbomb_pause, FALSE, FALSE,
3865 Xbomb_fall, FALSE, FALSE,
3869 Ybomb_s, FALSE, FALSE,
3870 EL_BOMB, ACTION_FALLING, -1
3873 Ybomb_sB, FALSE, TRUE,
3874 EL_BOMB, ACTION_FALLING, -1
3877 Ybomb_e, FALSE, FALSE,
3878 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3881 Ybomb_eB, FALSE, TRUE,
3882 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3885 Ybomb_w, FALSE, FALSE,
3886 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3889 Ybomb_wB, FALSE, TRUE,
3890 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3893 Ybomb_eat, FALSE, FALSE,
3894 EL_BOMB, ACTION_ACTIVATING, -1
3897 Xballoon, TRUE, FALSE,
3901 Yballoon_n, FALSE, FALSE,
3902 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3905 Yballoon_nB, FALSE, TRUE,
3906 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3909 Yballoon_e, FALSE, FALSE,
3910 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3913 Yballoon_eB, FALSE, TRUE,
3914 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3917 Yballoon_s, FALSE, FALSE,
3918 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3921 Yballoon_sB, FALSE, TRUE,
3922 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3925 Yballoon_w, FALSE, FALSE,
3926 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3929 Yballoon_wB, FALSE, TRUE,
3930 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3933 Xgrass, TRUE, FALSE,
3934 EL_EMC_GRASS, -1, -1
3937 Ygrass_nB, FALSE, FALSE,
3938 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3941 Ygrass_eB, FALSE, FALSE,
3942 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3945 Ygrass_sB, FALSE, FALSE,
3946 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3949 Ygrass_wB, FALSE, FALSE,
3950 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3957 Ydirt_nB, FALSE, FALSE,
3958 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3961 Ydirt_eB, FALSE, FALSE,
3962 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3965 Ydirt_sB, FALSE, FALSE,
3966 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3969 Ydirt_wB, FALSE, FALSE,
3970 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3973 Xacid_ne, TRUE, FALSE,
3974 EL_ACID_POOL_TOPRIGHT, -1, -1
3977 Xacid_se, TRUE, FALSE,
3978 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3981 Xacid_s, TRUE, FALSE,
3982 EL_ACID_POOL_BOTTOM, -1, -1
3985 Xacid_sw, TRUE, FALSE,
3986 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3989 Xacid_nw, TRUE, FALSE,
3990 EL_ACID_POOL_TOPLEFT, -1, -1
3993 Xacid_1, TRUE, FALSE,
3997 Xacid_2, FALSE, FALSE,
4001 Xacid_3, FALSE, FALSE,
4005 Xacid_4, FALSE, FALSE,
4009 Xacid_5, FALSE, FALSE,
4013 Xacid_6, FALSE, FALSE,
4017 Xacid_7, FALSE, FALSE,
4021 Xacid_8, FALSE, FALSE,
4025 Xball_1, TRUE, FALSE,
4026 EL_EMC_MAGIC_BALL, -1, -1
4029 Xball_1B, FALSE, FALSE,
4030 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4033 Xball_2, FALSE, FALSE,
4034 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4037 Xball_2B, FALSE, FALSE,
4038 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4041 Yball_eat, FALSE, FALSE,
4042 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4045 Ykey_1_eat, FALSE, FALSE,
4046 EL_EM_KEY_1, ACTION_COLLECTING, -1
4049 Ykey_2_eat, FALSE, FALSE,
4050 EL_EM_KEY_2, ACTION_COLLECTING, -1
4053 Ykey_3_eat, FALSE, FALSE,
4054 EL_EM_KEY_3, ACTION_COLLECTING, -1
4057 Ykey_4_eat, FALSE, FALSE,
4058 EL_EM_KEY_4, ACTION_COLLECTING, -1
4061 Ykey_5_eat, FALSE, FALSE,
4062 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4065 Ykey_6_eat, FALSE, FALSE,
4066 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4069 Ykey_7_eat, FALSE, FALSE,
4070 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4073 Ykey_8_eat, FALSE, FALSE,
4074 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4077 Ylenses_eat, FALSE, FALSE,
4078 EL_EMC_LENSES, ACTION_COLLECTING, -1
4081 Ymagnify_eat, FALSE, FALSE,
4082 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4085 Ygrass_eat, FALSE, FALSE,
4086 EL_EMC_GRASS, ACTION_SNAPPING, -1
4089 Ydirt_eat, FALSE, FALSE,
4090 EL_SAND, ACTION_SNAPPING, -1
4093 Xgrow_ns, TRUE, FALSE,
4094 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4097 Ygrow_ns_eat, FALSE, FALSE,
4098 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4101 Xgrow_ew, TRUE, FALSE,
4102 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4105 Ygrow_ew_eat, FALSE, FALSE,
4106 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4109 Xwonderwall, TRUE, FALSE,
4110 EL_MAGIC_WALL, -1, -1
4113 XwonderwallB, FALSE, FALSE,
4114 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4117 Xamoeba_1, TRUE, FALSE,
4118 EL_AMOEBA_DRY, ACTION_OTHER, -1
4121 Xamoeba_2, FALSE, FALSE,
4122 EL_AMOEBA_DRY, ACTION_OTHER, -1
4125 Xamoeba_3, FALSE, FALSE,
4126 EL_AMOEBA_DRY, ACTION_OTHER, -1
4129 Xamoeba_4, FALSE, FALSE,
4130 EL_AMOEBA_DRY, ACTION_OTHER, -1
4133 Xamoeba_5, TRUE, FALSE,
4134 EL_AMOEBA_WET, ACTION_OTHER, -1
4137 Xamoeba_6, FALSE, FALSE,
4138 EL_AMOEBA_WET, ACTION_OTHER, -1
4141 Xamoeba_7, FALSE, FALSE,
4142 EL_AMOEBA_WET, ACTION_OTHER, -1
4145 Xamoeba_8, FALSE, FALSE,
4146 EL_AMOEBA_WET, ACTION_OTHER, -1
4149 Xdoor_1, TRUE, FALSE,
4150 EL_EM_GATE_1, -1, -1
4153 Xdoor_2, TRUE, FALSE,
4154 EL_EM_GATE_2, -1, -1
4157 Xdoor_3, TRUE, FALSE,
4158 EL_EM_GATE_3, -1, -1
4161 Xdoor_4, TRUE, FALSE,
4162 EL_EM_GATE_4, -1, -1
4165 Xdoor_5, TRUE, FALSE,
4166 EL_EMC_GATE_5, -1, -1
4169 Xdoor_6, TRUE, FALSE,
4170 EL_EMC_GATE_6, -1, -1
4173 Xdoor_7, TRUE, FALSE,
4174 EL_EMC_GATE_7, -1, -1
4177 Xdoor_8, TRUE, FALSE,
4178 EL_EMC_GATE_8, -1, -1
4181 Xkey_1, TRUE, FALSE,
4185 Xkey_2, TRUE, FALSE,
4189 Xkey_3, TRUE, FALSE,
4193 Xkey_4, TRUE, FALSE,
4197 Xkey_5, TRUE, FALSE,
4198 EL_EMC_KEY_5, -1, -1
4201 Xkey_6, TRUE, FALSE,
4202 EL_EMC_KEY_6, -1, -1
4205 Xkey_7, TRUE, FALSE,
4206 EL_EMC_KEY_7, -1, -1
4209 Xkey_8, TRUE, FALSE,
4210 EL_EMC_KEY_8, -1, -1
4213 Xwind_n, TRUE, FALSE,
4214 EL_BALLOON_SWITCH_UP, -1, -1
4217 Xwind_e, TRUE, FALSE,
4218 EL_BALLOON_SWITCH_RIGHT, -1, -1
4221 Xwind_s, TRUE, FALSE,
4222 EL_BALLOON_SWITCH_DOWN, -1, -1
4225 Xwind_w, TRUE, FALSE,
4226 EL_BALLOON_SWITCH_LEFT, -1, -1
4229 Xwind_nesw, TRUE, FALSE,
4230 EL_BALLOON_SWITCH_ANY, -1, -1
4233 Xwind_stop, TRUE, FALSE,
4234 EL_BALLOON_SWITCH_NONE, -1, -1
4238 EL_EXIT_CLOSED, -1, -1
4241 Xexit_1, TRUE, FALSE,
4242 EL_EXIT_OPEN, -1, -1
4245 Xexit_2, FALSE, FALSE,
4246 EL_EXIT_OPEN, -1, -1
4249 Xexit_3, FALSE, FALSE,
4250 EL_EXIT_OPEN, -1, -1
4253 Xdynamite, TRUE, FALSE,
4254 EL_EM_DYNAMITE, -1, -1
4257 Ydynamite_eat, FALSE, FALSE,
4258 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4261 Xdynamite_1, TRUE, FALSE,
4262 EL_EM_DYNAMITE_ACTIVE, -1, -1
4265 Xdynamite_2, FALSE, FALSE,
4266 EL_EM_DYNAMITE_ACTIVE, -1, -1
4269 Xdynamite_3, FALSE, FALSE,
4270 EL_EM_DYNAMITE_ACTIVE, -1, -1
4273 Xdynamite_4, FALSE, FALSE,
4274 EL_EM_DYNAMITE_ACTIVE, -1, -1
4277 Xbumper, TRUE, FALSE,
4278 EL_EMC_SPRING_BUMPER, -1, -1
4281 XbumperB, FALSE, FALSE,
4282 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4285 Xwheel, TRUE, FALSE,
4286 EL_ROBOT_WHEEL, -1, -1
4289 XwheelB, FALSE, FALSE,
4290 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4293 Xswitch, TRUE, FALSE,
4294 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4297 XswitchB, FALSE, FALSE,
4298 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4302 EL_QUICKSAND_EMPTY, -1, -1
4305 Xsand_stone, TRUE, FALSE,
4306 EL_QUICKSAND_FULL, -1, -1
4309 Xsand_stonein_1, FALSE, TRUE,
4310 EL_ROCK, ACTION_FILLING, -1
4313 Xsand_stonein_2, FALSE, TRUE,
4314 EL_ROCK, ACTION_FILLING, -1
4317 Xsand_stonein_3, FALSE, TRUE,
4318 EL_ROCK, ACTION_FILLING, -1
4321 Xsand_stonein_4, FALSE, TRUE,
4322 EL_ROCK, ACTION_FILLING, -1
4325 Xsand_stonesand_1, FALSE, FALSE,
4326 EL_QUICKSAND_FULL, -1, -1
4329 Xsand_stonesand_2, FALSE, FALSE,
4330 EL_QUICKSAND_FULL, -1, -1
4333 Xsand_stonesand_3, FALSE, FALSE,
4334 EL_QUICKSAND_FULL, -1, -1
4337 Xsand_stonesand_4, FALSE, FALSE,
4338 EL_QUICKSAND_FULL, -1, -1
4341 Xsand_stoneout_1, FALSE, FALSE,
4342 EL_ROCK, ACTION_EMPTYING, -1
4345 Xsand_stoneout_2, FALSE, FALSE,
4346 EL_ROCK, ACTION_EMPTYING, -1
4349 Xsand_sandstone_1, FALSE, FALSE,
4350 EL_QUICKSAND_FULL, -1, -1
4353 Xsand_sandstone_2, FALSE, FALSE,
4354 EL_QUICKSAND_FULL, -1, -1
4357 Xsand_sandstone_3, FALSE, FALSE,
4358 EL_QUICKSAND_FULL, -1, -1
4361 Xsand_sandstone_4, FALSE, FALSE,
4362 EL_QUICKSAND_FULL, -1, -1
4365 Xplant, TRUE, FALSE,
4366 EL_EMC_PLANT, -1, -1
4369 Yplant, FALSE, FALSE,
4370 EL_EMC_PLANT, -1, -1
4373 Xlenses, TRUE, FALSE,
4374 EL_EMC_LENSES, -1, -1
4377 Xmagnify, TRUE, FALSE,
4378 EL_EMC_MAGNIFIER, -1, -1
4381 Xdripper, TRUE, FALSE,
4382 EL_EMC_DRIPPER, -1, -1
4385 XdripperB, FALSE, FALSE,
4386 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4389 Xfake_blank, TRUE, FALSE,
4390 EL_INVISIBLE_WALL, -1, -1
4393 Xfake_blankB, FALSE, FALSE,
4394 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4397 Xfake_grass, TRUE, FALSE,
4398 EL_EMC_FAKE_GRASS, -1, -1
4401 Xfake_grassB, FALSE, FALSE,
4402 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4405 Xfake_door_1, TRUE, FALSE,
4406 EL_EM_GATE_1_GRAY, -1, -1
4409 Xfake_door_2, TRUE, FALSE,
4410 EL_EM_GATE_2_GRAY, -1, -1
4413 Xfake_door_3, TRUE, FALSE,
4414 EL_EM_GATE_3_GRAY, -1, -1
4417 Xfake_door_4, TRUE, FALSE,
4418 EL_EM_GATE_4_GRAY, -1, -1
4421 Xfake_door_5, TRUE, FALSE,
4422 EL_EMC_GATE_5_GRAY, -1, -1
4425 Xfake_door_6, TRUE, FALSE,
4426 EL_EMC_GATE_6_GRAY, -1, -1
4429 Xfake_door_7, TRUE, FALSE,
4430 EL_EMC_GATE_7_GRAY, -1, -1
4433 Xfake_door_8, TRUE, FALSE,
4434 EL_EMC_GATE_8_GRAY, -1, -1
4437 Xfake_acid_1, TRUE, FALSE,
4438 EL_EMC_FAKE_ACID, -1, -1
4441 Xfake_acid_2, FALSE, FALSE,
4442 EL_EMC_FAKE_ACID, -1, -1
4445 Xfake_acid_3, FALSE, FALSE,
4446 EL_EMC_FAKE_ACID, -1, -1
4449 Xfake_acid_4, FALSE, FALSE,
4450 EL_EMC_FAKE_ACID, -1, -1
4453 Xfake_acid_5, FALSE, FALSE,
4454 EL_EMC_FAKE_ACID, -1, -1
4457 Xfake_acid_6, FALSE, FALSE,
4458 EL_EMC_FAKE_ACID, -1, -1
4461 Xfake_acid_7, FALSE, FALSE,
4462 EL_EMC_FAKE_ACID, -1, -1
4465 Xfake_acid_8, FALSE, FALSE,
4466 EL_EMC_FAKE_ACID, -1, -1
4469 Xsteel_1, TRUE, FALSE,
4470 EL_STEELWALL, -1, -1
4473 Xsteel_2, TRUE, FALSE,
4474 EL_EMC_STEELWALL_2, -1, -1
4477 Xsteel_3, TRUE, FALSE,
4478 EL_EMC_STEELWALL_3, -1, -1
4481 Xsteel_4, TRUE, FALSE,
4482 EL_EMC_STEELWALL_4, -1, -1
4485 Xwall_1, TRUE, FALSE,
4489 Xwall_2, TRUE, FALSE,
4490 EL_EMC_WALL_14, -1, -1
4493 Xwall_3, TRUE, FALSE,
4494 EL_EMC_WALL_15, -1, -1
4497 Xwall_4, TRUE, FALSE,
4498 EL_EMC_WALL_16, -1, -1
4501 Xround_wall_1, TRUE, FALSE,
4502 EL_WALL_SLIPPERY, -1, -1
4505 Xround_wall_2, TRUE, FALSE,
4506 EL_EMC_WALL_SLIPPERY_2, -1, -1
4509 Xround_wall_3, TRUE, FALSE,
4510 EL_EMC_WALL_SLIPPERY_3, -1, -1
4513 Xround_wall_4, TRUE, FALSE,
4514 EL_EMC_WALL_SLIPPERY_4, -1, -1
4517 Xdecor_1, TRUE, FALSE,
4518 EL_EMC_WALL_8, -1, -1
4521 Xdecor_2, TRUE, FALSE,
4522 EL_EMC_WALL_6, -1, -1
4525 Xdecor_3, TRUE, FALSE,
4526 EL_EMC_WALL_4, -1, -1
4529 Xdecor_4, TRUE, FALSE,
4530 EL_EMC_WALL_7, -1, -1
4533 Xdecor_5, TRUE, FALSE,
4534 EL_EMC_WALL_5, -1, -1
4537 Xdecor_6, TRUE, FALSE,
4538 EL_EMC_WALL_9, -1, -1
4541 Xdecor_7, TRUE, FALSE,
4542 EL_EMC_WALL_10, -1, -1
4545 Xdecor_8, TRUE, FALSE,
4546 EL_EMC_WALL_1, -1, -1
4549 Xdecor_9, TRUE, FALSE,
4550 EL_EMC_WALL_2, -1, -1
4553 Xdecor_10, TRUE, FALSE,
4554 EL_EMC_WALL_3, -1, -1
4557 Xdecor_11, TRUE, FALSE,
4558 EL_EMC_WALL_11, -1, -1
4561 Xdecor_12, TRUE, FALSE,
4562 EL_EMC_WALL_12, -1, -1
4565 Xalpha_0, TRUE, FALSE,
4566 EL_CHAR('0'), -1, -1
4569 Xalpha_1, TRUE, FALSE,
4570 EL_CHAR('1'), -1, -1
4573 Xalpha_2, TRUE, FALSE,
4574 EL_CHAR('2'), -1, -1
4577 Xalpha_3, TRUE, FALSE,
4578 EL_CHAR('3'), -1, -1
4581 Xalpha_4, TRUE, FALSE,
4582 EL_CHAR('4'), -1, -1
4585 Xalpha_5, TRUE, FALSE,
4586 EL_CHAR('5'), -1, -1
4589 Xalpha_6, TRUE, FALSE,
4590 EL_CHAR('6'), -1, -1
4593 Xalpha_7, TRUE, FALSE,
4594 EL_CHAR('7'), -1, -1
4597 Xalpha_8, TRUE, FALSE,
4598 EL_CHAR('8'), -1, -1
4601 Xalpha_9, TRUE, FALSE,
4602 EL_CHAR('9'), -1, -1
4605 Xalpha_excla, TRUE, FALSE,
4606 EL_CHAR('!'), -1, -1
4609 Xalpha_quote, TRUE, FALSE,
4610 EL_CHAR('"'), -1, -1
4613 Xalpha_comma, TRUE, FALSE,
4614 EL_CHAR(','), -1, -1
4617 Xalpha_minus, TRUE, FALSE,
4618 EL_CHAR('-'), -1, -1
4621 Xalpha_perio, TRUE, FALSE,
4622 EL_CHAR('.'), -1, -1
4625 Xalpha_colon, TRUE, FALSE,
4626 EL_CHAR(':'), -1, -1
4629 Xalpha_quest, TRUE, FALSE,
4630 EL_CHAR('?'), -1, -1
4633 Xalpha_a, TRUE, FALSE,
4634 EL_CHAR('A'), -1, -1
4637 Xalpha_b, TRUE, FALSE,
4638 EL_CHAR('B'), -1, -1
4641 Xalpha_c, TRUE, FALSE,
4642 EL_CHAR('C'), -1, -1
4645 Xalpha_d, TRUE, FALSE,
4646 EL_CHAR('D'), -1, -1
4649 Xalpha_e, TRUE, FALSE,
4650 EL_CHAR('E'), -1, -1
4653 Xalpha_f, TRUE, FALSE,
4654 EL_CHAR('F'), -1, -1
4657 Xalpha_g, TRUE, FALSE,
4658 EL_CHAR('G'), -1, -1
4661 Xalpha_h, TRUE, FALSE,
4662 EL_CHAR('H'), -1, -1
4665 Xalpha_i, TRUE, FALSE,
4666 EL_CHAR('I'), -1, -1
4669 Xalpha_j, TRUE, FALSE,
4670 EL_CHAR('J'), -1, -1
4673 Xalpha_k, TRUE, FALSE,
4674 EL_CHAR('K'), -1, -1
4677 Xalpha_l, TRUE, FALSE,
4678 EL_CHAR('L'), -1, -1
4681 Xalpha_m, TRUE, FALSE,
4682 EL_CHAR('M'), -1, -1
4685 Xalpha_n, TRUE, FALSE,
4686 EL_CHAR('N'), -1, -1
4689 Xalpha_o, TRUE, FALSE,
4690 EL_CHAR('O'), -1, -1
4693 Xalpha_p, TRUE, FALSE,
4694 EL_CHAR('P'), -1, -1
4697 Xalpha_q, TRUE, FALSE,
4698 EL_CHAR('Q'), -1, -1
4701 Xalpha_r, TRUE, FALSE,
4702 EL_CHAR('R'), -1, -1
4705 Xalpha_s, TRUE, FALSE,
4706 EL_CHAR('S'), -1, -1
4709 Xalpha_t, TRUE, FALSE,
4710 EL_CHAR('T'), -1, -1
4713 Xalpha_u, TRUE, FALSE,
4714 EL_CHAR('U'), -1, -1
4717 Xalpha_v, TRUE, FALSE,
4718 EL_CHAR('V'), -1, -1
4721 Xalpha_w, TRUE, FALSE,
4722 EL_CHAR('W'), -1, -1
4725 Xalpha_x, TRUE, FALSE,
4726 EL_CHAR('X'), -1, -1
4729 Xalpha_y, TRUE, FALSE,
4730 EL_CHAR('Y'), -1, -1
4733 Xalpha_z, TRUE, FALSE,
4734 EL_CHAR('Z'), -1, -1
4737 Xalpha_arrow_e, TRUE, FALSE,
4738 EL_CHAR('>'), -1, -1
4741 Xalpha_arrow_w, TRUE, FALSE,
4742 EL_CHAR('<'), -1, -1
4745 Xalpha_copyr, TRUE, FALSE,
4746 EL_CHAR('©'), -1, -1
4750 Xboom_bug, FALSE, FALSE,
4751 EL_BUG, ACTION_EXPLODING, -1
4754 Xboom_bomb, FALSE, FALSE,
4755 EL_BOMB, ACTION_EXPLODING, -1
4758 Xboom_android, FALSE, FALSE,
4759 EL_EMC_ANDROID, ACTION_OTHER, -1
4762 Xboom_1, FALSE, FALSE,
4763 EL_DEFAULT, ACTION_EXPLODING, -1
4766 Xboom_2, FALSE, FALSE,
4767 EL_DEFAULT, ACTION_EXPLODING, -1
4770 Znormal, FALSE, FALSE,
4774 Zdynamite, FALSE, FALSE,
4778 Zplayer, FALSE, FALSE,
4782 ZBORDER, FALSE, FALSE,
4792 static struct Mapping_EM_to_RND_player
4801 em_player_mapping_list[] =
4805 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4809 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4813 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4817 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4821 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4825 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4829 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4833 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4837 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4841 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4845 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4849 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4853 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4857 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4861 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4865 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4869 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4873 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4877 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4881 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4885 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4889 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4893 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4897 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4901 EL_PLAYER_1, ACTION_DEFAULT, -1,
4905 EL_PLAYER_2, ACTION_DEFAULT, -1,
4909 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4913 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4917 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4921 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4925 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4929 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4933 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4937 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4941 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4945 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4949 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4953 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4957 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4961 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4965 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4969 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4973 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4977 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4981 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4985 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4989 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4993 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4997 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5001 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5005 EL_PLAYER_3, ACTION_DEFAULT, -1,
5009 EL_PLAYER_4, ACTION_DEFAULT, -1,
5018 int map_element_RND_to_EM(int element_rnd)
5020 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5021 static boolean mapping_initialized = FALSE;
5023 if (!mapping_initialized)
5027 /* return "Xalpha_quest" for all undefined elements in mapping array */
5028 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5029 mapping_RND_to_EM[i] = Xalpha_quest;
5031 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5032 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5033 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5034 em_object_mapping_list[i].element_em;
5036 mapping_initialized = TRUE;
5039 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5040 return mapping_RND_to_EM[element_rnd];
5042 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5047 int map_element_EM_to_RND(int element_em)
5049 static unsigned short mapping_EM_to_RND[TILE_MAX];
5050 static boolean mapping_initialized = FALSE;
5052 if (!mapping_initialized)
5056 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5057 for (i = 0; i < TILE_MAX; i++)
5058 mapping_EM_to_RND[i] = EL_UNKNOWN;
5060 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5061 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5062 em_object_mapping_list[i].element_rnd;
5064 mapping_initialized = TRUE;
5067 if (element_em >= 0 && element_em < TILE_MAX)
5068 return mapping_EM_to_RND[element_em];
5070 Error(ERR_WARN, "invalid EM level element %d", element_em);
5075 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5077 struct LevelInfo_EM *level_em = level->native_em_level;
5078 struct LEVEL *lev = level_em->lev;
5081 for (i = 0; i < TILE_MAX; i++)
5082 lev->android_array[i] = Xblank;
5084 for (i = 0; i < level->num_android_clone_elements; i++)
5086 int element_rnd = level->android_clone_element[i];
5087 int element_em = map_element_RND_to_EM(element_rnd);
5089 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5090 if (em_object_mapping_list[j].element_rnd == element_rnd)
5091 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5095 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5097 struct LevelInfo_EM *level_em = level->native_em_level;
5098 struct LEVEL *lev = level_em->lev;
5101 level->num_android_clone_elements = 0;
5103 for (i = 0; i < TILE_MAX; i++)
5105 int element_em = lev->android_array[i];
5107 boolean element_found = FALSE;
5109 if (element_em == Xblank)
5112 element_rnd = map_element_EM_to_RND(element_em);
5114 for (j = 0; j < level->num_android_clone_elements; j++)
5115 if (level->android_clone_element[j] == element_rnd)
5116 element_found = TRUE;
5120 level->android_clone_element[level->num_android_clone_elements++] =
5123 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5128 if (level->num_android_clone_elements == 0)
5130 level->num_android_clone_elements = 1;
5131 level->android_clone_element[0] = EL_EMPTY;
5135 int map_direction_RND_to_EM(int direction)
5137 return (direction == MV_UP ? 0 :
5138 direction == MV_RIGHT ? 1 :
5139 direction == MV_DOWN ? 2 :
5140 direction == MV_LEFT ? 3 :
5144 int map_direction_EM_to_RND(int direction)
5146 return (direction == 0 ? MV_UP :
5147 direction == 1 ? MV_RIGHT :
5148 direction == 2 ? MV_DOWN :
5149 direction == 3 ? MV_LEFT :
5153 int get_next_element(int element)
5157 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5158 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5159 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5160 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5161 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5162 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5163 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5165 default: return element;
5170 int el_act_dir2img(int element, int action, int direction)
5172 element = GFX_ELEMENT(element);
5174 if (direction == MV_NONE)
5175 return element_info[element].graphic[action];
5177 direction = MV_DIR_TO_BIT(direction);
5179 return element_info[element].direction_graphic[action][direction];
5182 int el_act_dir2img(int element, int action, int direction)
5184 element = GFX_ELEMENT(element);
5185 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5187 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5188 return element_info[element].direction_graphic[action][direction];
5193 static int el_act_dir2crm(int element, int action, int direction)
5195 element = GFX_ELEMENT(element);
5197 if (direction == MV_NONE)
5198 return element_info[element].crumbled[action];
5200 direction = MV_DIR_TO_BIT(direction);
5202 return element_info[element].direction_crumbled[action][direction];
5205 static int el_act_dir2crm(int element, int action, int direction)
5207 element = GFX_ELEMENT(element);
5208 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5210 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5211 return element_info[element].direction_crumbled[action][direction];
5215 int el_act2img(int element, int action)
5217 element = GFX_ELEMENT(element);
5219 return element_info[element].graphic[action];
5222 int el_act2crm(int element, int action)
5224 element = GFX_ELEMENT(element);
5226 return element_info[element].crumbled[action];
5229 int el_dir2img(int element, int direction)
5231 element = GFX_ELEMENT(element);
5233 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5236 int el2baseimg(int element)
5238 return element_info[element].graphic[ACTION_DEFAULT];
5241 int el2img(int element)
5243 element = GFX_ELEMENT(element);
5245 return element_info[element].graphic[ACTION_DEFAULT];
5248 int el2edimg(int element)
5250 element = GFX_ELEMENT(element);
5252 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5255 int el2preimg(int element)
5257 element = GFX_ELEMENT(element);
5259 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5262 int font2baseimg(int font_nr)
5264 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5268 void setCenteredPlayerNr_EM(int centered_player_nr)
5270 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5273 int getCenteredPlayerNr_EM()
5276 if (game.centered_player_nr_next >= 0 &&
5277 !native_em_level.ply[game.centered_player_nr_next]->alive)
5278 game.centered_player_nr_next = game.centered_player_nr;
5281 if (game.centered_player_nr != game.centered_player_nr_next)
5282 game.centered_player_nr = game.centered_player_nr_next;
5284 return game.centered_player_nr;
5287 void setSetCenteredPlayer_EM(boolean set_centered_player)
5289 game.set_centered_player = set_centered_player;
5292 boolean getSetCenteredPlayer_EM()
5294 return game.set_centered_player;
5298 int getNumActivePlayers_EM()
5300 int num_players = 0;
5306 for (i = 0; i < MAX_PLAYERS; i++)
5307 if (tape.player_participates[i])
5314 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5316 int game_frame_delay_value;
5318 game_frame_delay_value =
5319 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5320 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5323 if (tape.playing && tape.warp_forward && !tape.pausing)
5324 game_frame_delay_value = 0;
5326 return game_frame_delay_value;
5330 unsigned int InitRND(long seed)
5332 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5333 return InitEngineRND_EM(seed);
5335 return InitEngineRND(seed);
5338 void InitGraphicInfo_EM(void)
5340 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5341 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5345 int num_em_gfx_errors = 0;
5347 if (graphic_info_em_object[0][0].bitmap == NULL)
5349 /* EM graphics not yet initialized in em_open_all() */
5354 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5357 /* always start with reliable default values */
5358 for (i = 0; i < TILE_MAX; i++)
5360 object_mapping[i].element_rnd = EL_UNKNOWN;
5361 object_mapping[i].is_backside = FALSE;
5362 object_mapping[i].action = ACTION_DEFAULT;
5363 object_mapping[i].direction = MV_NONE;
5366 /* always start with reliable default values */
5367 for (p = 0; p < MAX_PLAYERS; p++)
5369 for (i = 0; i < SPR_MAX; i++)
5371 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5372 player_mapping[p][i].action = ACTION_DEFAULT;
5373 player_mapping[p][i].direction = MV_NONE;
5377 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5379 int e = em_object_mapping_list[i].element_em;
5381 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5382 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5384 if (em_object_mapping_list[i].action != -1)
5385 object_mapping[e].action = em_object_mapping_list[i].action;
5387 if (em_object_mapping_list[i].direction != -1)
5388 object_mapping[e].direction =
5389 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5392 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5394 int a = em_player_mapping_list[i].action_em;
5395 int p = em_player_mapping_list[i].player_nr;
5397 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5399 if (em_player_mapping_list[i].action != -1)
5400 player_mapping[p][a].action = em_player_mapping_list[i].action;
5402 if (em_player_mapping_list[i].direction != -1)
5403 player_mapping[p][a].direction =
5404 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5407 for (i = 0; i < TILE_MAX; i++)
5409 int element = object_mapping[i].element_rnd;
5410 int action = object_mapping[i].action;
5411 int direction = object_mapping[i].direction;
5412 boolean is_backside = object_mapping[i].is_backside;
5413 boolean action_removing = (action == ACTION_DIGGING ||
5414 action == ACTION_SNAPPING ||
5415 action == ACTION_COLLECTING);
5416 boolean action_exploding = ((action == ACTION_EXPLODING ||
5417 action == ACTION_SMASHED_BY_ROCK ||
5418 action == ACTION_SMASHED_BY_SPRING) &&
5419 element != EL_DIAMOND);
5420 boolean action_active = (action == ACTION_ACTIVE);
5421 boolean action_other = (action == ACTION_OTHER);
5423 for (j = 0; j < 8; j++)
5425 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5426 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5428 i == Xdrip_stretch ? element :
5429 i == Xdrip_stretchB ? element :
5430 i == Ydrip_s1 ? element :
5431 i == Ydrip_s1B ? element :
5432 i == Xball_1B ? element :
5433 i == Xball_2 ? element :
5434 i == Xball_2B ? element :
5435 i == Yball_eat ? element :
5436 i == Ykey_1_eat ? element :
5437 i == Ykey_2_eat ? element :
5438 i == Ykey_3_eat ? element :
5439 i == Ykey_4_eat ? element :
5440 i == Ykey_5_eat ? element :
5441 i == Ykey_6_eat ? element :
5442 i == Ykey_7_eat ? element :
5443 i == Ykey_8_eat ? element :
5444 i == Ylenses_eat ? element :
5445 i == Ymagnify_eat ? element :
5446 i == Ygrass_eat ? element :
5447 i == Ydirt_eat ? element :
5448 i == Yemerald_stone ? EL_EMERALD :
5449 i == Ydiamond_stone ? EL_ROCK :
5450 i == Xsand_stonein_1 ? element :
5451 i == Xsand_stonein_2 ? element :
5452 i == Xsand_stonein_3 ? element :
5453 i == Xsand_stonein_4 ? element :
5454 is_backside ? EL_EMPTY :
5455 action_removing ? EL_EMPTY :
5457 int effective_action = (j < 7 ? action :
5458 i == Xdrip_stretch ? action :
5459 i == Xdrip_stretchB ? action :
5460 i == Ydrip_s1 ? action :
5461 i == Ydrip_s1B ? action :
5462 i == Xball_1B ? action :
5463 i == Xball_2 ? action :
5464 i == Xball_2B ? action :
5465 i == Yball_eat ? action :
5466 i == Ykey_1_eat ? action :
5467 i == Ykey_2_eat ? action :
5468 i == Ykey_3_eat ? action :
5469 i == Ykey_4_eat ? action :
5470 i == Ykey_5_eat ? action :
5471 i == Ykey_6_eat ? action :
5472 i == Ykey_7_eat ? action :
5473 i == Ykey_8_eat ? action :
5474 i == Ylenses_eat ? action :
5475 i == Ymagnify_eat ? action :
5476 i == Ygrass_eat ? action :
5477 i == Ydirt_eat ? action :
5478 i == Xsand_stonein_1 ? action :
5479 i == Xsand_stonein_2 ? action :
5480 i == Xsand_stonein_3 ? action :
5481 i == Xsand_stonein_4 ? action :
5482 i == Xsand_stoneout_1 ? action :
5483 i == Xsand_stoneout_2 ? action :
5484 i == Xboom_android ? ACTION_EXPLODING :
5485 action_exploding ? ACTION_EXPLODING :
5486 action_active ? action :
5487 action_other ? action :
5489 int graphic = (el_act_dir2img(effective_element, effective_action,
5491 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5493 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5494 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5495 boolean has_action_graphics = (graphic != base_graphic);
5496 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5497 struct GraphicInfo *g = &graphic_info[graphic];
5498 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5501 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5502 boolean special_animation = (action != ACTION_DEFAULT &&
5503 g->anim_frames == 3 &&
5504 g->anim_delay == 2 &&
5505 g->anim_mode & ANIM_LINEAR);
5506 int sync_frame = (i == Xdrip_stretch ? 7 :
5507 i == Xdrip_stretchB ? 7 :
5508 i == Ydrip_s2 ? j + 8 :
5509 i == Ydrip_s2B ? j + 8 :
5518 i == Xfake_acid_1 ? 0 :
5519 i == Xfake_acid_2 ? 10 :
5520 i == Xfake_acid_3 ? 20 :
5521 i == Xfake_acid_4 ? 30 :
5522 i == Xfake_acid_5 ? 40 :
5523 i == Xfake_acid_6 ? 50 :
5524 i == Xfake_acid_7 ? 60 :
5525 i == Xfake_acid_8 ? 70 :
5527 i == Xball_2B ? j + 8 :
5528 i == Yball_eat ? j + 1 :
5529 i == Ykey_1_eat ? j + 1 :
5530 i == Ykey_2_eat ? j + 1 :
5531 i == Ykey_3_eat ? j + 1 :
5532 i == Ykey_4_eat ? j + 1 :
5533 i == Ykey_5_eat ? j + 1 :
5534 i == Ykey_6_eat ? j + 1 :
5535 i == Ykey_7_eat ? j + 1 :
5536 i == Ykey_8_eat ? j + 1 :
5537 i == Ylenses_eat ? j + 1 :
5538 i == Ymagnify_eat ? j + 1 :
5539 i == Ygrass_eat ? j + 1 :
5540 i == Ydirt_eat ? j + 1 :
5541 i == Xamoeba_1 ? 0 :
5542 i == Xamoeba_2 ? 1 :
5543 i == Xamoeba_3 ? 2 :
5544 i == Xamoeba_4 ? 3 :
5545 i == Xamoeba_5 ? 0 :
5546 i == Xamoeba_6 ? 1 :
5547 i == Xamoeba_7 ? 2 :
5548 i == Xamoeba_8 ? 3 :
5549 i == Xexit_2 ? j + 8 :
5550 i == Xexit_3 ? j + 16 :
5551 i == Xdynamite_1 ? 0 :
5552 i == Xdynamite_2 ? 8 :
5553 i == Xdynamite_3 ? 16 :
5554 i == Xdynamite_4 ? 24 :
5555 i == Xsand_stonein_1 ? j + 1 :
5556 i == Xsand_stonein_2 ? j + 9 :
5557 i == Xsand_stonein_3 ? j + 17 :
5558 i == Xsand_stonein_4 ? j + 25 :
5559 i == Xsand_stoneout_1 && j == 0 ? 0 :
5560 i == Xsand_stoneout_1 && j == 1 ? 0 :
5561 i == Xsand_stoneout_1 && j == 2 ? 1 :
5562 i == Xsand_stoneout_1 && j == 3 ? 2 :
5563 i == Xsand_stoneout_1 && j == 4 ? 2 :
5564 i == Xsand_stoneout_1 && j == 5 ? 3 :
5565 i == Xsand_stoneout_1 && j == 6 ? 4 :
5566 i == Xsand_stoneout_1 && j == 7 ? 4 :
5567 i == Xsand_stoneout_2 && j == 0 ? 5 :
5568 i == Xsand_stoneout_2 && j == 1 ? 6 :
5569 i == Xsand_stoneout_2 && j == 2 ? 7 :
5570 i == Xsand_stoneout_2 && j == 3 ? 8 :
5571 i == Xsand_stoneout_2 && j == 4 ? 9 :
5572 i == Xsand_stoneout_2 && j == 5 ? 11 :
5573 i == Xsand_stoneout_2 && j == 6 ? 13 :
5574 i == Xsand_stoneout_2 && j == 7 ? 15 :
5575 i == Xboom_bug && j == 1 ? 2 :
5576 i == Xboom_bug && j == 2 ? 2 :
5577 i == Xboom_bug && j == 3 ? 4 :
5578 i == Xboom_bug && j == 4 ? 4 :
5579 i == Xboom_bug && j == 5 ? 2 :
5580 i == Xboom_bug && j == 6 ? 2 :
5581 i == Xboom_bug && j == 7 ? 0 :
5582 i == Xboom_bomb && j == 1 ? 2 :
5583 i == Xboom_bomb && j == 2 ? 2 :
5584 i == Xboom_bomb && j == 3 ? 4 :
5585 i == Xboom_bomb && j == 4 ? 4 :
5586 i == Xboom_bomb && j == 5 ? 2 :
5587 i == Xboom_bomb && j == 6 ? 2 :
5588 i == Xboom_bomb && j == 7 ? 0 :
5589 i == Xboom_android && j == 7 ? 6 :
5590 i == Xboom_1 && j == 1 ? 2 :
5591 i == Xboom_1 && j == 2 ? 2 :
5592 i == Xboom_1 && j == 3 ? 4 :
5593 i == Xboom_1 && j == 4 ? 4 :
5594 i == Xboom_1 && j == 5 ? 6 :
5595 i == Xboom_1 && j == 6 ? 6 :
5596 i == Xboom_1 && j == 7 ? 8 :
5597 i == Xboom_2 && j == 0 ? 8 :
5598 i == Xboom_2 && j == 1 ? 8 :
5599 i == Xboom_2 && j == 2 ? 10 :
5600 i == Xboom_2 && j == 3 ? 10 :
5601 i == Xboom_2 && j == 4 ? 10 :
5602 i == Xboom_2 && j == 5 ? 12 :
5603 i == Xboom_2 && j == 6 ? 12 :
5604 i == Xboom_2 && j == 7 ? 12 :
5605 special_animation && j == 4 ? 3 :
5606 effective_action != action ? 0 :
5610 Bitmap *debug_bitmap = g_em->bitmap;
5611 int debug_src_x = g_em->src_x;
5612 int debug_src_y = g_em->src_y;
5615 int frame = getAnimationFrame(g->anim_frames,
5618 g->anim_start_frame,
5621 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5622 g->double_movement && is_backside);
5624 g_em->bitmap = src_bitmap;
5625 g_em->src_x = src_x;
5626 g_em->src_y = src_y;
5627 g_em->src_offset_x = 0;
5628 g_em->src_offset_y = 0;
5629 g_em->dst_offset_x = 0;
5630 g_em->dst_offset_y = 0;
5631 g_em->width = TILEX;
5632 g_em->height = TILEY;
5634 g_em->crumbled_bitmap = NULL;
5635 g_em->crumbled_src_x = 0;
5636 g_em->crumbled_src_y = 0;
5637 g_em->crumbled_border_size = 0;
5639 g_em->has_crumbled_graphics = FALSE;
5640 g_em->preserve_background = FALSE;
5643 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5644 printf("::: empty crumbled: %d [%s], %d, %d\n",
5645 effective_element, element_info[effective_element].token_name,
5646 effective_action, direction);
5649 /* if element can be crumbled, but certain action graphics are just empty
5650 space (like snapping sand with the original R'n'D graphics), do not
5651 treat these empty space graphics as crumbled graphics in EMC engine */
5652 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5654 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5656 g_em->has_crumbled_graphics = TRUE;
5657 g_em->crumbled_bitmap = src_bitmap;
5658 g_em->crumbled_src_x = src_x;
5659 g_em->crumbled_src_y = src_y;
5660 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5664 if (element == EL_ROCK &&
5665 effective_action == ACTION_FILLING)
5666 printf("::: has_action_graphics == %d\n", has_action_graphics);
5669 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5670 effective_action == ACTION_MOVING ||
5671 effective_action == ACTION_PUSHING ||
5672 effective_action == ACTION_EATING)) ||
5673 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5674 effective_action == ACTION_EMPTYING)))
5677 (effective_action == ACTION_FALLING ||
5678 effective_action == ACTION_FILLING ||
5679 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5680 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5681 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5682 int num_steps = (i == Ydrip_s1 ? 16 :
5683 i == Ydrip_s1B ? 16 :
5684 i == Ydrip_s2 ? 16 :
5685 i == Ydrip_s2B ? 16 :
5686 i == Xsand_stonein_1 ? 32 :
5687 i == Xsand_stonein_2 ? 32 :
5688 i == Xsand_stonein_3 ? 32 :
5689 i == Xsand_stonein_4 ? 32 :
5690 i == Xsand_stoneout_1 ? 16 :
5691 i == Xsand_stoneout_2 ? 16 : 8);
5692 int cx = ABS(dx) * (TILEX / num_steps);
5693 int cy = ABS(dy) * (TILEY / num_steps);
5694 int step_frame = (i == Ydrip_s2 ? j + 8 :
5695 i == Ydrip_s2B ? j + 8 :
5696 i == Xsand_stonein_2 ? j + 8 :
5697 i == Xsand_stonein_3 ? j + 16 :
5698 i == Xsand_stonein_4 ? j + 24 :
5699 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5700 int step = (is_backside ? step_frame : num_steps - step_frame);
5702 if (is_backside) /* tile where movement starts */
5704 if (dx < 0 || dy < 0)
5706 g_em->src_offset_x = cx * step;
5707 g_em->src_offset_y = cy * step;
5711 g_em->dst_offset_x = cx * step;
5712 g_em->dst_offset_y = cy * step;
5715 else /* tile where movement ends */
5717 if (dx < 0 || dy < 0)
5719 g_em->dst_offset_x = cx * step;
5720 g_em->dst_offset_y = cy * step;
5724 g_em->src_offset_x = cx * step;
5725 g_em->src_offset_y = cy * step;
5729 g_em->width = TILEX - cx * step;
5730 g_em->height = TILEY - cy * step;
5734 /* create unique graphic identifier to decide if tile must be redrawn */
5735 /* bit 31 - 16 (16 bit): EM style graphic
5736 bit 15 - 12 ( 4 bit): EM style frame
5737 bit 11 - 6 ( 6 bit): graphic width
5738 bit 5 - 0 ( 6 bit): graphic height */
5739 g_em->unique_identifier =
5740 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5742 /* create unique graphic identifier to decide if tile must be redrawn */
5743 /* bit 31 - 16 (16 bit): EM style element
5744 bit 15 - 12 ( 4 bit): EM style frame
5745 bit 11 - 6 ( 6 bit): graphic width
5746 bit 5 - 0 ( 6 bit): graphic height */
5747 g_em->unique_identifier =
5748 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5752 if (effective_element == EL_ROCK)
5753 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5754 effective_action, j, graphic, frame, g_em->unique_identifier);
5760 /* skip check for EMC elements not contained in original EMC artwork */
5761 if (element == EL_EMC_FAKE_ACID)
5765 if (g_em->bitmap != debug_bitmap ||
5766 g_em->src_x != debug_src_x ||
5767 g_em->src_y != debug_src_y ||
5768 g_em->src_offset_x != 0 ||
5769 g_em->src_offset_y != 0 ||
5770 g_em->dst_offset_x != 0 ||
5771 g_em->dst_offset_y != 0 ||
5772 g_em->width != TILEX ||
5773 g_em->height != TILEY)
5775 static int last_i = -1;
5783 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5784 i, element, element_info[element].token_name,
5785 element_action_info[effective_action].suffix, direction);
5787 if (element != effective_element)
5788 printf(" [%d ('%s')]",
5790 element_info[effective_element].token_name);
5794 if (g_em->bitmap != debug_bitmap)
5795 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5796 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5798 if (g_em->src_x != debug_src_x ||
5799 g_em->src_y != debug_src_y)
5800 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5801 j, (is_backside ? 'B' : 'F'),
5802 g_em->src_x, g_em->src_y,
5803 g_em->src_x / 32, g_em->src_y / 32,
5804 debug_src_x, debug_src_y,
5805 debug_src_x / 32, debug_src_y / 32);
5807 if (g_em->src_offset_x != 0 ||
5808 g_em->src_offset_y != 0 ||
5809 g_em->dst_offset_x != 0 ||
5810 g_em->dst_offset_y != 0)
5811 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5813 g_em->src_offset_x, g_em->src_offset_y,
5814 g_em->dst_offset_x, g_em->dst_offset_y);
5816 if (g_em->width != TILEX ||
5817 g_em->height != TILEY)
5818 printf(" %d (%d): size %d,%d should be %d,%d\n",
5820 g_em->width, g_em->height, TILEX, TILEY);
5822 num_em_gfx_errors++;
5829 for (i = 0; i < TILE_MAX; i++)
5831 for (j = 0; j < 8; j++)
5833 int element = object_mapping[i].element_rnd;
5834 int action = object_mapping[i].action;
5835 int direction = object_mapping[i].direction;
5836 boolean is_backside = object_mapping[i].is_backside;
5838 int graphic_action = el_act_dir2img(element, action, direction);
5839 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5841 int graphic_action = element_info[element].graphic[action];
5842 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5845 if ((action == ACTION_SMASHED_BY_ROCK ||
5846 action == ACTION_SMASHED_BY_SPRING ||
5847 action == ACTION_EATING) &&
5848 graphic_action == graphic_default)
5850 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5851 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5852 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5853 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5856 /* no separate animation for "smashed by rock" -- use rock instead */
5857 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5858 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5860 g_em->bitmap = g_xx->bitmap;
5861 g_em->src_x = g_xx->src_x;
5862 g_em->src_y = g_xx->src_y;
5863 g_em->src_offset_x = g_xx->src_offset_x;
5864 g_em->src_offset_y = g_xx->src_offset_y;
5865 g_em->dst_offset_x = g_xx->dst_offset_x;
5866 g_em->dst_offset_y = g_xx->dst_offset_y;
5867 g_em->width = g_xx->width;
5868 g_em->height = g_xx->height;
5870 g_em->unique_identifier = g_xx->unique_identifier;
5874 g_em->preserve_background = TRUE;
5879 for (p = 0; p < MAX_PLAYERS; p++)
5881 for (i = 0; i < SPR_MAX; i++)
5883 int element = player_mapping[p][i].element_rnd;
5884 int action = player_mapping[p][i].action;
5885 int direction = player_mapping[p][i].direction;
5887 for (j = 0; j < 8; j++)
5889 int effective_element = element;
5890 int effective_action = action;
5891 int graphic = (direction == MV_NONE ?
5892 el_act2img(effective_element, effective_action) :
5893 el_act_dir2img(effective_element, effective_action,
5895 struct GraphicInfo *g = &graphic_info[graphic];
5896 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5902 Bitmap *debug_bitmap = g_em->bitmap;
5903 int debug_src_x = g_em->src_x;
5904 int debug_src_y = g_em->src_y;
5907 int frame = getAnimationFrame(g->anim_frames,
5910 g->anim_start_frame,
5913 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5915 g_em->bitmap = src_bitmap;
5916 g_em->src_x = src_x;
5917 g_em->src_y = src_y;
5918 g_em->src_offset_x = 0;
5919 g_em->src_offset_y = 0;
5920 g_em->dst_offset_x = 0;
5921 g_em->dst_offset_y = 0;
5922 g_em->width = TILEX;
5923 g_em->height = TILEY;
5928 /* skip check for EMC elements not contained in original EMC artwork */
5929 if (element == EL_PLAYER_3 ||
5930 element == EL_PLAYER_4)
5934 if (g_em->bitmap != debug_bitmap ||
5935 g_em->src_x != debug_src_x ||
5936 g_em->src_y != debug_src_y)
5938 static int last_i = -1;
5946 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5947 p, i, element, element_info[element].token_name,
5948 element_action_info[effective_action].suffix, direction);
5950 if (element != effective_element)
5951 printf(" [%d ('%s')]",
5953 element_info[effective_element].token_name);
5957 if (g_em->bitmap != debug_bitmap)
5958 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5959 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5961 if (g_em->src_x != debug_src_x ||
5962 g_em->src_y != debug_src_y)
5963 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5965 g_em->src_x, g_em->src_y,
5966 g_em->src_x / 32, g_em->src_y / 32,
5967 debug_src_x, debug_src_y,
5968 debug_src_x / 32, debug_src_y / 32);
5970 num_em_gfx_errors++;
5980 printf("::: [%d errors found]\n", num_em_gfx_errors);