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 SDL_Surface *surface_screen = backbuffer->surface;
424 SDL_Surface *surface_screen_copy = NULL;
425 SDL_Surface *surface_black = NULL;
426 SDL_Surface *surface_cross; /* initialized later */
427 boolean fade_reverse; /* initialized later */
428 unsigned int flags = SDL_SRCALPHA;
429 unsigned int time_last, time_current;
433 /* use same surface type as screen surface */
434 if ((surface_screen->flags & SDL_HWSURFACE))
435 flags |= SDL_HWSURFACE;
437 flags |= SDL_SWSURFACE;
439 /* create surface for copy of screen buffer */
440 if ((surface_screen_copy =
441 SDL_CreateRGBSurface(flags,
444 surface_screen->format->BitsPerPixel,
445 surface_screen->format->Rmask,
446 surface_screen->format->Gmask,
447 surface_screen->format->Bmask,
448 surface_screen->format->Amask)) == NULL)
449 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
451 SDL_BlitSurface(surface_screen, NULL, surface_screen_copy, NULL);
453 /* create black surface for fading from/to black */
455 SDL_CreateRGBSurface(flags,
458 surface_screen->format->BitsPerPixel,
459 surface_screen->format->Rmask,
460 surface_screen->format->Gmask,
461 surface_screen->format->Bmask,
462 surface_screen->format->Amask)) == NULL)
463 Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
465 SDL_FillRect(surface_black, NULL, SDL_MapRGB(surface_screen->format, 0,0,0));
467 fade_reverse = (fade_mode == FADE_MODE_FADE_IN ? TRUE : FALSE);
468 surface_cross = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_cross->surface :
471 time_current = SDL_GetTicks();
473 for (alpha = 0.0; alpha < 255.0;)
475 time_last = time_current;
476 time_current = SDL_GetTicks();
477 alpha += 255 * ((float)(time_current - time_last) / fade_ms);
478 alpha_final = (int)(fade_reverse ? 255.0 - alpha : alpha);
479 alpha_final = MIN(MAX(0, alpha_final), 255);
481 /* draw existing image to screen buffer */
482 SDL_BlitSurface(surface_screen_copy, NULL, surface_screen, NULL);
484 /* draw new image to screen buffer using alpha blending */
485 SDL_SetAlpha(surface_cross, SDL_SRCALPHA, alpha_final);
486 SDL_BlitSurface(surface_cross, NULL, surface_screen, NULL);
488 /* draw screen buffer to visible display */
489 SDL_Flip(surface_screen);
492 SDL_FreeSurface(surface_screen_copy);
493 SDL_FreeSurface(surface_black);
495 redraw_mask = REDRAW_NONE;
498 void FadeIn(int fade_ms)
501 FadeExt(NULL, fade_ms, FADE_MODE_FADE_IN);
507 void FadeOut(int fade_ms)
510 FadeExt(NULL, fade_ms, FADE_MODE_FADE_OUT);
516 void FadeCross(Bitmap *bitmap, int fade_ms)
519 FadeExt(bitmap, fade_ms, FADE_MODE_CROSSFADE);
525 void SetMainBackgroundImageIfDefined(int graphic)
527 if (graphic_info[graphic].bitmap)
528 SetMainBackgroundImage(graphic);
531 void SetMainBackgroundImage(int graphic)
533 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
534 graphic_info[graphic].bitmap ?
535 graphic_info[graphic].bitmap :
536 graphic_info[IMG_BACKGROUND].bitmap);
539 void SetDoorBackgroundImage(int graphic)
541 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
542 graphic_info[graphic].bitmap ?
543 graphic_info[graphic].bitmap :
544 graphic_info[IMG_BACKGROUND].bitmap);
547 void DrawBackground(int dst_x, int dst_y, int width, int height)
549 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
551 redraw_mask |= REDRAW_FIELD;
556 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
558 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
560 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
561 SetDrawtoField(DRAW_BUFFERED);
564 SetDrawtoField(DRAW_BACKBUFFER);
566 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
568 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
569 SetDrawtoField(DRAW_DIRECT);
573 void MarkTileDirty(int x, int y)
575 int xx = redraw_x1 + x;
576 int yy = redraw_y1 + y;
581 redraw[xx][yy] = TRUE;
582 redraw_mask |= REDRAW_TILES;
585 void SetBorderElement()
589 BorderElement = EL_EMPTY;
591 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
593 for (x = 0; x < lev_fieldx; x++)
595 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
596 BorderElement = EL_STEELWALL;
598 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
604 void SetRandomAnimationValue(int x, int y)
606 gfx.anim_random_frame = GfxRandom[x][y];
609 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
611 /* animation synchronized with global frame counter, not move position */
612 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
613 sync_frame = FrameCounter;
616 if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
622 printf("::: FOO!\n");
626 return getAnimationFrame(graphic_info[graphic].anim_frames,
627 graphic_info[graphic].anim_delay,
628 graphic_info[graphic].anim_mode,
629 graphic_info[graphic].anim_start_frame,
633 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
634 int *x, int *y, boolean get_backside)
636 struct GraphicInfo *g = &graphic_info[graphic];
637 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
638 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
642 if (g->offset_y == 0) /* frames are ordered horizontally */
644 int max_width = g->anim_frames_per_line * g->width;
645 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
647 *x = pos % max_width;
648 *y = src_y % g->height + pos / max_width * g->height;
650 else if (g->offset_x == 0) /* frames are ordered vertically */
652 int max_height = g->anim_frames_per_line * g->height;
653 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
655 *x = src_x % g->width + pos / max_height * g->width;
656 *y = pos % max_height;
658 else /* frames are ordered diagonally */
660 *x = src_x + frame * g->offset_x;
661 *y = src_y + frame * g->offset_y;
665 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
667 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
670 void DrawGraphic(int x, int y, int graphic, int frame)
673 if (!IN_SCR_FIELD(x, y))
675 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
676 printf("DrawGraphic(): This should never happen!\n");
681 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
685 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
691 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
692 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
695 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
698 if (!IN_SCR_FIELD(x, y))
700 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
701 printf("DrawGraphicThruMask(): This should never happen!\n");
706 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
711 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
717 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
719 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
720 dst_x - src_x, dst_y - src_y);
721 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
724 void DrawMiniGraphic(int x, int y, int graphic)
726 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
727 MarkTileDirty(x / 2, y / 2);
730 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
732 struct GraphicInfo *g = &graphic_info[graphic];
734 int mini_starty = g->bitmap->height * 2 / 3;
737 *x = mini_startx + g->src_x / 2;
738 *y = mini_starty + g->src_y / 2;
741 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
746 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
747 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
750 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
751 int graphic, int frame,
752 int cut_mode, int mask_mode)
757 int width = TILEX, height = TILEY;
760 if (dx || dy) /* shifted graphic */
762 if (x < BX1) /* object enters playfield from the left */
769 else if (x > BX2) /* object enters playfield from the right */
775 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
781 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
783 else if (dx) /* general horizontal movement */
784 MarkTileDirty(x + SIGN(dx), y);
786 if (y < BY1) /* object enters playfield from the top */
788 if (cut_mode==CUT_BELOW) /* object completely above top border */
796 else if (y > BY2) /* object enters playfield from the bottom */
802 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
808 else if (dy > 0 && cut_mode == CUT_ABOVE)
810 if (y == BY2) /* object completely above bottom border */
816 MarkTileDirty(x, y + 1);
817 } /* object leaves playfield to the bottom */
818 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
820 else if (dy) /* general vertical movement */
821 MarkTileDirty(x, y + SIGN(dy));
825 if (!IN_SCR_FIELD(x, y))
827 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
828 printf("DrawGraphicShifted(): This should never happen!\n");
833 if (width > 0 && height > 0)
835 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
840 dst_x = FX + x * TILEX + dx;
841 dst_y = FY + y * TILEY + dy;
843 if (mask_mode == USE_MASKING)
845 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
846 dst_x - src_x, dst_y - src_y);
847 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
851 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
858 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
859 int graphic, int frame,
860 int cut_mode, int mask_mode)
865 int width = TILEX, height = TILEY;
868 int x2 = x + SIGN(dx);
869 int y2 = y + SIGN(dy);
870 int anim_frames = graphic_info[graphic].anim_frames;
871 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
872 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
873 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
875 /* re-calculate animation frame for two-tile movement animation */
876 frame = getGraphicAnimationFrame(graphic, sync_frame);
878 /* check if movement start graphic inside screen area and should be drawn */
879 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
881 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
883 dst_x = FX + x1 * TILEX;
884 dst_y = FY + y1 * TILEY;
886 if (mask_mode == USE_MASKING)
888 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
889 dst_x - src_x, dst_y - src_y);
890 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
894 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
897 MarkTileDirty(x1, y1);
900 /* check if movement end graphic inside screen area and should be drawn */
901 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
903 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
905 dst_x = FX + x2 * TILEX;
906 dst_y = FY + y2 * TILEY;
908 if (mask_mode == USE_MASKING)
910 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
911 dst_x - src_x, dst_y - src_y);
912 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
916 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
919 MarkTileDirty(x2, y2);
923 static void DrawGraphicShifted(int x, int y, int dx, int dy,
924 int graphic, int frame,
925 int cut_mode, int mask_mode)
929 DrawGraphic(x, y, graphic, frame);
934 if (graphic_info[graphic].double_movement) /* EM style movement images */
935 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
937 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
940 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
941 int frame, int cut_mode)
943 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
946 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
947 int cut_mode, int mask_mode)
949 int lx = LEVELX(x), ly = LEVELY(y);
953 if (IN_LEV_FIELD(lx, ly))
955 SetRandomAnimationValue(lx, ly);
957 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
958 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
960 /* do not use double (EM style) movement graphic when not moving */
961 if (graphic_info[graphic].double_movement && !dx && !dy)
963 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
964 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
967 else /* border element */
969 graphic = el2img(element);
970 frame = getGraphicAnimationFrame(graphic, -1);
973 if (element == EL_EXPANDABLE_WALL)
975 boolean left_stopped = FALSE, right_stopped = FALSE;
977 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
979 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
980 right_stopped = TRUE;
982 if (left_stopped && right_stopped)
984 else if (left_stopped)
986 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
987 frame = graphic_info[graphic].anim_frames - 1;
989 else if (right_stopped)
991 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
992 frame = graphic_info[graphic].anim_frames - 1;
997 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
998 else if (mask_mode == USE_MASKING)
999 DrawGraphicThruMask(x, y, graphic, frame);
1001 DrawGraphic(x, y, graphic, frame);
1004 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1005 int cut_mode, int mask_mode)
1007 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1008 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1009 cut_mode, mask_mode);
1012 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1015 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1018 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1021 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1024 void DrawLevelElementThruMask(int x, int y, int element)
1026 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1029 void DrawLevelFieldThruMask(int x, int y)
1031 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1034 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1038 int sx = SCREENX(x), sy = SCREENY(y);
1040 int width, height, cx, cy, i;
1041 int crumbled_border_size = graphic_info[graphic].border_size;
1042 static int xy[4][2] =
1050 if (!IN_LEV_FIELD(x, y))
1053 element = TILE_GFX_ELEMENT(x, y);
1055 /* crumble field itself */
1056 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1058 if (!IN_SCR_FIELD(sx, sy))
1061 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1063 for (i = 0; i < 4; i++)
1065 int xx = x + xy[i][0];
1066 int yy = y + xy[i][1];
1068 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1071 /* check if neighbour field is of same type */
1072 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1075 if (i == 1 || i == 2)
1077 width = crumbled_border_size;
1079 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1085 height = crumbled_border_size;
1087 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1090 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1091 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1094 MarkTileDirty(sx, sy);
1096 else /* crumble neighbour fields */
1098 for (i = 0; i < 4; i++)
1100 int xx = x + xy[i][0];
1101 int yy = y + xy[i][1];
1102 int sxx = sx + xy[i][0];
1103 int syy = sy + xy[i][1];
1106 if (!IN_LEV_FIELD(xx, yy) ||
1107 !IN_SCR_FIELD(sxx, syy) ||
1112 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1116 element = TILE_GFX_ELEMENT(xx, yy);
1118 if (!GFX_CRUMBLED(element))
1121 if (!IN_LEV_FIELD(xx, yy) ||
1122 !IN_SCR_FIELD(sxx, syy) ||
1123 !GFX_CRUMBLED(Feld[xx][yy]) ||
1129 graphic = el_act2crm(element, ACTION_DEFAULT);
1131 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1133 crumbled_border_size = graphic_info[graphic].border_size;
1135 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1137 if (i == 1 || i == 2)
1139 width = crumbled_border_size;
1141 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1147 height = crumbled_border_size;
1149 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1152 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1153 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1155 MarkTileDirty(sxx, syy);
1160 void DrawLevelFieldCrumbledSand(int x, int y)
1164 if (!IN_LEV_FIELD(x, y))
1168 /* !!! CHECK THIS !!! */
1171 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1172 GFX_CRUMBLED(GfxElement[x][y]))
1175 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1176 GfxElement[x][y] != EL_UNDEFINED &&
1177 GFX_CRUMBLED(GfxElement[x][y]))
1179 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1186 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1188 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1191 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1194 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1197 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1198 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1199 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1200 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1201 int sx = SCREENX(x), sy = SCREENY(y);
1203 DrawGraphic(sx, sy, graphic1, frame1);
1204 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1207 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1209 int sx = SCREENX(x), sy = SCREENY(y);
1210 static int xy[4][2] =
1219 for (i = 0; i < 4; i++)
1221 int xx = x + xy[i][0];
1222 int yy = y + xy[i][1];
1223 int sxx = sx + xy[i][0];
1224 int syy = sy + xy[i][1];
1226 if (!IN_LEV_FIELD(xx, yy) ||
1227 !IN_SCR_FIELD(sxx, syy) ||
1228 !GFX_CRUMBLED(Feld[xx][yy]) ||
1232 DrawLevelField(xx, yy);
1236 static int getBorderElement(int x, int y)
1240 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1241 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1242 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1243 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1244 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1245 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1246 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1248 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1249 int steel_position = (x == -1 && y == -1 ? 0 :
1250 x == lev_fieldx && y == -1 ? 1 :
1251 x == -1 && y == lev_fieldy ? 2 :
1252 x == lev_fieldx && y == lev_fieldy ? 3 :
1253 x == -1 || x == lev_fieldx ? 4 :
1254 y == -1 || y == lev_fieldy ? 5 : 6);
1256 return border[steel_position][steel_type];
1259 void DrawScreenElement(int x, int y, int element)
1261 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1262 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1265 void DrawLevelElement(int x, int y, int element)
1267 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1268 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1271 void DrawScreenField(int x, int y)
1273 int lx = LEVELX(x), ly = LEVELY(y);
1274 int element, content;
1276 if (!IN_LEV_FIELD(lx, ly))
1278 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1281 element = getBorderElement(lx, ly);
1283 DrawScreenElement(x, y, element);
1287 element = Feld[lx][ly];
1288 content = Store[lx][ly];
1290 if (IS_MOVING(lx, ly))
1292 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1293 boolean cut_mode = NO_CUTTING;
1295 if (element == EL_QUICKSAND_EMPTYING ||
1296 element == EL_MAGIC_WALL_EMPTYING ||
1297 element == EL_BD_MAGIC_WALL_EMPTYING ||
1298 element == EL_AMOEBA_DROPPING)
1299 cut_mode = CUT_ABOVE;
1300 else if (element == EL_QUICKSAND_FILLING ||
1301 element == EL_MAGIC_WALL_FILLING ||
1302 element == EL_BD_MAGIC_WALL_FILLING)
1303 cut_mode = CUT_BELOW;
1305 if (cut_mode == CUT_ABOVE)
1306 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1308 DrawScreenElement(x, y, EL_EMPTY);
1311 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1312 else if (cut_mode == NO_CUTTING)
1313 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1315 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1317 if (content == EL_ACID)
1319 int dir = MovDir[lx][ly];
1320 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1321 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1323 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1326 else if (IS_BLOCKED(lx, ly))
1331 boolean cut_mode = NO_CUTTING;
1332 int element_old, content_old;
1334 Blocked2Moving(lx, ly, &oldx, &oldy);
1337 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1338 MovDir[oldx][oldy] == MV_RIGHT);
1340 element_old = Feld[oldx][oldy];
1341 content_old = Store[oldx][oldy];
1343 if (element_old == EL_QUICKSAND_EMPTYING ||
1344 element_old == EL_MAGIC_WALL_EMPTYING ||
1345 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1346 element_old == EL_AMOEBA_DROPPING)
1347 cut_mode = CUT_ABOVE;
1349 DrawScreenElement(x, y, EL_EMPTY);
1352 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1354 else if (cut_mode == NO_CUTTING)
1355 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1358 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1361 else if (IS_DRAWABLE(element))
1362 DrawScreenElement(x, y, element);
1364 DrawScreenElement(x, y, EL_EMPTY);
1367 void DrawLevelField(int x, int y)
1369 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1370 DrawScreenField(SCREENX(x), SCREENY(y));
1371 else if (IS_MOVING(x, y))
1375 Moving2Blocked(x, y, &newx, &newy);
1376 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1377 DrawScreenField(SCREENX(newx), SCREENY(newy));
1379 else if (IS_BLOCKED(x, y))
1383 Blocked2Moving(x, y, &oldx, &oldy);
1384 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1385 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1389 void DrawMiniElement(int x, int y, int element)
1393 graphic = el2edimg(element);
1394 DrawMiniGraphic(x, y, graphic);
1397 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1399 int x = sx + scroll_x, y = sy + scroll_y;
1401 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1402 DrawMiniElement(sx, sy, EL_EMPTY);
1403 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1404 DrawMiniElement(sx, sy, Feld[x][y]);
1406 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1409 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1410 int x, int y, int xsize, int ysize, int font_nr)
1412 int font_width = getFontWidth(font_nr);
1413 int font_height = getFontHeight(font_nr);
1414 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1417 int dst_x = SX + startx + x * font_width;
1418 int dst_y = SY + starty + y * font_height;
1419 int width = graphic_info[graphic].width;
1420 int height = graphic_info[graphic].height;
1421 int inner_width = MAX(width - 2 * font_width, font_width);
1422 int inner_height = MAX(height - 2 * font_height, font_height);
1423 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1424 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1425 boolean draw_masked = graphic_info[graphic].draw_masked;
1427 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1429 if (src_bitmap == NULL || width < font_width || height < font_height)
1431 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1435 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1436 inner_sx + (x - 1) * font_width % inner_width);
1437 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1438 inner_sy + (y - 1) * font_height % inner_height);
1442 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1443 dst_x - src_x, dst_y - src_y);
1444 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1448 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1452 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1454 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1455 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1456 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1457 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1458 boolean no_delay = (tape.warp_forward);
1459 unsigned long anim_delay = 0;
1460 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1461 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1462 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1463 int font_width = getFontWidth(font_nr);
1464 int font_height = getFontHeight(font_nr);
1465 int max_xsize = level.envelope_xsize[envelope_nr];
1466 int max_ysize = level.envelope_ysize[envelope_nr];
1467 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1468 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1469 int xend = max_xsize;
1470 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1471 int xstep = (xstart < xend ? 1 : 0);
1472 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1475 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1477 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1478 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1479 int sx = (SXSIZE - xsize * font_width) / 2;
1480 int sy = (SYSIZE - ysize * font_height) / 2;
1483 SetDrawtoField(DRAW_BUFFERED);
1485 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1487 SetDrawtoField(DRAW_BACKBUFFER);
1489 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1490 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1492 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1493 level.envelope_text[envelope_nr], font_nr, max_xsize,
1494 xsize - 2, ysize - 2, mask_mode);
1496 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1499 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1503 void ShowEnvelope(int envelope_nr)
1505 int element = EL_ENVELOPE_1 + envelope_nr;
1506 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1507 int sound_opening = element_info[element].sound[ACTION_OPENING];
1508 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1509 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1510 boolean no_delay = (tape.warp_forward);
1511 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1512 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1513 int anim_mode = graphic_info[graphic].anim_mode;
1514 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1515 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1517 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1519 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1521 if (anim_mode == ANIM_DEFAULT)
1522 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1524 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1527 Delay(wait_delay_value);
1529 WaitForEventToContinue();
1531 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1533 if (anim_mode != ANIM_NONE)
1534 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1536 if (anim_mode == ANIM_DEFAULT)
1537 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1539 game.envelope_active = FALSE;
1541 SetDrawtoField(DRAW_BUFFERED);
1543 redraw_mask |= REDRAW_FIELD;
1547 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1549 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1550 int mini_startx = src_bitmap->width * 3 / 4;
1551 int mini_starty = src_bitmap->height * 2 / 3;
1552 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1553 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1555 *bitmap = src_bitmap;
1560 void DrawMicroElement(int xpos, int ypos, int element)
1564 int graphic = el2preimg(element);
1566 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1567 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1575 SetDrawBackgroundMask(REDRAW_NONE);
1578 for (x = BX1; x <= BX2; x++)
1579 for (y = BY1; y <= BY2; y++)
1580 DrawScreenField(x, y);
1582 redraw_mask |= REDRAW_FIELD;
1585 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1589 for (x = 0; x < size_x; x++)
1590 for (y = 0; y < size_y; y++)
1591 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1593 redraw_mask |= REDRAW_FIELD;
1596 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1600 DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
1602 if (lev_fieldx < STD_LEV_FIELDX)
1603 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1604 if (lev_fieldy < STD_LEV_FIELDY)
1605 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1607 xpos += MICRO_TILEX;
1608 ypos += MICRO_TILEY;
1610 for (x = -1; x <= STD_LEV_FIELDX; x++)
1612 for (y = -1; y <= STD_LEV_FIELDY; y++)
1614 int lx = from_x + x, ly = from_y + y;
1616 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1617 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1618 level.field[lx][ly]);
1619 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1620 && BorderElement != EL_EMPTY)
1621 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1622 getBorderElement(lx, ly));
1626 redraw_mask |= REDRAW_MICROLEVEL;
1629 #define MICROLABEL_EMPTY 0
1630 #define MICROLABEL_LEVEL_NAME 1
1631 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1632 #define MICROLABEL_LEVEL_AUTHOR 3
1633 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1634 #define MICROLABEL_IMPORTED_FROM 5
1635 #define MICROLABEL_IMPORTED_BY_HEAD 6
1636 #define MICROLABEL_IMPORTED_BY 7
1638 static void DrawMicroLevelLabelExt(int mode)
1640 char label_text[MAX_OUTPUT_LINESIZE + 1];
1641 int max_len_label_text;
1642 int font_nr = FONT_TEXT_2;
1645 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1646 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1647 mode == MICROLABEL_IMPORTED_BY_HEAD)
1648 font_nr = FONT_TEXT_3;
1650 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1652 for (i = 0; i < max_len_label_text; i++)
1653 label_text[i] = ' ';
1654 label_text[max_len_label_text] = '\0';
1656 if (strlen(label_text) > 0)
1658 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1659 int lypos = MICROLABEL2_YPOS;
1661 DrawText(lxpos, lypos, label_text, font_nr);
1665 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1666 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1667 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1668 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1669 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1670 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1671 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1672 max_len_label_text);
1673 label_text[max_len_label_text] = '\0';
1675 if (strlen(label_text) > 0)
1677 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1678 int lypos = MICROLABEL2_YPOS;
1680 DrawText(lxpos, lypos, label_text, font_nr);
1683 redraw_mask |= REDRAW_MICROLEVEL;
1686 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1688 static unsigned long scroll_delay = 0;
1689 static unsigned long label_delay = 0;
1690 static int from_x, from_y, scroll_direction;
1691 static int label_state, label_counter;
1692 int last_game_status = game_status; /* save current game status */
1694 /* force PREVIEW font on preview level */
1695 game_status = GAME_MODE_PSEUDO_PREVIEW;
1699 from_x = from_y = 0;
1700 scroll_direction = MV_RIGHT;
1704 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1705 DrawMicroLevelLabelExt(label_state);
1707 /* initialize delay counters */
1708 DelayReached(&scroll_delay, 0);
1709 DelayReached(&label_delay, 0);
1711 if (leveldir_current->name)
1713 char label_text[MAX_OUTPUT_LINESIZE + 1];
1714 int font_nr = FONT_TEXT_1;
1715 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1718 strncpy(label_text, leveldir_current->name, max_len_label_text);
1719 label_text[max_len_label_text] = '\0';
1721 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1722 lypos = SY + MICROLABEL1_YPOS;
1724 DrawText(lxpos, lypos, label_text, font_nr);
1727 game_status = last_game_status; /* restore current game status */
1732 /* scroll micro level, if needed */
1733 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1734 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1736 switch (scroll_direction)
1742 scroll_direction = MV_UP;
1746 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1749 scroll_direction = MV_DOWN;
1756 scroll_direction = MV_RIGHT;
1760 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1763 scroll_direction = MV_LEFT;
1770 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1773 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1774 /* redraw micro level label, if needed */
1775 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1776 !strEqual(level.author, ANONYMOUS_NAME) &&
1777 !strEqual(level.author, leveldir_current->name) &&
1778 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1780 int max_label_counter = 23;
1782 if (leveldir_current->imported_from != NULL &&
1783 strlen(leveldir_current->imported_from) > 0)
1784 max_label_counter += 14;
1785 if (leveldir_current->imported_by != NULL &&
1786 strlen(leveldir_current->imported_by) > 0)
1787 max_label_counter += 14;
1789 label_counter = (label_counter + 1) % max_label_counter;
1790 label_state = (label_counter >= 0 && label_counter <= 7 ?
1791 MICROLABEL_LEVEL_NAME :
1792 label_counter >= 9 && label_counter <= 12 ?
1793 MICROLABEL_LEVEL_AUTHOR_HEAD :
1794 label_counter >= 14 && label_counter <= 21 ?
1795 MICROLABEL_LEVEL_AUTHOR :
1796 label_counter >= 23 && label_counter <= 26 ?
1797 MICROLABEL_IMPORTED_FROM_HEAD :
1798 label_counter >= 28 && label_counter <= 35 ?
1799 MICROLABEL_IMPORTED_FROM :
1800 label_counter >= 37 && label_counter <= 40 ?
1801 MICROLABEL_IMPORTED_BY_HEAD :
1802 label_counter >= 42 && label_counter <= 49 ?
1803 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1805 if (leveldir_current->imported_from == NULL &&
1806 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1807 label_state == MICROLABEL_IMPORTED_FROM))
1808 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1809 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1811 DrawMicroLevelLabelExt(label_state);
1814 game_status = last_game_status; /* restore current game status */
1817 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1818 int graphic, int sync_frame, int mask_mode)
1820 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1822 if (mask_mode == USE_MASKING)
1823 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1825 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1828 inline void DrawGraphicAnimation(int x, int y, int graphic)
1830 int lx = LEVELX(x), ly = LEVELY(y);
1832 if (!IN_SCR_FIELD(x, y))
1835 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1836 graphic, GfxFrame[lx][ly], NO_MASKING);
1837 MarkTileDirty(x, y);
1840 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1842 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1845 void DrawLevelElementAnimation(int x, int y, int element)
1847 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1849 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1852 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1854 int sx = SCREENX(x), sy = SCREENY(y);
1856 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1859 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1862 DrawGraphicAnimation(sx, sy, graphic);
1865 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1866 DrawLevelFieldCrumbledSand(x, y);
1868 if (GFX_CRUMBLED(Feld[x][y]))
1869 DrawLevelFieldCrumbledSand(x, y);
1873 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1875 int sx = SCREENX(x), sy = SCREENY(y);
1878 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1881 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1883 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1886 DrawGraphicAnimation(sx, sy, graphic);
1888 if (GFX_CRUMBLED(element))
1889 DrawLevelFieldCrumbledSand(x, y);
1892 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1894 if (player->use_murphy)
1896 /* this works only because currently only one player can be "murphy" ... */
1897 static int last_horizontal_dir = MV_LEFT;
1898 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1900 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1901 last_horizontal_dir = move_dir;
1903 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1905 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1907 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1913 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1916 static boolean equalGraphics(int graphic1, int graphic2)
1918 struct GraphicInfo *g1 = &graphic_info[graphic1];
1919 struct GraphicInfo *g2 = &graphic_info[graphic2];
1921 return (g1->bitmap == g2->bitmap &&
1922 g1->src_x == g2->src_x &&
1923 g1->src_y == g2->src_y &&
1924 g1->anim_frames == g2->anim_frames &&
1925 g1->anim_delay == g2->anim_delay &&
1926 g1->anim_mode == g2->anim_mode);
1929 void DrawAllPlayers()
1933 for (i = 0; i < MAX_PLAYERS; i++)
1934 if (stored_player[i].active)
1935 DrawPlayer(&stored_player[i]);
1938 void DrawPlayerField(int x, int y)
1940 if (!IS_PLAYER(x, y))
1943 DrawPlayer(PLAYERINFO(x, y));
1946 void DrawPlayer(struct PlayerInfo *player)
1948 int jx = player->jx;
1949 int jy = player->jy;
1950 int move_dir = player->MovDir;
1951 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1952 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1953 int last_jx = (player->is_moving ? jx - dx : jx);
1954 int last_jy = (player->is_moving ? jy - dy : jy);
1955 int next_jx = jx + dx;
1956 int next_jy = jy + dy;
1957 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1958 boolean player_is_opaque = FALSE;
1959 int sx = SCREENX(jx), sy = SCREENY(jy);
1960 int sxx = 0, syy = 0;
1961 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1963 int action = ACTION_DEFAULT;
1964 int last_player_graphic = getPlayerGraphic(player, move_dir);
1965 int last_player_frame = player->Frame;
1969 /* GfxElement[][] is set to the element the player is digging or collecting;
1970 remove also for off-screen player if the player is not moving anymore */
1971 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1972 GfxElement[jx][jy] = EL_UNDEFINED;
1975 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1979 if (!IN_LEV_FIELD(jx, jy))
1981 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1982 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1983 printf("DrawPlayerField(): This should never happen!\n");
1988 if (element == EL_EXPLOSION)
1991 action = (player->is_pushing ? ACTION_PUSHING :
1992 player->is_digging ? ACTION_DIGGING :
1993 player->is_collecting ? ACTION_COLLECTING :
1994 player->is_moving ? ACTION_MOVING :
1995 player->is_snapping ? ACTION_SNAPPING :
1996 player->is_dropping ? ACTION_DROPPING :
1997 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2000 if (player->is_waiting)
2001 move_dir = player->dir_waiting;
2004 InitPlayerGfxAnimation(player, action, move_dir);
2006 /* ----------------------------------------------------------------------- */
2007 /* draw things in the field the player is leaving, if needed */
2008 /* ----------------------------------------------------------------------- */
2010 if (player->is_moving)
2012 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2014 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2016 if (last_element == EL_DYNAMITE_ACTIVE ||
2017 last_element == EL_EM_DYNAMITE_ACTIVE ||
2018 last_element == EL_SP_DISK_RED_ACTIVE)
2019 DrawDynamite(last_jx, last_jy);
2021 DrawLevelFieldThruMask(last_jx, last_jy);
2023 else 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 DrawLevelField(last_jx, last_jy);
2030 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2031 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2034 if (!IN_SCR_FIELD(sx, sy))
2037 if (setup.direct_draw)
2038 SetDrawtoField(DRAW_BUFFERED);
2040 /* ----------------------------------------------------------------------- */
2041 /* draw things behind the player, if needed */
2042 /* ----------------------------------------------------------------------- */
2045 DrawLevelElement(jx, jy, Back[jx][jy]);
2046 else if (IS_ACTIVE_BOMB(element))
2047 DrawLevelElement(jx, jy, EL_EMPTY);
2050 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2052 int old_element = GfxElement[jx][jy];
2053 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2054 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2056 if (GFX_CRUMBLED(old_element))
2057 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2059 DrawGraphic(sx, sy, old_graphic, frame);
2061 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2062 player_is_opaque = TRUE;
2066 GfxElement[jx][jy] = EL_UNDEFINED;
2068 /* make sure that pushed elements are drawn with correct frame rate */
2069 if (player->is_pushing && player->is_moving)
2070 GfxFrame[jx][jy] = player->StepFrame;
2072 DrawLevelField(jx, jy);
2076 /* ----------------------------------------------------------------------- */
2077 /* draw player himself */
2078 /* ----------------------------------------------------------------------- */
2080 graphic = getPlayerGraphic(player, move_dir);
2082 /* in the case of changed player action or direction, prevent the current
2083 animation frame from being restarted for identical animations */
2084 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2085 player->Frame = last_player_frame;
2087 frame = getGraphicAnimationFrame(graphic, player->Frame);
2091 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2092 sxx = player->GfxPos;
2094 syy = player->GfxPos;
2097 if (!setup.soft_scrolling && ScreenMovPos)
2100 if (player_is_opaque)
2101 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2103 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2105 if (SHIELD_ON(player))
2107 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2108 IMG_SHIELD_NORMAL_ACTIVE);
2109 int frame = getGraphicAnimationFrame(graphic, -1);
2111 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2114 /* ----------------------------------------------------------------------- */
2115 /* draw things the player is pushing, if needed */
2116 /* ----------------------------------------------------------------------- */
2119 printf("::: %d, %d [%d, %d] [%d]\n",
2120 player->is_pushing, player_is_moving, player->GfxAction,
2121 player->is_moving, player_is_moving);
2125 if (player->is_pushing && player->is_moving)
2127 int px = SCREENX(jx), py = SCREENY(jy);
2128 int pxx = (TILEX - ABS(sxx)) * dx;
2129 int pyy = (TILEY - ABS(syy)) * dy;
2134 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2135 element = Feld[next_jx][next_jy];
2137 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2138 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2140 /* draw background element under pushed element (like the Sokoban field) */
2141 if (Back[next_jx][next_jy])
2142 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2144 /* masked drawing is needed for EMC style (double) movement graphics */
2145 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2149 /* ----------------------------------------------------------------------- */
2150 /* draw things in front of player (active dynamite or dynabombs) */
2151 /* ----------------------------------------------------------------------- */
2153 if (IS_ACTIVE_BOMB(element))
2155 graphic = el2img(element);
2156 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2158 if (game.emulation == EMU_SUPAPLEX)
2159 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2161 DrawGraphicThruMask(sx, sy, graphic, frame);
2164 if (player_is_moving && last_element == EL_EXPLOSION)
2166 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2167 GfxElement[last_jx][last_jy] : EL_EMPTY);
2168 int graphic = el_act2img(element, ACTION_EXPLODING);
2169 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2170 int phase = ExplodePhase[last_jx][last_jy] - 1;
2171 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2174 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2177 /* ----------------------------------------------------------------------- */
2178 /* draw elements the player is just walking/passing through/under */
2179 /* ----------------------------------------------------------------------- */
2181 if (player_is_moving)
2183 /* handle the field the player is leaving ... */
2184 if (IS_ACCESSIBLE_INSIDE(last_element))
2185 DrawLevelField(last_jx, last_jy);
2186 else if (IS_ACCESSIBLE_UNDER(last_element))
2187 DrawLevelFieldThruMask(last_jx, last_jy);
2190 /* do not redraw accessible elements if the player is just pushing them */
2191 if (!player_is_moving || !player->is_pushing)
2193 /* ... and the field the player is entering */
2194 if (IS_ACCESSIBLE_INSIDE(element))
2195 DrawLevelField(jx, jy);
2196 else if (IS_ACCESSIBLE_UNDER(element))
2197 DrawLevelFieldThruMask(jx, jy);
2200 if (setup.direct_draw)
2202 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2203 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2204 int x_size = TILEX * (1 + ABS(jx - last_jx));
2205 int y_size = TILEY * (1 + ABS(jy - last_jy));
2207 BlitBitmap(drawto_field, window,
2208 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2209 SetDrawtoField(DRAW_DIRECT);
2212 MarkTileDirty(sx, sy);
2215 /* ------------------------------------------------------------------------- */
2217 void WaitForEventToContinue()
2219 boolean still_wait = TRUE;
2221 /* simulate releasing mouse button over last gadget, if still pressed */
2223 HandleGadgets(-1, -1, 0);
2225 button_status = MB_RELEASED;
2237 case EVENT_BUTTONPRESS:
2238 case EVENT_KEYPRESS:
2242 case EVENT_KEYRELEASE:
2243 ClearPlayerAction();
2247 HandleOtherEvents(&event);
2251 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2258 /* don't eat all CPU time */
2263 #define MAX_REQUEST_LINES 13
2264 #define MAX_REQUEST_LINE_FONT1_LEN 7
2265 #define MAX_REQUEST_LINE_FONT2_LEN 10
2267 boolean Request(char *text, unsigned int req_state)
2269 int mx, my, ty, result = -1;
2270 unsigned int old_door_state;
2271 int last_game_status = game_status; /* save current game status */
2272 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2273 int font_nr = FONT_TEXT_2;
2274 int max_word_len = 0;
2277 for (text_ptr = text; *text_ptr; text_ptr++)
2279 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2281 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2283 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2284 font_nr = FONT_LEVEL_NUMBER;
2290 if (game_status == GAME_MODE_PLAYING &&
2291 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2292 BlitScreenToBitmap_EM(backbuffer);
2294 /* disable deactivated drawing when quick-loading level tape recording */
2295 if (tape.playing && tape.deactivate_display)
2296 TapeDeactivateDisplayOff(TRUE);
2298 SetMouseCursor(CURSOR_DEFAULT);
2300 #if defined(NETWORK_AVALIABLE)
2301 /* pause network game while waiting for request to answer */
2302 if (options.network &&
2303 game_status == GAME_MODE_PLAYING &&
2304 req_state & REQUEST_WAIT_FOR_INPUT)
2305 SendToServer_PausePlaying();
2308 old_door_state = GetDoorState();
2310 /* simulate releasing mouse button over last gadget, if still pressed */
2312 HandleGadgets(-1, -1, 0);
2316 if (old_door_state & DOOR_OPEN_1)
2318 CloseDoor(DOOR_CLOSE_1);
2320 /* save old door content */
2321 BlitBitmap(bitmap_db_door, bitmap_db_door,
2322 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2323 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2326 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2328 /* clear door drawing field */
2329 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2331 /* force DOOR font on preview level */
2332 game_status = GAME_MODE_PSEUDO_DOOR;
2334 /* write text for request */
2335 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2337 char text_line[max_request_line_len + 1];
2343 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2346 if (!tc || tc == ' ')
2357 strncpy(text_line, text, tl);
2360 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2361 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2362 text_line, font_nr);
2364 text += tl + (tc == ' ' ? 1 : 0);
2367 game_status = last_game_status; /* restore current game status */
2369 if (req_state & REQ_ASK)
2371 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2372 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2374 else if (req_state & REQ_CONFIRM)
2376 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2378 else if (req_state & REQ_PLAYER)
2380 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2381 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2382 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2383 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2386 /* copy request gadgets to door backbuffer */
2387 BlitBitmap(drawto, bitmap_db_door,
2388 DX, DY, DXSIZE, DYSIZE,
2389 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2391 OpenDoor(DOOR_OPEN_1);
2393 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2395 SetDrawBackgroundMask(REDRAW_FIELD);
2400 if (game_status != GAME_MODE_MAIN)
2403 button_status = MB_RELEASED;
2405 request_gadget_id = -1;
2407 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2419 case EVENT_BUTTONPRESS:
2420 case EVENT_BUTTONRELEASE:
2421 case EVENT_MOTIONNOTIFY:
2423 if (event.type == EVENT_MOTIONNOTIFY)
2425 if (!PointerInWindow(window))
2426 continue; /* window and pointer are on different screens */
2431 motion_status = TRUE;
2432 mx = ((MotionEvent *) &event)->x;
2433 my = ((MotionEvent *) &event)->y;
2437 motion_status = FALSE;
2438 mx = ((ButtonEvent *) &event)->x;
2439 my = ((ButtonEvent *) &event)->y;
2440 if (event.type == EVENT_BUTTONPRESS)
2441 button_status = ((ButtonEvent *) &event)->button;
2443 button_status = MB_RELEASED;
2446 /* this sets 'request_gadget_id' */
2447 HandleGadgets(mx, my, button_status);
2449 switch(request_gadget_id)
2451 case TOOL_CTRL_ID_YES:
2454 case TOOL_CTRL_ID_NO:
2457 case TOOL_CTRL_ID_CONFIRM:
2458 result = TRUE | FALSE;
2461 case TOOL_CTRL_ID_PLAYER_1:
2464 case TOOL_CTRL_ID_PLAYER_2:
2467 case TOOL_CTRL_ID_PLAYER_3:
2470 case TOOL_CTRL_ID_PLAYER_4:
2481 case EVENT_KEYPRESS:
2482 switch(GetEventKey((KeyEvent *)&event, TRUE))
2495 if (req_state & REQ_PLAYER)
2499 case EVENT_KEYRELEASE:
2500 ClearPlayerAction();
2504 HandleOtherEvents(&event);
2508 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2510 int joy = AnyJoystick();
2512 if (joy & JOY_BUTTON_1)
2514 else if (joy & JOY_BUTTON_2)
2520 /* don't eat all CPU time */
2524 if (game_status != GAME_MODE_MAIN)
2529 if (!(req_state & REQ_STAY_OPEN))
2531 CloseDoor(DOOR_CLOSE_1);
2533 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2534 (req_state & REQ_REOPEN))
2535 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2540 SetDrawBackgroundMask(REDRAW_FIELD);
2542 #if defined(NETWORK_AVALIABLE)
2543 /* continue network game after request */
2544 if (options.network &&
2545 game_status == GAME_MODE_PLAYING &&
2546 req_state & REQUEST_WAIT_FOR_INPUT)
2547 SendToServer_ContinuePlaying();
2550 /* restore deactivated drawing when quick-loading level tape recording */
2551 if (tape.playing && tape.deactivate_display)
2552 TapeDeactivateDisplayOn();
2557 unsigned int OpenDoor(unsigned int door_state)
2559 if (door_state & DOOR_COPY_BACK)
2561 if (door_state & DOOR_OPEN_1)
2562 BlitBitmap(bitmap_db_door, bitmap_db_door,
2563 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2564 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2566 if (door_state & DOOR_OPEN_2)
2567 BlitBitmap(bitmap_db_door, bitmap_db_door,
2568 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2569 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2571 door_state &= ~DOOR_COPY_BACK;
2574 return MoveDoor(door_state);
2577 unsigned int CloseDoor(unsigned int door_state)
2579 unsigned int old_door_state = GetDoorState();
2581 if (!(door_state & DOOR_NO_COPY_BACK))
2583 if (old_door_state & DOOR_OPEN_1)
2584 BlitBitmap(backbuffer, bitmap_db_door,
2585 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2587 if (old_door_state & DOOR_OPEN_2)
2588 BlitBitmap(backbuffer, bitmap_db_door,
2589 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2591 door_state &= ~DOOR_NO_COPY_BACK;
2594 return MoveDoor(door_state);
2597 unsigned int GetDoorState()
2599 return MoveDoor(DOOR_GET_STATE);
2602 unsigned int SetDoorState(unsigned int door_state)
2604 return MoveDoor(door_state | DOOR_SET_STATE);
2607 unsigned int MoveDoor(unsigned int door_state)
2609 static int door1 = DOOR_OPEN_1;
2610 static int door2 = DOOR_CLOSE_2;
2611 unsigned long door_delay = 0;
2612 unsigned long door_delay_value;
2615 if (door_1.width < 0 || door_1.width > DXSIZE)
2616 door_1.width = DXSIZE;
2617 if (door_1.height < 0 || door_1.height > DYSIZE)
2618 door_1.height = DYSIZE;
2619 if (door_2.width < 0 || door_2.width > VXSIZE)
2620 door_2.width = VXSIZE;
2621 if (door_2.height < 0 || door_2.height > VYSIZE)
2622 door_2.height = VYSIZE;
2624 if (door_state == DOOR_GET_STATE)
2625 return (door1 | door2);
2627 if (door_state & DOOR_SET_STATE)
2629 if (door_state & DOOR_ACTION_1)
2630 door1 = door_state & DOOR_ACTION_1;
2631 if (door_state & DOOR_ACTION_2)
2632 door2 = door_state & DOOR_ACTION_2;
2634 return (door1 | door2);
2637 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2638 door_state &= ~DOOR_OPEN_1;
2639 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2640 door_state &= ~DOOR_CLOSE_1;
2641 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2642 door_state &= ~DOOR_OPEN_2;
2643 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2644 door_state &= ~DOOR_CLOSE_2;
2646 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2649 if (setup.quick_doors)
2651 stepsize = 20; /* must be choosen to always draw last frame */
2652 door_delay_value = 0;
2655 if (global.autoplay_leveldir)
2657 door_state |= DOOR_NO_DELAY;
2658 door_state &= ~DOOR_CLOSE_ALL;
2661 if (door_state & DOOR_ACTION)
2663 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2664 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2665 boolean door_1_done = (!handle_door_1);
2666 boolean door_2_done = (!handle_door_2);
2667 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2668 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2669 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2670 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2671 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2672 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2673 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2674 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2675 int door_skip = max_door_size - door_size;
2677 int end = door_size;
2679 int end = (door_state & DOOR_ACTION_1 &&
2680 door_1.anim_mode & ANIM_VERTICAL ? DYSIZE : DXSIZE);
2683 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2685 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2689 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2691 /* opening door sound has priority over simultaneously closing door */
2692 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2693 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2694 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2695 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2698 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2701 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2702 GC gc = bitmap->stored_clip_gc;
2704 if (door_state & DOOR_ACTION_1)
2706 int a = MIN(x * door_1.step_offset, end);
2707 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2708 int i = p + door_skip;
2710 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2712 BlitBitmap(bitmap_db_door, drawto,
2713 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2714 DXSIZE, DYSIZE, DX, DY);
2718 BlitBitmap(bitmap_db_door, drawto,
2719 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2720 DXSIZE, DYSIZE - p / 2, DX, DY);
2722 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2725 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2727 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2728 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2729 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2730 int dst2_x = DX, dst2_y = DY;
2731 int width = i, height = DYSIZE;
2733 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2734 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2737 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2738 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2741 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2743 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2744 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2745 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2746 int dst2_x = DX, dst2_y = DY;
2747 int width = DXSIZE, height = i;
2749 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2750 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2753 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2754 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2757 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2759 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2761 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2762 BlitBitmapMasked(bitmap, drawto,
2763 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2764 DX + DXSIZE - i, DY + j);
2765 BlitBitmapMasked(bitmap, drawto,
2766 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2767 DX + DXSIZE - i, DY + 140 + j);
2768 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2769 DY - (DOOR_GFX_PAGEY1 + j));
2770 BlitBitmapMasked(bitmap, drawto,
2771 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2773 BlitBitmapMasked(bitmap, drawto,
2774 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2777 BlitBitmapMasked(bitmap, drawto,
2778 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2780 BlitBitmapMasked(bitmap, drawto,
2781 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2783 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2784 BlitBitmapMasked(bitmap, drawto,
2785 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2786 DX + DXSIZE - i, DY + 77 + j);
2787 BlitBitmapMasked(bitmap, drawto,
2788 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2789 DX + DXSIZE - i, DY + 203 + j);
2792 redraw_mask |= REDRAW_DOOR_1;
2793 door_1_done = (a == end);
2796 if (door_state & DOOR_ACTION_2)
2798 int a = MIN(x * door_2.step_offset, door_size_2);
2799 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2800 int i = p + door_skip;
2802 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2804 BlitBitmap(bitmap_db_door, drawto,
2805 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2806 VXSIZE, VYSIZE, VX, VY);
2808 else if (x <= VYSIZE)
2810 BlitBitmap(bitmap_db_door, drawto,
2811 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2812 VXSIZE, VYSIZE - p / 2, VX, VY);
2814 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2817 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2819 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2820 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2821 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2822 int dst2_x = VX, dst2_y = VY;
2823 int width = i, height = VYSIZE;
2825 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2826 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2829 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2830 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2833 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2835 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2836 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2837 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2838 int dst2_x = VX, dst2_y = VY;
2839 int width = VXSIZE, height = i;
2841 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2842 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2845 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2846 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2849 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2851 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2853 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2854 BlitBitmapMasked(bitmap, drawto,
2855 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2856 VX + VXSIZE - i, VY + j);
2857 SetClipOrigin(bitmap, gc,
2858 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2859 BlitBitmapMasked(bitmap, drawto,
2860 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2863 BlitBitmapMasked(bitmap, drawto,
2864 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2865 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2866 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2867 BlitBitmapMasked(bitmap, drawto,
2868 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2870 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2873 redraw_mask |= REDRAW_DOOR_2;
2874 door_2_done = (a == VXSIZE);
2877 if (!(door_state & DOOR_NO_DELAY))
2881 if (game_status == GAME_MODE_MAIN)
2884 WaitUntilDelayReached(&door_delay, door_delay_value);
2889 if (door_state & DOOR_ACTION_1)
2890 door1 = door_state & DOOR_ACTION_1;
2891 if (door_state & DOOR_ACTION_2)
2892 door2 = door_state & DOOR_ACTION_2;
2894 return (door1 | door2);
2897 void DrawSpecialEditorDoor()
2899 /* draw bigger toolbox window */
2900 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2901 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2903 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2904 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2907 redraw_mask |= REDRAW_ALL;
2910 void UndrawSpecialEditorDoor()
2912 /* draw normal tape recorder window */
2913 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2914 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2917 redraw_mask |= REDRAW_ALL;
2921 /* ---------- new tool button stuff ---------------------------------------- */
2923 /* graphic position values for tool buttons */
2924 #define TOOL_BUTTON_YES_XPOS 2
2925 #define TOOL_BUTTON_YES_YPOS 250
2926 #define TOOL_BUTTON_YES_GFX_YPOS 0
2927 #define TOOL_BUTTON_YES_XSIZE 46
2928 #define TOOL_BUTTON_YES_YSIZE 28
2929 #define TOOL_BUTTON_NO_XPOS 52
2930 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2931 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2932 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2933 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2934 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2935 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2936 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2937 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2938 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2939 #define TOOL_BUTTON_PLAYER_XSIZE 30
2940 #define TOOL_BUTTON_PLAYER_YSIZE 30
2941 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2942 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2943 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2944 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2945 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2946 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2947 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2948 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2949 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2950 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2951 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2952 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2953 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2954 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2955 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2956 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2957 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2958 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2959 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2960 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2969 } toolbutton_info[NUM_TOOL_BUTTONS] =
2972 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2973 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2974 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2979 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2980 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2981 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2986 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2987 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2988 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2989 TOOL_CTRL_ID_CONFIRM,
2993 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2994 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2995 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2996 TOOL_CTRL_ID_PLAYER_1,
3000 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3001 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3002 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3003 TOOL_CTRL_ID_PLAYER_2,
3007 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3008 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3009 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3010 TOOL_CTRL_ID_PLAYER_3,
3014 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3015 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3016 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3017 TOOL_CTRL_ID_PLAYER_4,
3022 void CreateToolButtons()
3026 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3028 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3029 Bitmap *deco_bitmap = None;
3030 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3031 struct GadgetInfo *gi;
3032 unsigned long event_mask;
3033 int gd_xoffset, gd_yoffset;
3034 int gd_x1, gd_x2, gd_y;
3037 event_mask = GD_EVENT_RELEASED;
3039 gd_xoffset = toolbutton_info[i].xpos;
3040 gd_yoffset = toolbutton_info[i].ypos;
3041 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3042 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3043 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3045 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3047 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3049 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3050 &deco_bitmap, &deco_x, &deco_y);
3051 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3052 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3055 gi = CreateGadget(GDI_CUSTOM_ID, id,
3056 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3057 GDI_X, DX + toolbutton_info[i].x,
3058 GDI_Y, DY + toolbutton_info[i].y,
3059 GDI_WIDTH, toolbutton_info[i].width,
3060 GDI_HEIGHT, toolbutton_info[i].height,
3061 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3062 GDI_STATE, GD_BUTTON_UNPRESSED,
3063 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3064 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3065 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3066 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3067 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3068 GDI_DECORATION_SHIFTING, 1, 1,
3069 GDI_EVENT_MASK, event_mask,
3070 GDI_CALLBACK_ACTION, HandleToolButtons,
3074 Error(ERR_EXIT, "cannot create gadget");
3076 tool_gadget[id] = gi;
3080 void FreeToolButtons()
3084 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3085 FreeGadget(tool_gadget[i]);
3088 static void UnmapToolButtons()
3092 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3093 UnmapGadget(tool_gadget[i]);
3096 static void HandleToolButtons(struct GadgetInfo *gi)
3098 request_gadget_id = gi->custom_id;
3101 static struct Mapping_EM_to_RND_object
3104 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3105 boolean is_backside; /* backside of moving element */
3111 em_object_mapping_list[] =
3114 Xblank, TRUE, FALSE,
3118 Yacid_splash_eB, FALSE, FALSE,
3119 EL_ACID_SPLASH_RIGHT, -1, -1
3122 Yacid_splash_wB, FALSE, FALSE,
3123 EL_ACID_SPLASH_LEFT, -1, -1
3126 #ifdef EM_ENGINE_BAD_ROLL
3128 Xstone_force_e, FALSE, FALSE,
3129 EL_ROCK, -1, MV_BIT_RIGHT
3132 Xstone_force_w, FALSE, FALSE,
3133 EL_ROCK, -1, MV_BIT_LEFT
3136 Xnut_force_e, FALSE, FALSE,
3137 EL_NUT, -1, MV_BIT_RIGHT
3140 Xnut_force_w, FALSE, FALSE,
3141 EL_NUT, -1, MV_BIT_LEFT
3144 Xspring_force_e, FALSE, FALSE,
3145 EL_SPRING, -1, MV_BIT_RIGHT
3148 Xspring_force_w, FALSE, FALSE,
3149 EL_SPRING, -1, MV_BIT_LEFT
3152 Xemerald_force_e, FALSE, FALSE,
3153 EL_EMERALD, -1, MV_BIT_RIGHT
3156 Xemerald_force_w, FALSE, FALSE,
3157 EL_EMERALD, -1, MV_BIT_LEFT
3160 Xdiamond_force_e, FALSE, FALSE,
3161 EL_DIAMOND, -1, MV_BIT_RIGHT
3164 Xdiamond_force_w, FALSE, FALSE,
3165 EL_DIAMOND, -1, MV_BIT_LEFT
3168 Xbomb_force_e, FALSE, FALSE,
3169 EL_BOMB, -1, MV_BIT_RIGHT
3172 Xbomb_force_w, FALSE, FALSE,
3173 EL_BOMB, -1, MV_BIT_LEFT
3175 #endif /* EM_ENGINE_BAD_ROLL */
3178 Xstone, TRUE, FALSE,
3182 Xstone_pause, FALSE, FALSE,
3186 Xstone_fall, FALSE, FALSE,
3190 Ystone_s, FALSE, FALSE,
3191 EL_ROCK, ACTION_FALLING, -1
3194 Ystone_sB, FALSE, TRUE,
3195 EL_ROCK, ACTION_FALLING, -1
3198 Ystone_e, FALSE, FALSE,
3199 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3202 Ystone_eB, FALSE, TRUE,
3203 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3206 Ystone_w, FALSE, FALSE,
3207 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3210 Ystone_wB, FALSE, TRUE,
3211 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3218 Xnut_pause, FALSE, FALSE,
3222 Xnut_fall, FALSE, FALSE,
3226 Ynut_s, FALSE, FALSE,
3227 EL_NUT, ACTION_FALLING, -1
3230 Ynut_sB, FALSE, TRUE,
3231 EL_NUT, ACTION_FALLING, -1
3234 Ynut_e, FALSE, FALSE,
3235 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3238 Ynut_eB, FALSE, TRUE,
3239 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3242 Ynut_w, FALSE, FALSE,
3243 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3246 Ynut_wB, FALSE, TRUE,
3247 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3250 Xbug_n, TRUE, FALSE,
3254 Xbug_e, TRUE, FALSE,
3255 EL_BUG_RIGHT, -1, -1
3258 Xbug_s, TRUE, FALSE,
3262 Xbug_w, TRUE, FALSE,
3266 Xbug_gon, FALSE, FALSE,
3270 Xbug_goe, FALSE, FALSE,
3271 EL_BUG_RIGHT, -1, -1
3274 Xbug_gos, FALSE, FALSE,
3278 Xbug_gow, FALSE, FALSE,
3282 Ybug_n, FALSE, FALSE,
3283 EL_BUG, ACTION_MOVING, MV_BIT_UP
3286 Ybug_nB, FALSE, TRUE,
3287 EL_BUG, ACTION_MOVING, MV_BIT_UP
3290 Ybug_e, FALSE, FALSE,
3291 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3294 Ybug_eB, FALSE, TRUE,
3295 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3298 Ybug_s, FALSE, FALSE,
3299 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3302 Ybug_sB, FALSE, TRUE,
3303 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3306 Ybug_w, FALSE, FALSE,
3307 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3310 Ybug_wB, FALSE, TRUE,
3311 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3314 Ybug_w_n, FALSE, FALSE,
3315 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3318 Ybug_n_e, FALSE, FALSE,
3319 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3322 Ybug_e_s, FALSE, FALSE,
3323 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3326 Ybug_s_w, FALSE, FALSE,
3327 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3330 Ybug_e_n, FALSE, FALSE,
3331 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3334 Ybug_s_e, FALSE, FALSE,
3335 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3338 Ybug_w_s, FALSE, FALSE,
3339 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3342 Ybug_n_w, FALSE, FALSE,
3343 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3346 Ybug_stone, FALSE, FALSE,
3347 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3350 Ybug_spring, FALSE, FALSE,
3351 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3354 Xtank_n, TRUE, FALSE,
3355 EL_SPACESHIP_UP, -1, -1
3358 Xtank_e, TRUE, FALSE,
3359 EL_SPACESHIP_RIGHT, -1, -1
3362 Xtank_s, TRUE, FALSE,
3363 EL_SPACESHIP_DOWN, -1, -1
3366 Xtank_w, TRUE, FALSE,
3367 EL_SPACESHIP_LEFT, -1, -1
3370 Xtank_gon, FALSE, FALSE,
3371 EL_SPACESHIP_UP, -1, -1
3374 Xtank_goe, FALSE, FALSE,
3375 EL_SPACESHIP_RIGHT, -1, -1
3378 Xtank_gos, FALSE, FALSE,
3379 EL_SPACESHIP_DOWN, -1, -1
3382 Xtank_gow, FALSE, FALSE,
3383 EL_SPACESHIP_LEFT, -1, -1
3386 Ytank_n, FALSE, FALSE,
3387 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3390 Ytank_nB, FALSE, TRUE,
3391 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3394 Ytank_e, FALSE, FALSE,
3395 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3398 Ytank_eB, FALSE, TRUE,
3399 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3402 Ytank_s, FALSE, FALSE,
3403 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3406 Ytank_sB, FALSE, TRUE,
3407 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3410 Ytank_w, FALSE, FALSE,
3411 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3414 Ytank_wB, FALSE, TRUE,
3415 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3418 Ytank_w_n, FALSE, FALSE,
3419 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3422 Ytank_n_e, FALSE, FALSE,
3423 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3426 Ytank_e_s, FALSE, FALSE,
3427 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3430 Ytank_s_w, FALSE, FALSE,
3431 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3434 Ytank_e_n, FALSE, FALSE,
3435 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3438 Ytank_s_e, FALSE, FALSE,
3439 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3442 Ytank_w_s, FALSE, FALSE,
3443 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3446 Ytank_n_w, FALSE, FALSE,
3447 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3450 Ytank_stone, FALSE, FALSE,
3451 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3454 Ytank_spring, FALSE, FALSE,
3455 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3458 Xandroid, TRUE, FALSE,
3459 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3462 Xandroid_1_n, FALSE, FALSE,
3463 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3466 Xandroid_2_n, FALSE, FALSE,
3467 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3470 Xandroid_1_e, FALSE, FALSE,
3471 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3474 Xandroid_2_e, FALSE, FALSE,
3475 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3478 Xandroid_1_w, FALSE, FALSE,
3479 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3482 Xandroid_2_w, FALSE, FALSE,
3483 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3486 Xandroid_1_s, FALSE, FALSE,
3487 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3490 Xandroid_2_s, FALSE, FALSE,
3491 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3494 Yandroid_n, FALSE, FALSE,
3495 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3498 Yandroid_nB, FALSE, TRUE,
3499 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3502 Yandroid_ne, FALSE, FALSE,
3503 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3506 Yandroid_neB, FALSE, TRUE,
3507 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3510 Yandroid_e, FALSE, FALSE,
3511 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3514 Yandroid_eB, FALSE, TRUE,
3515 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3518 Yandroid_se, FALSE, FALSE,
3519 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3522 Yandroid_seB, FALSE, TRUE,
3523 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3526 Yandroid_s, FALSE, FALSE,
3527 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3530 Yandroid_sB, FALSE, TRUE,
3531 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3534 Yandroid_sw, FALSE, FALSE,
3535 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3538 Yandroid_swB, FALSE, TRUE,
3539 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3542 Yandroid_w, FALSE, FALSE,
3543 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3546 Yandroid_wB, FALSE, TRUE,
3547 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3550 Yandroid_nw, FALSE, FALSE,
3551 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3554 Yandroid_nwB, FALSE, TRUE,
3555 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3558 Xspring, TRUE, FALSE,
3562 Xspring_pause, FALSE, FALSE,
3566 Xspring_e, FALSE, FALSE,
3570 Xspring_w, FALSE, FALSE,
3574 Xspring_fall, FALSE, FALSE,
3578 Yspring_s, FALSE, FALSE,
3579 EL_SPRING, ACTION_FALLING, -1
3582 Yspring_sB, FALSE, TRUE,
3583 EL_SPRING, ACTION_FALLING, -1
3586 Yspring_e, FALSE, FALSE,
3587 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3590 Yspring_eB, FALSE, TRUE,
3591 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3594 Yspring_w, FALSE, FALSE,
3595 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3598 Yspring_wB, FALSE, TRUE,
3599 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3602 Yspring_kill_e, FALSE, FALSE,
3603 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3606 Yspring_kill_eB, FALSE, TRUE,
3607 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3610 Yspring_kill_w, FALSE, FALSE,
3611 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3614 Yspring_kill_wB, FALSE, TRUE,
3615 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3618 Xeater_n, TRUE, FALSE,
3619 EL_YAMYAM_UP, -1, -1
3622 Xeater_e, TRUE, FALSE,
3623 EL_YAMYAM_RIGHT, -1, -1
3626 Xeater_w, TRUE, FALSE,
3627 EL_YAMYAM_LEFT, -1, -1
3630 Xeater_s, TRUE, FALSE,
3631 EL_YAMYAM_DOWN, -1, -1
3634 Yeater_n, FALSE, FALSE,
3635 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3638 Yeater_nB, FALSE, TRUE,
3639 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3642 Yeater_e, FALSE, FALSE,
3643 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3646 Yeater_eB, FALSE, TRUE,
3647 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3650 Yeater_s, FALSE, FALSE,
3651 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3654 Yeater_sB, FALSE, TRUE,
3655 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3658 Yeater_w, FALSE, FALSE,
3659 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3662 Yeater_wB, FALSE, TRUE,
3663 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3666 Yeater_stone, FALSE, FALSE,
3667 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3670 Yeater_spring, FALSE, FALSE,
3671 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3674 Xalien, TRUE, FALSE,
3678 Xalien_pause, FALSE, FALSE,
3682 Yalien_n, FALSE, FALSE,
3683 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3686 Yalien_nB, FALSE, TRUE,
3687 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3690 Yalien_e, FALSE, FALSE,
3691 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3694 Yalien_eB, FALSE, TRUE,
3695 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3698 Yalien_s, FALSE, FALSE,
3699 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3702 Yalien_sB, FALSE, TRUE,
3703 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3706 Yalien_w, FALSE, FALSE,
3707 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3710 Yalien_wB, FALSE, TRUE,
3711 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3714 Yalien_stone, FALSE, FALSE,
3715 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3718 Yalien_spring, FALSE, FALSE,
3719 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3722 Xemerald, TRUE, FALSE,
3726 Xemerald_pause, FALSE, FALSE,
3730 Xemerald_fall, FALSE, FALSE,
3734 Xemerald_shine, FALSE, FALSE,
3735 EL_EMERALD, ACTION_TWINKLING, -1
3738 Yemerald_s, FALSE, FALSE,
3739 EL_EMERALD, ACTION_FALLING, -1
3742 Yemerald_sB, FALSE, TRUE,
3743 EL_EMERALD, ACTION_FALLING, -1
3746 Yemerald_e, FALSE, FALSE,
3747 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3750 Yemerald_eB, FALSE, TRUE,
3751 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3754 Yemerald_w, FALSE, FALSE,
3755 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3758 Yemerald_wB, FALSE, TRUE,
3759 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3762 Yemerald_eat, FALSE, FALSE,
3763 EL_EMERALD, ACTION_COLLECTING, -1
3766 Yemerald_stone, FALSE, FALSE,
3767 EL_NUT, ACTION_BREAKING, -1
3770 Xdiamond, TRUE, FALSE,
3774 Xdiamond_pause, FALSE, FALSE,
3778 Xdiamond_fall, FALSE, FALSE,
3782 Xdiamond_shine, FALSE, FALSE,
3783 EL_DIAMOND, ACTION_TWINKLING, -1
3786 Ydiamond_s, FALSE, FALSE,
3787 EL_DIAMOND, ACTION_FALLING, -1
3790 Ydiamond_sB, FALSE, TRUE,
3791 EL_DIAMOND, ACTION_FALLING, -1
3794 Ydiamond_e, FALSE, FALSE,
3795 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3798 Ydiamond_eB, FALSE, TRUE,
3799 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3802 Ydiamond_w, FALSE, FALSE,
3803 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3806 Ydiamond_wB, FALSE, TRUE,
3807 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3810 Ydiamond_eat, FALSE, FALSE,
3811 EL_DIAMOND, ACTION_COLLECTING, -1
3814 Ydiamond_stone, FALSE, FALSE,
3815 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3818 Xdrip_fall, TRUE, FALSE,
3819 EL_AMOEBA_DROP, -1, -1
3822 Xdrip_stretch, FALSE, FALSE,
3823 EL_AMOEBA_DROP, ACTION_FALLING, -1
3826 Xdrip_stretchB, FALSE, TRUE,
3827 EL_AMOEBA_DROP, ACTION_FALLING, -1
3830 Xdrip_eat, FALSE, FALSE,
3831 EL_AMOEBA_DROP, ACTION_GROWING, -1
3834 Ydrip_s1, FALSE, FALSE,
3835 EL_AMOEBA_DROP, ACTION_FALLING, -1
3838 Ydrip_s1B, FALSE, TRUE,
3839 EL_AMOEBA_DROP, ACTION_FALLING, -1
3842 Ydrip_s2, FALSE, FALSE,
3843 EL_AMOEBA_DROP, ACTION_FALLING, -1
3846 Ydrip_s2B, FALSE, TRUE,
3847 EL_AMOEBA_DROP, ACTION_FALLING, -1
3854 Xbomb_pause, FALSE, FALSE,
3858 Xbomb_fall, FALSE, FALSE,
3862 Ybomb_s, FALSE, FALSE,
3863 EL_BOMB, ACTION_FALLING, -1
3866 Ybomb_sB, FALSE, TRUE,
3867 EL_BOMB, ACTION_FALLING, -1
3870 Ybomb_e, FALSE, FALSE,
3871 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3874 Ybomb_eB, FALSE, TRUE,
3875 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3878 Ybomb_w, FALSE, FALSE,
3879 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3882 Ybomb_wB, FALSE, TRUE,
3883 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3886 Ybomb_eat, FALSE, FALSE,
3887 EL_BOMB, ACTION_ACTIVATING, -1
3890 Xballoon, TRUE, FALSE,
3894 Yballoon_n, FALSE, FALSE,
3895 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3898 Yballoon_nB, FALSE, TRUE,
3899 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3902 Yballoon_e, FALSE, FALSE,
3903 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3906 Yballoon_eB, FALSE, TRUE,
3907 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3910 Yballoon_s, FALSE, FALSE,
3911 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3914 Yballoon_sB, FALSE, TRUE,
3915 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3918 Yballoon_w, FALSE, FALSE,
3919 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3922 Yballoon_wB, FALSE, TRUE,
3923 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3926 Xgrass, TRUE, FALSE,
3927 EL_EMC_GRASS, -1, -1
3930 Ygrass_nB, FALSE, FALSE,
3931 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3934 Ygrass_eB, FALSE, FALSE,
3935 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3938 Ygrass_sB, FALSE, FALSE,
3939 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3942 Ygrass_wB, FALSE, FALSE,
3943 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3950 Ydirt_nB, FALSE, FALSE,
3951 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3954 Ydirt_eB, FALSE, FALSE,
3955 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3958 Ydirt_sB, FALSE, FALSE,
3959 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3962 Ydirt_wB, FALSE, FALSE,
3963 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3966 Xacid_ne, TRUE, FALSE,
3967 EL_ACID_POOL_TOPRIGHT, -1, -1
3970 Xacid_se, TRUE, FALSE,
3971 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3974 Xacid_s, TRUE, FALSE,
3975 EL_ACID_POOL_BOTTOM, -1, -1
3978 Xacid_sw, TRUE, FALSE,
3979 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3982 Xacid_nw, TRUE, FALSE,
3983 EL_ACID_POOL_TOPLEFT, -1, -1
3986 Xacid_1, TRUE, FALSE,
3990 Xacid_2, FALSE, FALSE,
3994 Xacid_3, FALSE, FALSE,
3998 Xacid_4, FALSE, FALSE,
4002 Xacid_5, FALSE, FALSE,
4006 Xacid_6, FALSE, FALSE,
4010 Xacid_7, FALSE, FALSE,
4014 Xacid_8, FALSE, FALSE,
4018 Xball_1, TRUE, FALSE,
4019 EL_EMC_MAGIC_BALL, -1, -1
4022 Xball_1B, FALSE, FALSE,
4023 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4026 Xball_2, FALSE, FALSE,
4027 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4030 Xball_2B, FALSE, FALSE,
4031 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4034 Yball_eat, FALSE, FALSE,
4035 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4038 Ykey_1_eat, FALSE, FALSE,
4039 EL_EM_KEY_1, ACTION_COLLECTING, -1
4042 Ykey_2_eat, FALSE, FALSE,
4043 EL_EM_KEY_2, ACTION_COLLECTING, -1
4046 Ykey_3_eat, FALSE, FALSE,
4047 EL_EM_KEY_3, ACTION_COLLECTING, -1
4050 Ykey_4_eat, FALSE, FALSE,
4051 EL_EM_KEY_4, ACTION_COLLECTING, -1
4054 Ykey_5_eat, FALSE, FALSE,
4055 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4058 Ykey_6_eat, FALSE, FALSE,
4059 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4062 Ykey_7_eat, FALSE, FALSE,
4063 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4066 Ykey_8_eat, FALSE, FALSE,
4067 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4070 Ylenses_eat, FALSE, FALSE,
4071 EL_EMC_LENSES, ACTION_COLLECTING, -1
4074 Ymagnify_eat, FALSE, FALSE,
4075 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4078 Ygrass_eat, FALSE, FALSE,
4079 EL_EMC_GRASS, ACTION_SNAPPING, -1
4082 Ydirt_eat, FALSE, FALSE,
4083 EL_SAND, ACTION_SNAPPING, -1
4086 Xgrow_ns, TRUE, FALSE,
4087 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4090 Ygrow_ns_eat, FALSE, FALSE,
4091 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4094 Xgrow_ew, TRUE, FALSE,
4095 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4098 Ygrow_ew_eat, FALSE, FALSE,
4099 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4102 Xwonderwall, TRUE, FALSE,
4103 EL_MAGIC_WALL, -1, -1
4106 XwonderwallB, FALSE, FALSE,
4107 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4110 Xamoeba_1, TRUE, FALSE,
4111 EL_AMOEBA_DRY, ACTION_OTHER, -1
4114 Xamoeba_2, FALSE, FALSE,
4115 EL_AMOEBA_DRY, ACTION_OTHER, -1
4118 Xamoeba_3, FALSE, FALSE,
4119 EL_AMOEBA_DRY, ACTION_OTHER, -1
4122 Xamoeba_4, FALSE, FALSE,
4123 EL_AMOEBA_DRY, ACTION_OTHER, -1
4126 Xamoeba_5, TRUE, FALSE,
4127 EL_AMOEBA_WET, ACTION_OTHER, -1
4130 Xamoeba_6, FALSE, FALSE,
4131 EL_AMOEBA_WET, ACTION_OTHER, -1
4134 Xamoeba_7, FALSE, FALSE,
4135 EL_AMOEBA_WET, ACTION_OTHER, -1
4138 Xamoeba_8, FALSE, FALSE,
4139 EL_AMOEBA_WET, ACTION_OTHER, -1
4142 Xdoor_1, TRUE, FALSE,
4143 EL_EM_GATE_1, -1, -1
4146 Xdoor_2, TRUE, FALSE,
4147 EL_EM_GATE_2, -1, -1
4150 Xdoor_3, TRUE, FALSE,
4151 EL_EM_GATE_3, -1, -1
4154 Xdoor_4, TRUE, FALSE,
4155 EL_EM_GATE_4, -1, -1
4158 Xdoor_5, TRUE, FALSE,
4159 EL_EMC_GATE_5, -1, -1
4162 Xdoor_6, TRUE, FALSE,
4163 EL_EMC_GATE_6, -1, -1
4166 Xdoor_7, TRUE, FALSE,
4167 EL_EMC_GATE_7, -1, -1
4170 Xdoor_8, TRUE, FALSE,
4171 EL_EMC_GATE_8, -1, -1
4174 Xkey_1, TRUE, FALSE,
4178 Xkey_2, TRUE, FALSE,
4182 Xkey_3, TRUE, FALSE,
4186 Xkey_4, TRUE, FALSE,
4190 Xkey_5, TRUE, FALSE,
4191 EL_EMC_KEY_5, -1, -1
4194 Xkey_6, TRUE, FALSE,
4195 EL_EMC_KEY_6, -1, -1
4198 Xkey_7, TRUE, FALSE,
4199 EL_EMC_KEY_7, -1, -1
4202 Xkey_8, TRUE, FALSE,
4203 EL_EMC_KEY_8, -1, -1
4206 Xwind_n, TRUE, FALSE,
4207 EL_BALLOON_SWITCH_UP, -1, -1
4210 Xwind_e, TRUE, FALSE,
4211 EL_BALLOON_SWITCH_RIGHT, -1, -1
4214 Xwind_s, TRUE, FALSE,
4215 EL_BALLOON_SWITCH_DOWN, -1, -1
4218 Xwind_w, TRUE, FALSE,
4219 EL_BALLOON_SWITCH_LEFT, -1, -1
4222 Xwind_nesw, TRUE, FALSE,
4223 EL_BALLOON_SWITCH_ANY, -1, -1
4226 Xwind_stop, TRUE, FALSE,
4227 EL_BALLOON_SWITCH_NONE, -1, -1
4231 EL_EXIT_CLOSED, -1, -1
4234 Xexit_1, TRUE, FALSE,
4235 EL_EXIT_OPEN, -1, -1
4238 Xexit_2, FALSE, FALSE,
4239 EL_EXIT_OPEN, -1, -1
4242 Xexit_3, FALSE, FALSE,
4243 EL_EXIT_OPEN, -1, -1
4246 Xdynamite, TRUE, FALSE,
4247 EL_EM_DYNAMITE, -1, -1
4250 Ydynamite_eat, FALSE, FALSE,
4251 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4254 Xdynamite_1, TRUE, FALSE,
4255 EL_EM_DYNAMITE_ACTIVE, -1, -1
4258 Xdynamite_2, FALSE, FALSE,
4259 EL_EM_DYNAMITE_ACTIVE, -1, -1
4262 Xdynamite_3, FALSE, FALSE,
4263 EL_EM_DYNAMITE_ACTIVE, -1, -1
4266 Xdynamite_4, FALSE, FALSE,
4267 EL_EM_DYNAMITE_ACTIVE, -1, -1
4270 Xbumper, TRUE, FALSE,
4271 EL_EMC_SPRING_BUMPER, -1, -1
4274 XbumperB, FALSE, FALSE,
4275 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4278 Xwheel, TRUE, FALSE,
4279 EL_ROBOT_WHEEL, -1, -1
4282 XwheelB, FALSE, FALSE,
4283 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4286 Xswitch, TRUE, FALSE,
4287 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4290 XswitchB, FALSE, FALSE,
4291 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4295 EL_QUICKSAND_EMPTY, -1, -1
4298 Xsand_stone, TRUE, FALSE,
4299 EL_QUICKSAND_FULL, -1, -1
4302 Xsand_stonein_1, FALSE, TRUE,
4303 EL_ROCK, ACTION_FILLING, -1
4306 Xsand_stonein_2, FALSE, TRUE,
4307 EL_ROCK, ACTION_FILLING, -1
4310 Xsand_stonein_3, FALSE, TRUE,
4311 EL_ROCK, ACTION_FILLING, -1
4314 Xsand_stonein_4, FALSE, TRUE,
4315 EL_ROCK, ACTION_FILLING, -1
4318 Xsand_stonesand_1, FALSE, FALSE,
4319 EL_QUICKSAND_FULL, -1, -1
4322 Xsand_stonesand_2, FALSE, FALSE,
4323 EL_QUICKSAND_FULL, -1, -1
4326 Xsand_stonesand_3, FALSE, FALSE,
4327 EL_QUICKSAND_FULL, -1, -1
4330 Xsand_stonesand_4, FALSE, FALSE,
4331 EL_QUICKSAND_FULL, -1, -1
4334 Xsand_stoneout_1, FALSE, FALSE,
4335 EL_ROCK, ACTION_EMPTYING, -1
4338 Xsand_stoneout_2, FALSE, FALSE,
4339 EL_ROCK, ACTION_EMPTYING, -1
4342 Xsand_sandstone_1, FALSE, FALSE,
4343 EL_QUICKSAND_FULL, -1, -1
4346 Xsand_sandstone_2, FALSE, FALSE,
4347 EL_QUICKSAND_FULL, -1, -1
4350 Xsand_sandstone_3, FALSE, FALSE,
4351 EL_QUICKSAND_FULL, -1, -1
4354 Xsand_sandstone_4, FALSE, FALSE,
4355 EL_QUICKSAND_FULL, -1, -1
4358 Xplant, TRUE, FALSE,
4359 EL_EMC_PLANT, -1, -1
4362 Yplant, FALSE, FALSE,
4363 EL_EMC_PLANT, -1, -1
4366 Xlenses, TRUE, FALSE,
4367 EL_EMC_LENSES, -1, -1
4370 Xmagnify, TRUE, FALSE,
4371 EL_EMC_MAGNIFIER, -1, -1
4374 Xdripper, TRUE, FALSE,
4375 EL_EMC_DRIPPER, -1, -1
4378 XdripperB, FALSE, FALSE,
4379 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4382 Xfake_blank, TRUE, FALSE,
4383 EL_INVISIBLE_WALL, -1, -1
4386 Xfake_blankB, FALSE, FALSE,
4387 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4390 Xfake_grass, TRUE, FALSE,
4391 EL_EMC_FAKE_GRASS, -1, -1
4394 Xfake_grassB, FALSE, FALSE,
4395 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4398 Xfake_door_1, TRUE, FALSE,
4399 EL_EM_GATE_1_GRAY, -1, -1
4402 Xfake_door_2, TRUE, FALSE,
4403 EL_EM_GATE_2_GRAY, -1, -1
4406 Xfake_door_3, TRUE, FALSE,
4407 EL_EM_GATE_3_GRAY, -1, -1
4410 Xfake_door_4, TRUE, FALSE,
4411 EL_EM_GATE_4_GRAY, -1, -1
4414 Xfake_door_5, TRUE, FALSE,
4415 EL_EMC_GATE_5_GRAY, -1, -1
4418 Xfake_door_6, TRUE, FALSE,
4419 EL_EMC_GATE_6_GRAY, -1, -1
4422 Xfake_door_7, TRUE, FALSE,
4423 EL_EMC_GATE_7_GRAY, -1, -1
4426 Xfake_door_8, TRUE, FALSE,
4427 EL_EMC_GATE_8_GRAY, -1, -1
4430 Xfake_acid_1, TRUE, FALSE,
4431 EL_EMC_FAKE_ACID, -1, -1
4434 Xfake_acid_2, FALSE, FALSE,
4435 EL_EMC_FAKE_ACID, -1, -1
4438 Xfake_acid_3, FALSE, FALSE,
4439 EL_EMC_FAKE_ACID, -1, -1
4442 Xfake_acid_4, FALSE, FALSE,
4443 EL_EMC_FAKE_ACID, -1, -1
4446 Xfake_acid_5, FALSE, FALSE,
4447 EL_EMC_FAKE_ACID, -1, -1
4450 Xfake_acid_6, FALSE, FALSE,
4451 EL_EMC_FAKE_ACID, -1, -1
4454 Xfake_acid_7, FALSE, FALSE,
4455 EL_EMC_FAKE_ACID, -1, -1
4458 Xfake_acid_8, FALSE, FALSE,
4459 EL_EMC_FAKE_ACID, -1, -1
4462 Xsteel_1, TRUE, FALSE,
4463 EL_STEELWALL, -1, -1
4466 Xsteel_2, TRUE, FALSE,
4467 EL_EMC_STEELWALL_2, -1, -1
4470 Xsteel_3, TRUE, FALSE,
4471 EL_EMC_STEELWALL_3, -1, -1
4474 Xsteel_4, TRUE, FALSE,
4475 EL_EMC_STEELWALL_4, -1, -1
4478 Xwall_1, TRUE, FALSE,
4482 Xwall_2, TRUE, FALSE,
4483 EL_EMC_WALL_14, -1, -1
4486 Xwall_3, TRUE, FALSE,
4487 EL_EMC_WALL_15, -1, -1
4490 Xwall_4, TRUE, FALSE,
4491 EL_EMC_WALL_16, -1, -1
4494 Xround_wall_1, TRUE, FALSE,
4495 EL_WALL_SLIPPERY, -1, -1
4498 Xround_wall_2, TRUE, FALSE,
4499 EL_EMC_WALL_SLIPPERY_2, -1, -1
4502 Xround_wall_3, TRUE, FALSE,
4503 EL_EMC_WALL_SLIPPERY_3, -1, -1
4506 Xround_wall_4, TRUE, FALSE,
4507 EL_EMC_WALL_SLIPPERY_4, -1, -1
4510 Xdecor_1, TRUE, FALSE,
4511 EL_EMC_WALL_8, -1, -1
4514 Xdecor_2, TRUE, FALSE,
4515 EL_EMC_WALL_6, -1, -1
4518 Xdecor_3, TRUE, FALSE,
4519 EL_EMC_WALL_4, -1, -1
4522 Xdecor_4, TRUE, FALSE,
4523 EL_EMC_WALL_7, -1, -1
4526 Xdecor_5, TRUE, FALSE,
4527 EL_EMC_WALL_5, -1, -1
4530 Xdecor_6, TRUE, FALSE,
4531 EL_EMC_WALL_9, -1, -1
4534 Xdecor_7, TRUE, FALSE,
4535 EL_EMC_WALL_10, -1, -1
4538 Xdecor_8, TRUE, FALSE,
4539 EL_EMC_WALL_1, -1, -1
4542 Xdecor_9, TRUE, FALSE,
4543 EL_EMC_WALL_2, -1, -1
4546 Xdecor_10, TRUE, FALSE,
4547 EL_EMC_WALL_3, -1, -1
4550 Xdecor_11, TRUE, FALSE,
4551 EL_EMC_WALL_11, -1, -1
4554 Xdecor_12, TRUE, FALSE,
4555 EL_EMC_WALL_12, -1, -1
4558 Xalpha_0, TRUE, FALSE,
4559 EL_CHAR('0'), -1, -1
4562 Xalpha_1, TRUE, FALSE,
4563 EL_CHAR('1'), -1, -1
4566 Xalpha_2, TRUE, FALSE,
4567 EL_CHAR('2'), -1, -1
4570 Xalpha_3, TRUE, FALSE,
4571 EL_CHAR('3'), -1, -1
4574 Xalpha_4, TRUE, FALSE,
4575 EL_CHAR('4'), -1, -1
4578 Xalpha_5, TRUE, FALSE,
4579 EL_CHAR('5'), -1, -1
4582 Xalpha_6, TRUE, FALSE,
4583 EL_CHAR('6'), -1, -1
4586 Xalpha_7, TRUE, FALSE,
4587 EL_CHAR('7'), -1, -1
4590 Xalpha_8, TRUE, FALSE,
4591 EL_CHAR('8'), -1, -1
4594 Xalpha_9, TRUE, FALSE,
4595 EL_CHAR('9'), -1, -1
4598 Xalpha_excla, TRUE, FALSE,
4599 EL_CHAR('!'), -1, -1
4602 Xalpha_quote, TRUE, FALSE,
4603 EL_CHAR('"'), -1, -1
4606 Xalpha_comma, TRUE, FALSE,
4607 EL_CHAR(','), -1, -1
4610 Xalpha_minus, TRUE, FALSE,
4611 EL_CHAR('-'), -1, -1
4614 Xalpha_perio, TRUE, FALSE,
4615 EL_CHAR('.'), -1, -1
4618 Xalpha_colon, TRUE, FALSE,
4619 EL_CHAR(':'), -1, -1
4622 Xalpha_quest, TRUE, FALSE,
4623 EL_CHAR('?'), -1, -1
4626 Xalpha_a, TRUE, FALSE,
4627 EL_CHAR('A'), -1, -1
4630 Xalpha_b, TRUE, FALSE,
4631 EL_CHAR('B'), -1, -1
4634 Xalpha_c, TRUE, FALSE,
4635 EL_CHAR('C'), -1, -1
4638 Xalpha_d, TRUE, FALSE,
4639 EL_CHAR('D'), -1, -1
4642 Xalpha_e, TRUE, FALSE,
4643 EL_CHAR('E'), -1, -1
4646 Xalpha_f, TRUE, FALSE,
4647 EL_CHAR('F'), -1, -1
4650 Xalpha_g, TRUE, FALSE,
4651 EL_CHAR('G'), -1, -1
4654 Xalpha_h, TRUE, FALSE,
4655 EL_CHAR('H'), -1, -1
4658 Xalpha_i, TRUE, FALSE,
4659 EL_CHAR('I'), -1, -1
4662 Xalpha_j, TRUE, FALSE,
4663 EL_CHAR('J'), -1, -1
4666 Xalpha_k, TRUE, FALSE,
4667 EL_CHAR('K'), -1, -1
4670 Xalpha_l, TRUE, FALSE,
4671 EL_CHAR('L'), -1, -1
4674 Xalpha_m, TRUE, FALSE,
4675 EL_CHAR('M'), -1, -1
4678 Xalpha_n, TRUE, FALSE,
4679 EL_CHAR('N'), -1, -1
4682 Xalpha_o, TRUE, FALSE,
4683 EL_CHAR('O'), -1, -1
4686 Xalpha_p, TRUE, FALSE,
4687 EL_CHAR('P'), -1, -1
4690 Xalpha_q, TRUE, FALSE,
4691 EL_CHAR('Q'), -1, -1
4694 Xalpha_r, TRUE, FALSE,
4695 EL_CHAR('R'), -1, -1
4698 Xalpha_s, TRUE, FALSE,
4699 EL_CHAR('S'), -1, -1
4702 Xalpha_t, TRUE, FALSE,
4703 EL_CHAR('T'), -1, -1
4706 Xalpha_u, TRUE, FALSE,
4707 EL_CHAR('U'), -1, -1
4710 Xalpha_v, TRUE, FALSE,
4711 EL_CHAR('V'), -1, -1
4714 Xalpha_w, TRUE, FALSE,
4715 EL_CHAR('W'), -1, -1
4718 Xalpha_x, TRUE, FALSE,
4719 EL_CHAR('X'), -1, -1
4722 Xalpha_y, TRUE, FALSE,
4723 EL_CHAR('Y'), -1, -1
4726 Xalpha_z, TRUE, FALSE,
4727 EL_CHAR('Z'), -1, -1
4730 Xalpha_arrow_e, TRUE, FALSE,
4731 EL_CHAR('>'), -1, -1
4734 Xalpha_arrow_w, TRUE, FALSE,
4735 EL_CHAR('<'), -1, -1
4738 Xalpha_copyr, TRUE, FALSE,
4739 EL_CHAR('©'), -1, -1
4743 Xboom_bug, FALSE, FALSE,
4744 EL_BUG, ACTION_EXPLODING, -1
4747 Xboom_bomb, FALSE, FALSE,
4748 EL_BOMB, ACTION_EXPLODING, -1
4751 Xboom_android, FALSE, FALSE,
4752 EL_EMC_ANDROID, ACTION_OTHER, -1
4755 Xboom_1, FALSE, FALSE,
4756 EL_DEFAULT, ACTION_EXPLODING, -1
4759 Xboom_2, FALSE, FALSE,
4760 EL_DEFAULT, ACTION_EXPLODING, -1
4763 Znormal, FALSE, FALSE,
4767 Zdynamite, FALSE, FALSE,
4771 Zplayer, FALSE, FALSE,
4775 ZBORDER, FALSE, FALSE,
4785 static struct Mapping_EM_to_RND_player
4794 em_player_mapping_list[] =
4798 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4802 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4806 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4810 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4814 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4818 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4822 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4826 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4830 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4834 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4838 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4842 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4846 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4850 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4854 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4858 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4862 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4866 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4870 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4874 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4878 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4882 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4886 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4890 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4894 EL_PLAYER_1, ACTION_DEFAULT, -1,
4898 EL_PLAYER_2, ACTION_DEFAULT, -1,
4902 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4906 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4910 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4914 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4918 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4922 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4926 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4930 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4934 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4938 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4942 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4946 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4950 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4954 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4958 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4962 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4966 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4970 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4974 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4978 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4982 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4986 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4990 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4994 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
4998 EL_PLAYER_3, ACTION_DEFAULT, -1,
5002 EL_PLAYER_4, ACTION_DEFAULT, -1,
5011 int map_element_RND_to_EM(int element_rnd)
5013 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5014 static boolean mapping_initialized = FALSE;
5016 if (!mapping_initialized)
5020 /* return "Xalpha_quest" for all undefined elements in mapping array */
5021 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5022 mapping_RND_to_EM[i] = Xalpha_quest;
5024 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5025 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5026 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5027 em_object_mapping_list[i].element_em;
5029 mapping_initialized = TRUE;
5032 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5033 return mapping_RND_to_EM[element_rnd];
5035 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5040 int map_element_EM_to_RND(int element_em)
5042 static unsigned short mapping_EM_to_RND[TILE_MAX];
5043 static boolean mapping_initialized = FALSE;
5045 if (!mapping_initialized)
5049 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5050 for (i = 0; i < TILE_MAX; i++)
5051 mapping_EM_to_RND[i] = EL_UNKNOWN;
5053 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5054 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5055 em_object_mapping_list[i].element_rnd;
5057 mapping_initialized = TRUE;
5060 if (element_em >= 0 && element_em < TILE_MAX)
5061 return mapping_EM_to_RND[element_em];
5063 Error(ERR_WARN, "invalid EM level element %d", element_em);
5068 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5070 struct LevelInfo_EM *level_em = level->native_em_level;
5071 struct LEVEL *lev = level_em->lev;
5074 for (i = 0; i < TILE_MAX; i++)
5075 lev->android_array[i] = Xblank;
5077 for (i = 0; i < level->num_android_clone_elements; i++)
5079 int element_rnd = level->android_clone_element[i];
5080 int element_em = map_element_RND_to_EM(element_rnd);
5082 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5083 if (em_object_mapping_list[j].element_rnd == element_rnd)
5084 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5088 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5090 struct LevelInfo_EM *level_em = level->native_em_level;
5091 struct LEVEL *lev = level_em->lev;
5094 level->num_android_clone_elements = 0;
5096 for (i = 0; i < TILE_MAX; i++)
5098 int element_em = lev->android_array[i];
5100 boolean element_found = FALSE;
5102 if (element_em == Xblank)
5105 element_rnd = map_element_EM_to_RND(element_em);
5107 for (j = 0; j < level->num_android_clone_elements; j++)
5108 if (level->android_clone_element[j] == element_rnd)
5109 element_found = TRUE;
5113 level->android_clone_element[level->num_android_clone_elements++] =
5116 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5121 if (level->num_android_clone_elements == 0)
5123 level->num_android_clone_elements = 1;
5124 level->android_clone_element[0] = EL_EMPTY;
5128 int map_direction_RND_to_EM(int direction)
5130 return (direction == MV_UP ? 0 :
5131 direction == MV_RIGHT ? 1 :
5132 direction == MV_DOWN ? 2 :
5133 direction == MV_LEFT ? 3 :
5137 int map_direction_EM_to_RND(int direction)
5139 return (direction == 0 ? MV_UP :
5140 direction == 1 ? MV_RIGHT :
5141 direction == 2 ? MV_DOWN :
5142 direction == 3 ? MV_LEFT :
5146 int get_next_element(int element)
5150 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5151 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5152 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5153 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5154 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5155 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5156 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5158 default: return element;
5163 int el_act_dir2img(int element, int action, int direction)
5165 element = GFX_ELEMENT(element);
5167 if (direction == MV_NONE)
5168 return element_info[element].graphic[action];
5170 direction = MV_DIR_TO_BIT(direction);
5172 return element_info[element].direction_graphic[action][direction];
5175 int el_act_dir2img(int element, int action, int direction)
5177 element = GFX_ELEMENT(element);
5178 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5180 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5181 return element_info[element].direction_graphic[action][direction];
5186 static int el_act_dir2crm(int element, int action, int direction)
5188 element = GFX_ELEMENT(element);
5190 if (direction == MV_NONE)
5191 return element_info[element].crumbled[action];
5193 direction = MV_DIR_TO_BIT(direction);
5195 return element_info[element].direction_crumbled[action][direction];
5198 static int el_act_dir2crm(int element, int action, int direction)
5200 element = GFX_ELEMENT(element);
5201 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5203 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5204 return element_info[element].direction_crumbled[action][direction];
5208 int el_act2img(int element, int action)
5210 element = GFX_ELEMENT(element);
5212 return element_info[element].graphic[action];
5215 int el_act2crm(int element, int action)
5217 element = GFX_ELEMENT(element);
5219 return element_info[element].crumbled[action];
5222 int el_dir2img(int element, int direction)
5224 element = GFX_ELEMENT(element);
5226 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5229 int el2baseimg(int element)
5231 return element_info[element].graphic[ACTION_DEFAULT];
5234 int el2img(int element)
5236 element = GFX_ELEMENT(element);
5238 return element_info[element].graphic[ACTION_DEFAULT];
5241 int el2edimg(int element)
5243 element = GFX_ELEMENT(element);
5245 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5248 int el2preimg(int element)
5250 element = GFX_ELEMENT(element);
5252 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5255 int font2baseimg(int font_nr)
5257 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5261 void setCenteredPlayerNr_EM(int centered_player_nr)
5263 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5266 int getCenteredPlayerNr_EM()
5269 if (game.centered_player_nr_next >= 0 &&
5270 !native_em_level.ply[game.centered_player_nr_next]->alive)
5271 game.centered_player_nr_next = game.centered_player_nr;
5274 if (game.centered_player_nr != game.centered_player_nr_next)
5275 game.centered_player_nr = game.centered_player_nr_next;
5277 return game.centered_player_nr;
5280 void setSetCenteredPlayer_EM(boolean set_centered_player)
5282 game.set_centered_player = set_centered_player;
5285 boolean getSetCenteredPlayer_EM()
5287 return game.set_centered_player;
5291 int getNumActivePlayers_EM()
5293 int num_players = 0;
5299 for (i = 0; i < MAX_PLAYERS; i++)
5300 if (tape.player_participates[i])
5307 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5309 int game_frame_delay_value;
5311 game_frame_delay_value =
5312 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5313 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5316 if (tape.playing && tape.warp_forward && !tape.pausing)
5317 game_frame_delay_value = 0;
5319 return game_frame_delay_value;
5323 unsigned int InitRND(long seed)
5325 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5326 return InitEngineRND_EM(seed);
5328 return InitEngineRND(seed);
5331 void InitGraphicInfo_EM(void)
5333 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5334 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5338 int num_em_gfx_errors = 0;
5340 if (graphic_info_em_object[0][0].bitmap == NULL)
5342 /* EM graphics not yet initialized in em_open_all() */
5347 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5350 /* always start with reliable default values */
5351 for (i = 0; i < TILE_MAX; i++)
5353 object_mapping[i].element_rnd = EL_UNKNOWN;
5354 object_mapping[i].is_backside = FALSE;
5355 object_mapping[i].action = ACTION_DEFAULT;
5356 object_mapping[i].direction = MV_NONE;
5359 /* always start with reliable default values */
5360 for (p = 0; p < MAX_PLAYERS; p++)
5362 for (i = 0; i < SPR_MAX; i++)
5364 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5365 player_mapping[p][i].action = ACTION_DEFAULT;
5366 player_mapping[p][i].direction = MV_NONE;
5370 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5372 int e = em_object_mapping_list[i].element_em;
5374 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5375 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5377 if (em_object_mapping_list[i].action != -1)
5378 object_mapping[e].action = em_object_mapping_list[i].action;
5380 if (em_object_mapping_list[i].direction != -1)
5381 object_mapping[e].direction =
5382 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5385 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5387 int a = em_player_mapping_list[i].action_em;
5388 int p = em_player_mapping_list[i].player_nr;
5390 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5392 if (em_player_mapping_list[i].action != -1)
5393 player_mapping[p][a].action = em_player_mapping_list[i].action;
5395 if (em_player_mapping_list[i].direction != -1)
5396 player_mapping[p][a].direction =
5397 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5400 for (i = 0; i < TILE_MAX; i++)
5402 int element = object_mapping[i].element_rnd;
5403 int action = object_mapping[i].action;
5404 int direction = object_mapping[i].direction;
5405 boolean is_backside = object_mapping[i].is_backside;
5406 boolean action_removing = (action == ACTION_DIGGING ||
5407 action == ACTION_SNAPPING ||
5408 action == ACTION_COLLECTING);
5409 boolean action_exploding = ((action == ACTION_EXPLODING ||
5410 action == ACTION_SMASHED_BY_ROCK ||
5411 action == ACTION_SMASHED_BY_SPRING) &&
5412 element != EL_DIAMOND);
5413 boolean action_active = (action == ACTION_ACTIVE);
5414 boolean action_other = (action == ACTION_OTHER);
5416 for (j = 0; j < 8; j++)
5418 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5419 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5421 i == Xdrip_stretch ? element :
5422 i == Xdrip_stretchB ? element :
5423 i == Ydrip_s1 ? element :
5424 i == Ydrip_s1B ? element :
5425 i == Xball_1B ? element :
5426 i == Xball_2 ? element :
5427 i == Xball_2B ? element :
5428 i == Yball_eat ? element :
5429 i == Ykey_1_eat ? element :
5430 i == Ykey_2_eat ? element :
5431 i == Ykey_3_eat ? element :
5432 i == Ykey_4_eat ? element :
5433 i == Ykey_5_eat ? element :
5434 i == Ykey_6_eat ? element :
5435 i == Ykey_7_eat ? element :
5436 i == Ykey_8_eat ? element :
5437 i == Ylenses_eat ? element :
5438 i == Ymagnify_eat ? element :
5439 i == Ygrass_eat ? element :
5440 i == Ydirt_eat ? element :
5441 i == Yemerald_stone ? EL_EMERALD :
5442 i == Ydiamond_stone ? EL_ROCK :
5443 i == Xsand_stonein_1 ? element :
5444 i == Xsand_stonein_2 ? element :
5445 i == Xsand_stonein_3 ? element :
5446 i == Xsand_stonein_4 ? element :
5447 is_backside ? EL_EMPTY :
5448 action_removing ? EL_EMPTY :
5450 int effective_action = (j < 7 ? action :
5451 i == Xdrip_stretch ? action :
5452 i == Xdrip_stretchB ? action :
5453 i == Ydrip_s1 ? action :
5454 i == Ydrip_s1B ? action :
5455 i == Xball_1B ? action :
5456 i == Xball_2 ? action :
5457 i == Xball_2B ? action :
5458 i == Yball_eat ? action :
5459 i == Ykey_1_eat ? action :
5460 i == Ykey_2_eat ? action :
5461 i == Ykey_3_eat ? action :
5462 i == Ykey_4_eat ? action :
5463 i == Ykey_5_eat ? action :
5464 i == Ykey_6_eat ? action :
5465 i == Ykey_7_eat ? action :
5466 i == Ykey_8_eat ? action :
5467 i == Ylenses_eat ? action :
5468 i == Ymagnify_eat ? action :
5469 i == Ygrass_eat ? action :
5470 i == Ydirt_eat ? action :
5471 i == Xsand_stonein_1 ? action :
5472 i == Xsand_stonein_2 ? action :
5473 i == Xsand_stonein_3 ? action :
5474 i == Xsand_stonein_4 ? action :
5475 i == Xsand_stoneout_1 ? action :
5476 i == Xsand_stoneout_2 ? action :
5477 i == Xboom_android ? ACTION_EXPLODING :
5478 action_exploding ? ACTION_EXPLODING :
5479 action_active ? action :
5480 action_other ? action :
5482 int graphic = (el_act_dir2img(effective_element, effective_action,
5484 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5486 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5487 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5488 boolean has_action_graphics = (graphic != base_graphic);
5489 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5490 struct GraphicInfo *g = &graphic_info[graphic];
5491 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5494 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5495 boolean special_animation = (action != ACTION_DEFAULT &&
5496 g->anim_frames == 3 &&
5497 g->anim_delay == 2 &&
5498 g->anim_mode & ANIM_LINEAR);
5499 int sync_frame = (i == Xdrip_stretch ? 7 :
5500 i == Xdrip_stretchB ? 7 :
5501 i == Ydrip_s2 ? j + 8 :
5502 i == Ydrip_s2B ? j + 8 :
5511 i == Xfake_acid_1 ? 0 :
5512 i == Xfake_acid_2 ? 10 :
5513 i == Xfake_acid_3 ? 20 :
5514 i == Xfake_acid_4 ? 30 :
5515 i == Xfake_acid_5 ? 40 :
5516 i == Xfake_acid_6 ? 50 :
5517 i == Xfake_acid_7 ? 60 :
5518 i == Xfake_acid_8 ? 70 :
5520 i == Xball_2B ? j + 8 :
5521 i == Yball_eat ? j + 1 :
5522 i == Ykey_1_eat ? j + 1 :
5523 i == Ykey_2_eat ? j + 1 :
5524 i == Ykey_3_eat ? j + 1 :
5525 i == Ykey_4_eat ? j + 1 :
5526 i == Ykey_5_eat ? j + 1 :
5527 i == Ykey_6_eat ? j + 1 :
5528 i == Ykey_7_eat ? j + 1 :
5529 i == Ykey_8_eat ? j + 1 :
5530 i == Ylenses_eat ? j + 1 :
5531 i == Ymagnify_eat ? j + 1 :
5532 i == Ygrass_eat ? j + 1 :
5533 i == Ydirt_eat ? j + 1 :
5534 i == Xamoeba_1 ? 0 :
5535 i == Xamoeba_2 ? 1 :
5536 i == Xamoeba_3 ? 2 :
5537 i == Xamoeba_4 ? 3 :
5538 i == Xamoeba_5 ? 0 :
5539 i == Xamoeba_6 ? 1 :
5540 i == Xamoeba_7 ? 2 :
5541 i == Xamoeba_8 ? 3 :
5542 i == Xexit_2 ? j + 8 :
5543 i == Xexit_3 ? j + 16 :
5544 i == Xdynamite_1 ? 0 :
5545 i == Xdynamite_2 ? 8 :
5546 i == Xdynamite_3 ? 16 :
5547 i == Xdynamite_4 ? 24 :
5548 i == Xsand_stonein_1 ? j + 1 :
5549 i == Xsand_stonein_2 ? j + 9 :
5550 i == Xsand_stonein_3 ? j + 17 :
5551 i == Xsand_stonein_4 ? j + 25 :
5552 i == Xsand_stoneout_1 && j == 0 ? 0 :
5553 i == Xsand_stoneout_1 && j == 1 ? 0 :
5554 i == Xsand_stoneout_1 && j == 2 ? 1 :
5555 i == Xsand_stoneout_1 && j == 3 ? 2 :
5556 i == Xsand_stoneout_1 && j == 4 ? 2 :
5557 i == Xsand_stoneout_1 && j == 5 ? 3 :
5558 i == Xsand_stoneout_1 && j == 6 ? 4 :
5559 i == Xsand_stoneout_1 && j == 7 ? 4 :
5560 i == Xsand_stoneout_2 && j == 0 ? 5 :
5561 i == Xsand_stoneout_2 && j == 1 ? 6 :
5562 i == Xsand_stoneout_2 && j == 2 ? 7 :
5563 i == Xsand_stoneout_2 && j == 3 ? 8 :
5564 i == Xsand_stoneout_2 && j == 4 ? 9 :
5565 i == Xsand_stoneout_2 && j == 5 ? 11 :
5566 i == Xsand_stoneout_2 && j == 6 ? 13 :
5567 i == Xsand_stoneout_2 && j == 7 ? 15 :
5568 i == Xboom_bug && j == 1 ? 2 :
5569 i == Xboom_bug && j == 2 ? 2 :
5570 i == Xboom_bug && j == 3 ? 4 :
5571 i == Xboom_bug && j == 4 ? 4 :
5572 i == Xboom_bug && j == 5 ? 2 :
5573 i == Xboom_bug && j == 6 ? 2 :
5574 i == Xboom_bug && j == 7 ? 0 :
5575 i == Xboom_bomb && j == 1 ? 2 :
5576 i == Xboom_bomb && j == 2 ? 2 :
5577 i == Xboom_bomb && j == 3 ? 4 :
5578 i == Xboom_bomb && j == 4 ? 4 :
5579 i == Xboom_bomb && j == 5 ? 2 :
5580 i == Xboom_bomb && j == 6 ? 2 :
5581 i == Xboom_bomb && j == 7 ? 0 :
5582 i == Xboom_android && j == 7 ? 6 :
5583 i == Xboom_1 && j == 1 ? 2 :
5584 i == Xboom_1 && j == 2 ? 2 :
5585 i == Xboom_1 && j == 3 ? 4 :
5586 i == Xboom_1 && j == 4 ? 4 :
5587 i == Xboom_1 && j == 5 ? 6 :
5588 i == Xboom_1 && j == 6 ? 6 :
5589 i == Xboom_1 && j == 7 ? 8 :
5590 i == Xboom_2 && j == 0 ? 8 :
5591 i == Xboom_2 && j == 1 ? 8 :
5592 i == Xboom_2 && j == 2 ? 10 :
5593 i == Xboom_2 && j == 3 ? 10 :
5594 i == Xboom_2 && j == 4 ? 10 :
5595 i == Xboom_2 && j == 5 ? 12 :
5596 i == Xboom_2 && j == 6 ? 12 :
5597 i == Xboom_2 && j == 7 ? 12 :
5598 special_animation && j == 4 ? 3 :
5599 effective_action != action ? 0 :
5603 Bitmap *debug_bitmap = g_em->bitmap;
5604 int debug_src_x = g_em->src_x;
5605 int debug_src_y = g_em->src_y;
5608 int frame = getAnimationFrame(g->anim_frames,
5611 g->anim_start_frame,
5614 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5615 g->double_movement && is_backside);
5617 g_em->bitmap = src_bitmap;
5618 g_em->src_x = src_x;
5619 g_em->src_y = src_y;
5620 g_em->src_offset_x = 0;
5621 g_em->src_offset_y = 0;
5622 g_em->dst_offset_x = 0;
5623 g_em->dst_offset_y = 0;
5624 g_em->width = TILEX;
5625 g_em->height = TILEY;
5627 g_em->crumbled_bitmap = NULL;
5628 g_em->crumbled_src_x = 0;
5629 g_em->crumbled_src_y = 0;
5630 g_em->crumbled_border_size = 0;
5632 g_em->has_crumbled_graphics = FALSE;
5633 g_em->preserve_background = FALSE;
5636 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5637 printf("::: empty crumbled: %d [%s], %d, %d\n",
5638 effective_element, element_info[effective_element].token_name,
5639 effective_action, direction);
5642 /* if element can be crumbled, but certain action graphics are just empty
5643 space (like snapping sand with the original R'n'D graphics), do not
5644 treat these empty space graphics as crumbled graphics in EMC engine */
5645 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5647 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5649 g_em->has_crumbled_graphics = TRUE;
5650 g_em->crumbled_bitmap = src_bitmap;
5651 g_em->crumbled_src_x = src_x;
5652 g_em->crumbled_src_y = src_y;
5653 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5657 if (element == EL_ROCK &&
5658 effective_action == ACTION_FILLING)
5659 printf("::: has_action_graphics == %d\n", has_action_graphics);
5662 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5663 effective_action == ACTION_MOVING ||
5664 effective_action == ACTION_PUSHING ||
5665 effective_action == ACTION_EATING)) ||
5666 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5667 effective_action == ACTION_EMPTYING)))
5670 (effective_action == ACTION_FALLING ||
5671 effective_action == ACTION_FILLING ||
5672 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5673 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5674 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5675 int num_steps = (i == Ydrip_s1 ? 16 :
5676 i == Ydrip_s1B ? 16 :
5677 i == Ydrip_s2 ? 16 :
5678 i == Ydrip_s2B ? 16 :
5679 i == Xsand_stonein_1 ? 32 :
5680 i == Xsand_stonein_2 ? 32 :
5681 i == Xsand_stonein_3 ? 32 :
5682 i == Xsand_stonein_4 ? 32 :
5683 i == Xsand_stoneout_1 ? 16 :
5684 i == Xsand_stoneout_2 ? 16 : 8);
5685 int cx = ABS(dx) * (TILEX / num_steps);
5686 int cy = ABS(dy) * (TILEY / num_steps);
5687 int step_frame = (i == Ydrip_s2 ? j + 8 :
5688 i == Ydrip_s2B ? j + 8 :
5689 i == Xsand_stonein_2 ? j + 8 :
5690 i == Xsand_stonein_3 ? j + 16 :
5691 i == Xsand_stonein_4 ? j + 24 :
5692 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5693 int step = (is_backside ? step_frame : num_steps - step_frame);
5695 if (is_backside) /* tile where movement starts */
5697 if (dx < 0 || dy < 0)
5699 g_em->src_offset_x = cx * step;
5700 g_em->src_offset_y = cy * step;
5704 g_em->dst_offset_x = cx * step;
5705 g_em->dst_offset_y = cy * step;
5708 else /* tile where movement ends */
5710 if (dx < 0 || dy < 0)
5712 g_em->dst_offset_x = cx * step;
5713 g_em->dst_offset_y = cy * step;
5717 g_em->src_offset_x = cx * step;
5718 g_em->src_offset_y = cy * step;
5722 g_em->width = TILEX - cx * step;
5723 g_em->height = TILEY - cy * step;
5727 /* create unique graphic identifier to decide if tile must be redrawn */
5728 /* bit 31 - 16 (16 bit): EM style graphic
5729 bit 15 - 12 ( 4 bit): EM style frame
5730 bit 11 - 6 ( 6 bit): graphic width
5731 bit 5 - 0 ( 6 bit): graphic height */
5732 g_em->unique_identifier =
5733 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5735 /* create unique graphic identifier to decide if tile must be redrawn */
5736 /* bit 31 - 16 (16 bit): EM style element
5737 bit 15 - 12 ( 4 bit): EM style frame
5738 bit 11 - 6 ( 6 bit): graphic width
5739 bit 5 - 0 ( 6 bit): graphic height */
5740 g_em->unique_identifier =
5741 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5745 if (effective_element == EL_ROCK)
5746 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5747 effective_action, j, graphic, frame, g_em->unique_identifier);
5753 /* skip check for EMC elements not contained in original EMC artwork */
5754 if (element == EL_EMC_FAKE_ACID)
5758 if (g_em->bitmap != debug_bitmap ||
5759 g_em->src_x != debug_src_x ||
5760 g_em->src_y != debug_src_y ||
5761 g_em->src_offset_x != 0 ||
5762 g_em->src_offset_y != 0 ||
5763 g_em->dst_offset_x != 0 ||
5764 g_em->dst_offset_y != 0 ||
5765 g_em->width != TILEX ||
5766 g_em->height != TILEY)
5768 static int last_i = -1;
5776 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5777 i, element, element_info[element].token_name,
5778 element_action_info[effective_action].suffix, direction);
5780 if (element != effective_element)
5781 printf(" [%d ('%s')]",
5783 element_info[effective_element].token_name);
5787 if (g_em->bitmap != debug_bitmap)
5788 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5789 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5791 if (g_em->src_x != debug_src_x ||
5792 g_em->src_y != debug_src_y)
5793 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5794 j, (is_backside ? 'B' : 'F'),
5795 g_em->src_x, g_em->src_y,
5796 g_em->src_x / 32, g_em->src_y / 32,
5797 debug_src_x, debug_src_y,
5798 debug_src_x / 32, debug_src_y / 32);
5800 if (g_em->src_offset_x != 0 ||
5801 g_em->src_offset_y != 0 ||
5802 g_em->dst_offset_x != 0 ||
5803 g_em->dst_offset_y != 0)
5804 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5806 g_em->src_offset_x, g_em->src_offset_y,
5807 g_em->dst_offset_x, g_em->dst_offset_y);
5809 if (g_em->width != TILEX ||
5810 g_em->height != TILEY)
5811 printf(" %d (%d): size %d,%d should be %d,%d\n",
5813 g_em->width, g_em->height, TILEX, TILEY);
5815 num_em_gfx_errors++;
5822 for (i = 0; i < TILE_MAX; i++)
5824 for (j = 0; j < 8; j++)
5826 int element = object_mapping[i].element_rnd;
5827 int action = object_mapping[i].action;
5828 int direction = object_mapping[i].direction;
5829 boolean is_backside = object_mapping[i].is_backside;
5831 int graphic_action = el_act_dir2img(element, action, direction);
5832 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5834 int graphic_action = element_info[element].graphic[action];
5835 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5838 if ((action == ACTION_SMASHED_BY_ROCK ||
5839 action == ACTION_SMASHED_BY_SPRING ||
5840 action == ACTION_EATING) &&
5841 graphic_action == graphic_default)
5843 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5844 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5845 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5846 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5849 /* no separate animation for "smashed by rock" -- use rock instead */
5850 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5851 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5853 g_em->bitmap = g_xx->bitmap;
5854 g_em->src_x = g_xx->src_x;
5855 g_em->src_y = g_xx->src_y;
5856 g_em->src_offset_x = g_xx->src_offset_x;
5857 g_em->src_offset_y = g_xx->src_offset_y;
5858 g_em->dst_offset_x = g_xx->dst_offset_x;
5859 g_em->dst_offset_y = g_xx->dst_offset_y;
5860 g_em->width = g_xx->width;
5861 g_em->height = g_xx->height;
5863 g_em->unique_identifier = g_xx->unique_identifier;
5867 g_em->preserve_background = TRUE;
5872 for (p = 0; p < MAX_PLAYERS; p++)
5874 for (i = 0; i < SPR_MAX; i++)
5876 int element = player_mapping[p][i].element_rnd;
5877 int action = player_mapping[p][i].action;
5878 int direction = player_mapping[p][i].direction;
5880 for (j = 0; j < 8; j++)
5882 int effective_element = element;
5883 int effective_action = action;
5884 int graphic = (direction == MV_NONE ?
5885 el_act2img(effective_element, effective_action) :
5886 el_act_dir2img(effective_element, effective_action,
5888 struct GraphicInfo *g = &graphic_info[graphic];
5889 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5895 Bitmap *debug_bitmap = g_em->bitmap;
5896 int debug_src_x = g_em->src_x;
5897 int debug_src_y = g_em->src_y;
5900 int frame = getAnimationFrame(g->anim_frames,
5903 g->anim_start_frame,
5906 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5908 g_em->bitmap = src_bitmap;
5909 g_em->src_x = src_x;
5910 g_em->src_y = src_y;
5911 g_em->src_offset_x = 0;
5912 g_em->src_offset_y = 0;
5913 g_em->dst_offset_x = 0;
5914 g_em->dst_offset_y = 0;
5915 g_em->width = TILEX;
5916 g_em->height = TILEY;
5921 /* skip check for EMC elements not contained in original EMC artwork */
5922 if (element == EL_PLAYER_3 ||
5923 element == EL_PLAYER_4)
5927 if (g_em->bitmap != debug_bitmap ||
5928 g_em->src_x != debug_src_x ||
5929 g_em->src_y != debug_src_y)
5931 static int last_i = -1;
5939 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5940 p, i, element, element_info[element].token_name,
5941 element_action_info[effective_action].suffix, direction);
5943 if (element != effective_element)
5944 printf(" [%d ('%s')]",
5946 element_info[effective_element].token_name);
5950 if (g_em->bitmap != debug_bitmap)
5951 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5952 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5954 if (g_em->src_x != debug_src_x ||
5955 g_em->src_y != debug_src_y)
5956 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5958 g_em->src_x, g_em->src_y,
5959 g_em->src_x / 32, g_em->src_y / 32,
5960 debug_src_x, debug_src_y,
5961 debug_src_x / 32, debug_src_y / 32);
5963 num_em_gfx_errors++;
5973 printf("::: [%d errors found]\n", num_em_gfx_errors);