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);
247 if (redraw_mask & REDRAW_FIELD)
249 if (game_status != GAME_MODE_PLAYING ||
250 redraw_mask & REDRAW_FROM_BACKBUFFER)
252 BlitBitmap(backbuffer, window,
253 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
257 int fx = FX, fy = FY;
259 if (setup.soft_scrolling)
261 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
262 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
265 if (setup.soft_scrolling ||
266 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
267 ABS(ScreenMovPos) == ScrollStepSize ||
268 redraw_tiles > REDRAWTILES_THRESHOLD)
270 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
274 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
276 (setup.soft_scrolling ?
277 "setup.soft_scrolling" :
278 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
279 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
280 ABS(ScreenGfxPos) == ScrollStepSize ?
281 "ABS(ScreenGfxPos) == ScrollStepSize" :
282 "redraw_tiles > REDRAWTILES_THRESHOLD"));
288 redraw_mask &= ~REDRAW_MAIN;
291 if (redraw_mask & REDRAW_DOORS)
293 if (redraw_mask & REDRAW_DOOR_1)
294 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
296 if (redraw_mask & REDRAW_DOOR_2)
297 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
299 if (redraw_mask & REDRAW_DOOR_3)
300 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
302 redraw_mask &= ~REDRAW_DOORS;
305 if (redraw_mask & REDRAW_MICROLEVEL)
307 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
308 SX, SY + 10 * TILEY);
310 redraw_mask &= ~REDRAW_MICROLEVEL;
313 if (redraw_mask & REDRAW_TILES)
315 for (x = 0; x < SCR_FIELDX; x++)
316 for (y = 0 ; y < SCR_FIELDY; y++)
317 if (redraw[redraw_x1 + x][redraw_y1 + y])
318 BlitBitmap(buffer, window,
319 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
320 SX + x * TILEX, SY + y * TILEY);
323 if (redraw_mask & REDRAW_FPS) /* display frames per second */
328 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
329 if (!global.fps_slowdown)
332 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
333 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
338 for (x = 0; x < MAX_BUF_XSIZE; x++)
339 for (y = 0; y < MAX_BUF_YSIZE; y++)
342 redraw_mask = REDRAW_NONE;
348 long fading_delay = 300;
350 if (setup.fading && (redraw_mask & REDRAW_FIELD))
357 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
360 for (i = 0; i < 2 * FULL_SYSIZE; i++)
362 for (y = 0; y < FULL_SYSIZE; y++)
364 BlitBitmap(backbuffer, window,
365 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
373 for (i = 1; i < FULL_SYSIZE; i+=2)
374 BlitBitmap(backbuffer, window,
375 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
381 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
382 BlitBitmapMasked(backbuffer, window,
383 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
388 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
389 BlitBitmapMasked(backbuffer, window,
390 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
395 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
396 BlitBitmapMasked(backbuffer, window,
397 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
402 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
403 BlitBitmapMasked(backbuffer, window,
404 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
409 redraw_mask &= ~REDRAW_MAIN;
416 void SetMainBackgroundImageIfDefined(int graphic)
418 if (graphic_info[graphic].bitmap)
419 SetMainBackgroundImage(graphic);
422 void SetMainBackgroundImage(int graphic)
424 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
425 graphic_info[graphic].bitmap ?
426 graphic_info[graphic].bitmap :
427 graphic_info[IMG_BACKGROUND].bitmap);
430 void SetDoorBackgroundImage(int graphic)
432 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
433 graphic_info[graphic].bitmap ?
434 graphic_info[graphic].bitmap :
435 graphic_info[IMG_BACKGROUND].bitmap);
438 void DrawBackground(int dst_x, int dst_y, int width, int height)
440 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
442 redraw_mask |= REDRAW_FIELD;
447 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
449 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
451 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
452 SetDrawtoField(DRAW_BUFFERED);
455 SetDrawtoField(DRAW_BACKBUFFER);
457 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
459 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
460 SetDrawtoField(DRAW_DIRECT);
464 void MarkTileDirty(int x, int y)
466 int xx = redraw_x1 + x;
467 int yy = redraw_y1 + y;
472 redraw[xx][yy] = TRUE;
473 redraw_mask |= REDRAW_TILES;
476 void SetBorderElement()
480 BorderElement = EL_EMPTY;
482 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
484 for (x = 0; x < lev_fieldx; x++)
486 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
487 BorderElement = EL_STEELWALL;
489 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
495 void SetRandomAnimationValue(int x, int y)
497 gfx.anim_random_frame = GfxRandom[x][y];
500 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
502 /* animation synchronized with global frame counter, not move position */
503 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
504 sync_frame = FrameCounter;
506 return getAnimationFrame(graphic_info[graphic].anim_frames,
507 graphic_info[graphic].anim_delay,
508 graphic_info[graphic].anim_mode,
509 graphic_info[graphic].anim_start_frame,
513 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
514 int *x, int *y, boolean get_backside)
516 struct GraphicInfo *g = &graphic_info[graphic];
517 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
518 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
522 if (g->offset_y == 0) /* frames are ordered horizontally */
524 int max_width = g->anim_frames_per_line * g->width;
525 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
527 *x = pos % max_width;
528 *y = src_y % g->height + pos / max_width * g->height;
530 else if (g->offset_x == 0) /* frames are ordered vertically */
532 int max_height = g->anim_frames_per_line * g->height;
533 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
535 *x = src_x % g->width + pos / max_height * g->width;
536 *y = pos % max_height;
538 else /* frames are ordered diagonally */
540 *x = src_x + frame * g->offset_x;
541 *y = src_y + frame * g->offset_y;
545 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
547 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
550 void DrawGraphic(int x, int y, int graphic, int frame)
553 if (!IN_SCR_FIELD(x, y))
555 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
556 printf("DrawGraphic(): This should never happen!\n");
561 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
565 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
571 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
572 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
575 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
578 if (!IN_SCR_FIELD(x, y))
580 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
581 printf("DrawGraphicThruMask(): This should never happen!\n");
586 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
591 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
597 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
599 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
600 dst_x - src_x, dst_y - src_y);
601 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
604 void DrawMiniGraphic(int x, int y, int graphic)
606 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
607 MarkTileDirty(x / 2, y / 2);
610 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
612 struct GraphicInfo *g = &graphic_info[graphic];
614 int mini_starty = g->bitmap->height * 2 / 3;
617 *x = mini_startx + g->src_x / 2;
618 *y = mini_starty + g->src_y / 2;
621 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
626 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
627 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
630 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
631 int graphic, int frame,
632 int cut_mode, int mask_mode)
637 int width = TILEX, height = TILEY;
640 if (dx || dy) /* shifted graphic */
642 if (x < BX1) /* object enters playfield from the left */
649 else if (x > BX2) /* object enters playfield from the right */
655 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
661 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
663 else if (dx) /* general horizontal movement */
664 MarkTileDirty(x + SIGN(dx), y);
666 if (y < BY1) /* object enters playfield from the top */
668 if (cut_mode==CUT_BELOW) /* object completely above top border */
676 else if (y > BY2) /* object enters playfield from the bottom */
682 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
688 else if (dy > 0 && cut_mode == CUT_ABOVE)
690 if (y == BY2) /* object completely above bottom border */
696 MarkTileDirty(x, y + 1);
697 } /* object leaves playfield to the bottom */
698 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
700 else if (dy) /* general vertical movement */
701 MarkTileDirty(x, y + SIGN(dy));
705 if (!IN_SCR_FIELD(x, y))
707 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
708 printf("DrawGraphicShifted(): This should never happen!\n");
713 if (width > 0 && height > 0)
715 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
720 dst_x = FX + x * TILEX + dx;
721 dst_y = FY + y * TILEY + dy;
723 if (mask_mode == USE_MASKING)
725 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
726 dst_x - src_x, dst_y - src_y);
727 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
731 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
738 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
739 int graphic, int frame,
740 int cut_mode, int mask_mode)
745 int width = TILEX, height = TILEY;
748 int x2 = x + SIGN(dx);
749 int y2 = y + SIGN(dy);
750 int anim_frames = graphic_info[graphic].anim_frames;
751 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
752 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
753 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
755 /* re-calculate animation frame for two-tile movement animation */
756 frame = getGraphicAnimationFrame(graphic, sync_frame);
758 /* check if movement start graphic inside screen area and should be drawn */
759 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
761 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
763 dst_x = FX + x1 * TILEX;
764 dst_y = FY + y1 * TILEY;
766 if (mask_mode == USE_MASKING)
768 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
769 dst_x - src_x, dst_y - src_y);
770 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
774 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
777 MarkTileDirty(x1, y1);
780 /* check if movement end graphic inside screen area and should be drawn */
781 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
783 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
785 dst_x = FX + x2 * TILEX;
786 dst_y = FY + y2 * TILEY;
788 if (mask_mode == USE_MASKING)
790 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
791 dst_x - src_x, dst_y - src_y);
792 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
796 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
799 MarkTileDirty(x2, y2);
803 static void DrawGraphicShifted(int x, int y, int dx, int dy,
804 int graphic, int frame,
805 int cut_mode, int mask_mode)
809 DrawGraphic(x, y, graphic, frame);
814 if (graphic_info[graphic].double_movement) /* EM style movement images */
815 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
817 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
820 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
821 int frame, int cut_mode)
823 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
826 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
827 int cut_mode, int mask_mode)
829 int lx = LEVELX(x), ly = LEVELY(y);
833 if (IN_LEV_FIELD(lx, ly))
835 SetRandomAnimationValue(lx, ly);
837 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
838 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
840 /* do not use double (EM style) movement graphic when not moving */
841 if (graphic_info[graphic].double_movement && !dx && !dy)
843 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
844 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
847 else /* border element */
849 graphic = el2img(element);
850 frame = getGraphicAnimationFrame(graphic, -1);
853 if (element == EL_EXPANDABLE_WALL)
855 boolean left_stopped = FALSE, right_stopped = FALSE;
857 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
859 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
860 right_stopped = TRUE;
862 if (left_stopped && right_stopped)
864 else if (left_stopped)
866 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
867 frame = graphic_info[graphic].anim_frames - 1;
869 else if (right_stopped)
871 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
872 frame = graphic_info[graphic].anim_frames - 1;
877 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
878 else if (mask_mode == USE_MASKING)
879 DrawGraphicThruMask(x, y, graphic, frame);
881 DrawGraphic(x, y, graphic, frame);
884 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
885 int cut_mode, int mask_mode)
887 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
888 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
889 cut_mode, mask_mode);
892 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
895 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
898 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
901 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
904 void DrawLevelElementThruMask(int x, int y, int element)
906 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
909 void DrawLevelFieldThruMask(int x, int y)
911 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
914 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
918 int sx = SCREENX(x), sy = SCREENY(y);
920 int width, height, cx, cy, i;
921 int crumbled_border_size = graphic_info[graphic].border_size;
922 static int xy[4][2] =
930 if (!IN_LEV_FIELD(x, y))
933 element = TILE_GFX_ELEMENT(x, y);
935 /* crumble field itself */
936 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
938 if (!IN_SCR_FIELD(sx, sy))
941 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
943 for (i = 0; i < 4; i++)
945 int xx = x + xy[i][0];
946 int yy = y + xy[i][1];
948 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
951 /* check if neighbour field is of same type */
952 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
955 if (i == 1 || i == 2)
957 width = crumbled_border_size;
959 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
965 height = crumbled_border_size;
967 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
970 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
971 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
974 MarkTileDirty(sx, sy);
976 else /* crumble neighbour fields */
978 for (i = 0; i < 4; i++)
980 int xx = x + xy[i][0];
981 int yy = y + xy[i][1];
982 int sxx = sx + xy[i][0];
983 int syy = sy + xy[i][1];
986 if (!IN_LEV_FIELD(xx, yy) ||
987 !IN_SCR_FIELD(sxx, syy) ||
992 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
996 element = TILE_GFX_ELEMENT(xx, yy);
998 if (!GFX_CRUMBLED(element))
1001 if (!IN_LEV_FIELD(xx, yy) ||
1002 !IN_SCR_FIELD(sxx, syy) ||
1003 !GFX_CRUMBLED(Feld[xx][yy]) ||
1009 graphic = el_act2crm(element, ACTION_DEFAULT);
1011 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1013 crumbled_border_size = graphic_info[graphic].border_size;
1015 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1017 if (i == 1 || i == 2)
1019 width = crumbled_border_size;
1021 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1027 height = crumbled_border_size;
1029 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1032 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1033 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1035 MarkTileDirty(sxx, syy);
1040 void DrawLevelFieldCrumbledSand(int x, int y)
1044 if (!IN_LEV_FIELD(x, y))
1048 /* !!! CHECK THIS !!! */
1051 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1052 GFX_CRUMBLED(GfxElement[x][y]))
1055 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1056 GfxElement[x][y] != EL_UNDEFINED &&
1057 GFX_CRUMBLED(GfxElement[x][y]))
1059 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1066 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1068 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1071 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1074 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1077 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1078 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1079 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1080 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1081 int sx = SCREENX(x), sy = SCREENY(y);
1083 DrawGraphic(sx, sy, graphic1, frame1);
1084 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1087 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1089 int sx = SCREENX(x), sy = SCREENY(y);
1090 static int xy[4][2] =
1099 for (i = 0; i < 4; i++)
1101 int xx = x + xy[i][0];
1102 int yy = y + xy[i][1];
1103 int sxx = sx + xy[i][0];
1104 int syy = sy + xy[i][1];
1106 if (!IN_LEV_FIELD(xx, yy) ||
1107 !IN_SCR_FIELD(sxx, syy) ||
1108 !GFX_CRUMBLED(Feld[xx][yy]) ||
1112 DrawLevelField(xx, yy);
1116 static int getBorderElement(int x, int y)
1120 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1121 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1122 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1123 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1124 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1125 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1126 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1128 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1129 int steel_position = (x == -1 && y == -1 ? 0 :
1130 x == lev_fieldx && y == -1 ? 1 :
1131 x == -1 && y == lev_fieldy ? 2 :
1132 x == lev_fieldx && y == lev_fieldy ? 3 :
1133 x == -1 || x == lev_fieldx ? 4 :
1134 y == -1 || y == lev_fieldy ? 5 : 6);
1136 return border[steel_position][steel_type];
1139 void DrawScreenElement(int x, int y, int element)
1141 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1142 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1145 void DrawLevelElement(int x, int y, int element)
1147 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1148 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1151 void DrawScreenField(int x, int y)
1153 int lx = LEVELX(x), ly = LEVELY(y);
1154 int element, content;
1156 if (!IN_LEV_FIELD(lx, ly))
1158 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1161 element = getBorderElement(lx, ly);
1163 DrawScreenElement(x, y, element);
1167 element = Feld[lx][ly];
1168 content = Store[lx][ly];
1170 if (IS_MOVING(lx, ly))
1172 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1173 boolean cut_mode = NO_CUTTING;
1175 if (element == EL_QUICKSAND_EMPTYING ||
1176 element == EL_MAGIC_WALL_EMPTYING ||
1177 element == EL_BD_MAGIC_WALL_EMPTYING ||
1178 element == EL_AMOEBA_DROPPING)
1179 cut_mode = CUT_ABOVE;
1180 else if (element == EL_QUICKSAND_FILLING ||
1181 element == EL_MAGIC_WALL_FILLING ||
1182 element == EL_BD_MAGIC_WALL_FILLING)
1183 cut_mode = CUT_BELOW;
1185 if (cut_mode == CUT_ABOVE)
1186 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1188 DrawScreenElement(x, y, EL_EMPTY);
1191 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1192 else if (cut_mode == NO_CUTTING)
1193 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1195 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1197 if (content == EL_ACID)
1199 int dir = MovDir[lx][ly];
1200 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1201 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1203 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1206 else if (IS_BLOCKED(lx, ly))
1211 boolean cut_mode = NO_CUTTING;
1212 int element_old, content_old;
1214 Blocked2Moving(lx, ly, &oldx, &oldy);
1217 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1218 MovDir[oldx][oldy] == MV_RIGHT);
1220 element_old = Feld[oldx][oldy];
1221 content_old = Store[oldx][oldy];
1223 if (element_old == EL_QUICKSAND_EMPTYING ||
1224 element_old == EL_MAGIC_WALL_EMPTYING ||
1225 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1226 element_old == EL_AMOEBA_DROPPING)
1227 cut_mode = CUT_ABOVE;
1229 DrawScreenElement(x, y, EL_EMPTY);
1232 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1234 else if (cut_mode == NO_CUTTING)
1235 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1238 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1241 else if (IS_DRAWABLE(element))
1242 DrawScreenElement(x, y, element);
1244 DrawScreenElement(x, y, EL_EMPTY);
1247 void DrawLevelField(int x, int y)
1249 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1250 DrawScreenField(SCREENX(x), SCREENY(y));
1251 else if (IS_MOVING(x, y))
1255 Moving2Blocked(x, y, &newx, &newy);
1256 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1257 DrawScreenField(SCREENX(newx), SCREENY(newy));
1259 else if (IS_BLOCKED(x, y))
1263 Blocked2Moving(x, y, &oldx, &oldy);
1264 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1265 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1269 void DrawMiniElement(int x, int y, int element)
1273 graphic = el2edimg(element);
1274 DrawMiniGraphic(x, y, graphic);
1277 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1279 int x = sx + scroll_x, y = sy + scroll_y;
1281 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1282 DrawMiniElement(sx, sy, EL_EMPTY);
1283 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1284 DrawMiniElement(sx, sy, Feld[x][y]);
1286 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1289 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1290 int x, int y, int xsize, int ysize, int font_nr)
1292 int font_width = getFontWidth(font_nr);
1293 int font_height = getFontHeight(font_nr);
1294 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1297 int dst_x = SX + startx + x * font_width;
1298 int dst_y = SY + starty + y * font_height;
1299 int width = graphic_info[graphic].width;
1300 int height = graphic_info[graphic].height;
1301 int inner_width = MAX(width - 2 * font_width, font_width);
1302 int inner_height = MAX(height - 2 * font_height, font_height);
1303 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1304 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1305 boolean draw_masked = graphic_info[graphic].draw_masked;
1307 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1309 if (src_bitmap == NULL || width < font_width || height < font_height)
1311 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1315 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1316 inner_sx + (x - 1) * font_width % inner_width);
1317 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1318 inner_sy + (y - 1) * font_height % inner_height);
1322 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1323 dst_x - src_x, dst_y - src_y);
1324 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1328 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1332 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1334 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1335 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1336 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1337 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1338 boolean no_delay = (tape.warp_forward);
1339 unsigned long anim_delay = 0;
1340 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1341 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1342 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1343 int font_width = getFontWidth(font_nr);
1344 int font_height = getFontHeight(font_nr);
1345 int max_xsize = level.envelope_xsize[envelope_nr];
1346 int max_ysize = level.envelope_ysize[envelope_nr];
1347 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1348 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1349 int xend = max_xsize;
1350 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1351 int xstep = (xstart < xend ? 1 : 0);
1352 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1355 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1357 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1358 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1359 int sx = (SXSIZE - xsize * font_width) / 2;
1360 int sy = (SYSIZE - ysize * font_height) / 2;
1363 SetDrawtoField(DRAW_BUFFERED);
1365 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1367 SetDrawtoField(DRAW_BACKBUFFER);
1369 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1370 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1372 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1373 level.envelope_text[envelope_nr], font_nr, max_xsize,
1374 xsize - 2, ysize - 2, mask_mode);
1376 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1379 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1383 void ShowEnvelope(int envelope_nr)
1385 int element = EL_ENVELOPE_1 + envelope_nr;
1386 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1387 int sound_opening = element_info[element].sound[ACTION_OPENING];
1388 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1389 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1390 boolean no_delay = (tape.warp_forward);
1391 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1392 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1393 int anim_mode = graphic_info[graphic].anim_mode;
1394 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1395 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1397 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1399 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1401 if (anim_mode == ANIM_DEFAULT)
1402 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1404 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1407 Delay(wait_delay_value);
1409 WaitForEventToContinue();
1411 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1413 if (anim_mode != ANIM_NONE)
1414 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1416 if (anim_mode == ANIM_DEFAULT)
1417 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1419 game.envelope_active = FALSE;
1421 SetDrawtoField(DRAW_BUFFERED);
1423 redraw_mask |= REDRAW_FIELD;
1427 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1429 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1430 int mini_startx = src_bitmap->width * 3 / 4;
1431 int mini_starty = src_bitmap->height * 2 / 3;
1432 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1433 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1435 *bitmap = src_bitmap;
1440 void DrawMicroElement(int xpos, int ypos, int element)
1444 int graphic = el2preimg(element);
1446 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1447 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1455 SetDrawBackgroundMask(REDRAW_NONE);
1458 for (x = BX1; x <= BX2; x++)
1459 for (y = BY1; y <= BY2; y++)
1460 DrawScreenField(x, y);
1462 redraw_mask |= REDRAW_FIELD;
1465 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1469 for (x = 0; x < size_x; x++)
1470 for (y = 0; y < size_y; y++)
1471 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1473 redraw_mask |= REDRAW_FIELD;
1476 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1480 DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
1482 if (lev_fieldx < STD_LEV_FIELDX)
1483 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1484 if (lev_fieldy < STD_LEV_FIELDY)
1485 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1487 xpos += MICRO_TILEX;
1488 ypos += MICRO_TILEY;
1490 for (x = -1; x <= STD_LEV_FIELDX; x++)
1492 for (y = -1; y <= STD_LEV_FIELDY; y++)
1494 int lx = from_x + x, ly = from_y + y;
1496 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1497 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1498 level.field[lx][ly]);
1499 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1500 && BorderElement != EL_EMPTY)
1501 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1502 getBorderElement(lx, ly));
1506 redraw_mask |= REDRAW_MICROLEVEL;
1509 #define MICROLABEL_EMPTY 0
1510 #define MICROLABEL_LEVEL_NAME 1
1511 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1512 #define MICROLABEL_LEVEL_AUTHOR 3
1513 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1514 #define MICROLABEL_IMPORTED_FROM 5
1515 #define MICROLABEL_IMPORTED_BY_HEAD 6
1516 #define MICROLABEL_IMPORTED_BY 7
1518 static void DrawMicroLevelLabelExt(int mode)
1520 char label_text[MAX_OUTPUT_LINESIZE + 1];
1521 int max_len_label_text;
1522 int font_nr = FONT_TEXT_2;
1525 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1526 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1527 mode == MICROLABEL_IMPORTED_BY_HEAD)
1528 font_nr = FONT_TEXT_3;
1530 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1532 for (i = 0; i < max_len_label_text; i++)
1533 label_text[i] = ' ';
1534 label_text[max_len_label_text] = '\0';
1536 if (strlen(label_text) > 0)
1538 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1539 int lypos = MICROLABEL2_YPOS;
1541 DrawText(lxpos, lypos, label_text, font_nr);
1545 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1546 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1547 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1548 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1549 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1550 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1551 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1552 max_len_label_text);
1553 label_text[max_len_label_text] = '\0';
1555 if (strlen(label_text) > 0)
1557 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1558 int lypos = MICROLABEL2_YPOS;
1560 DrawText(lxpos, lypos, label_text, font_nr);
1563 redraw_mask |= REDRAW_MICROLEVEL;
1566 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1568 static unsigned long scroll_delay = 0;
1569 static unsigned long label_delay = 0;
1570 static int from_x, from_y, scroll_direction;
1571 static int label_state, label_counter;
1572 int last_game_status = game_status; /* save current game status */
1574 /* force PREVIEW font on preview level */
1575 game_status = GAME_MODE_PSEUDO_PREVIEW;
1579 from_x = from_y = 0;
1580 scroll_direction = MV_RIGHT;
1584 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1585 DrawMicroLevelLabelExt(label_state);
1587 /* initialize delay counters */
1588 DelayReached(&scroll_delay, 0);
1589 DelayReached(&label_delay, 0);
1591 if (leveldir_current->name)
1593 char label_text[MAX_OUTPUT_LINESIZE + 1];
1594 int font_nr = FONT_TEXT_1;
1595 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1598 strncpy(label_text, leveldir_current->name, max_len_label_text);
1599 label_text[max_len_label_text] = '\0';
1601 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1602 lypos = SY + MICROLABEL1_YPOS;
1604 DrawText(lxpos, lypos, label_text, font_nr);
1607 game_status = last_game_status; /* restore current game status */
1612 /* scroll micro level, if needed */
1613 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1614 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1616 switch (scroll_direction)
1622 scroll_direction = MV_UP;
1626 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1629 scroll_direction = MV_DOWN;
1636 scroll_direction = MV_RIGHT;
1640 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1643 scroll_direction = MV_LEFT;
1650 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1653 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1654 /* redraw micro level label, if needed */
1655 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1656 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1657 strcmp(level.author, leveldir_current->name) != 0 &&
1658 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1660 int max_label_counter = 23;
1662 if (leveldir_current->imported_from != NULL &&
1663 strlen(leveldir_current->imported_from) > 0)
1664 max_label_counter += 14;
1665 if (leveldir_current->imported_by != NULL &&
1666 strlen(leveldir_current->imported_by) > 0)
1667 max_label_counter += 14;
1669 label_counter = (label_counter + 1) % max_label_counter;
1670 label_state = (label_counter >= 0 && label_counter <= 7 ?
1671 MICROLABEL_LEVEL_NAME :
1672 label_counter >= 9 && label_counter <= 12 ?
1673 MICROLABEL_LEVEL_AUTHOR_HEAD :
1674 label_counter >= 14 && label_counter <= 21 ?
1675 MICROLABEL_LEVEL_AUTHOR :
1676 label_counter >= 23 && label_counter <= 26 ?
1677 MICROLABEL_IMPORTED_FROM_HEAD :
1678 label_counter >= 28 && label_counter <= 35 ?
1679 MICROLABEL_IMPORTED_FROM :
1680 label_counter >= 37 && label_counter <= 40 ?
1681 MICROLABEL_IMPORTED_BY_HEAD :
1682 label_counter >= 42 && label_counter <= 49 ?
1683 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1685 if (leveldir_current->imported_from == NULL &&
1686 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1687 label_state == MICROLABEL_IMPORTED_FROM))
1688 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1689 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1691 DrawMicroLevelLabelExt(label_state);
1694 game_status = last_game_status; /* restore current game status */
1697 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1698 int graphic, int sync_frame, int mask_mode)
1700 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1702 if (mask_mode == USE_MASKING)
1703 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1705 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1708 inline void DrawGraphicAnimation(int x, int y, int graphic)
1710 int lx = LEVELX(x), ly = LEVELY(y);
1712 if (!IN_SCR_FIELD(x, y))
1715 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1716 graphic, GfxFrame[lx][ly], NO_MASKING);
1717 MarkTileDirty(x, y);
1720 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1722 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1725 void DrawLevelElementAnimation(int x, int y, int element)
1727 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1729 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1732 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1734 int sx = SCREENX(x), sy = SCREENY(y);
1736 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1739 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1742 DrawGraphicAnimation(sx, sy, graphic);
1745 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1746 DrawLevelFieldCrumbledSand(x, y);
1748 if (GFX_CRUMBLED(Feld[x][y]))
1749 DrawLevelFieldCrumbledSand(x, y);
1753 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1755 int sx = SCREENX(x), sy = SCREENY(y);
1758 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1761 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1763 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1766 DrawGraphicAnimation(sx, sy, graphic);
1768 if (GFX_CRUMBLED(element))
1769 DrawLevelFieldCrumbledSand(x, y);
1772 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1774 if (player->use_murphy)
1776 /* this works only because currently only one player can be "murphy" ... */
1777 static int last_horizontal_dir = MV_LEFT;
1778 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1780 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1781 last_horizontal_dir = move_dir;
1783 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1785 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1787 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1793 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1796 static boolean equalGraphics(int graphic1, int graphic2)
1798 struct GraphicInfo *g1 = &graphic_info[graphic1];
1799 struct GraphicInfo *g2 = &graphic_info[graphic2];
1801 return (g1->bitmap == g2->bitmap &&
1802 g1->src_x == g2->src_x &&
1803 g1->src_y == g2->src_y &&
1804 g1->anim_frames == g2->anim_frames &&
1805 g1->anim_delay == g2->anim_delay &&
1806 g1->anim_mode == g2->anim_mode);
1809 void DrawAllPlayers()
1813 for (i = 0; i < MAX_PLAYERS; i++)
1814 if (stored_player[i].active)
1815 DrawPlayer(&stored_player[i]);
1818 void DrawPlayerField(int x, int y)
1820 if (!IS_PLAYER(x, y))
1823 DrawPlayer(PLAYERINFO(x, y));
1826 void DrawPlayer(struct PlayerInfo *player)
1828 int jx = player->jx;
1829 int jy = player->jy;
1830 int move_dir = player->MovDir;
1831 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1832 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1833 int last_jx = (player->is_moving ? jx - dx : jx);
1834 int last_jy = (player->is_moving ? jy - dy : jy);
1835 int next_jx = jx + dx;
1836 int next_jy = jy + dy;
1837 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1838 boolean player_is_opaque = FALSE;
1839 int sx = SCREENX(jx), sy = SCREENY(jy);
1840 int sxx = 0, syy = 0;
1841 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1843 int action = ACTION_DEFAULT;
1844 int last_player_graphic = getPlayerGraphic(player, move_dir);
1845 int last_player_frame = player->Frame;
1849 /* GfxElement[][] is set to the element the player is digging or collecting;
1850 remove also for off-screen player if the player is not moving anymore */
1851 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1852 GfxElement[jx][jy] = EL_UNDEFINED;
1855 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1859 if (!IN_LEV_FIELD(jx, jy))
1861 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1862 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1863 printf("DrawPlayerField(): This should never happen!\n");
1868 if (element == EL_EXPLOSION)
1871 action = (player->is_pushing ? ACTION_PUSHING :
1872 player->is_digging ? ACTION_DIGGING :
1873 player->is_collecting ? ACTION_COLLECTING :
1874 player->is_moving ? ACTION_MOVING :
1875 player->is_snapping ? ACTION_SNAPPING :
1876 player->is_dropping ? ACTION_DROPPING :
1877 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1880 if (player->is_waiting)
1881 move_dir = player->dir_waiting;
1884 InitPlayerGfxAnimation(player, action, move_dir);
1886 /* ----------------------------------------------------------------------- */
1887 /* draw things in the field the player is leaving, if needed */
1888 /* ----------------------------------------------------------------------- */
1890 if (player->is_moving)
1892 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1894 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1896 if (last_element == EL_DYNAMITE_ACTIVE ||
1897 last_element == EL_EM_DYNAMITE_ACTIVE ||
1898 last_element == EL_SP_DISK_RED_ACTIVE)
1899 DrawDynamite(last_jx, last_jy);
1901 DrawLevelFieldThruMask(last_jx, last_jy);
1903 else if (last_element == EL_DYNAMITE_ACTIVE ||
1904 last_element == EL_EM_DYNAMITE_ACTIVE ||
1905 last_element == EL_SP_DISK_RED_ACTIVE)
1906 DrawDynamite(last_jx, last_jy);
1908 DrawLevelField(last_jx, last_jy);
1910 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
1911 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
1914 if (!IN_SCR_FIELD(sx, sy))
1917 if (setup.direct_draw)
1918 SetDrawtoField(DRAW_BUFFERED);
1920 /* ----------------------------------------------------------------------- */
1921 /* draw things behind the player, if needed */
1922 /* ----------------------------------------------------------------------- */
1925 DrawLevelElement(jx, jy, Back[jx][jy]);
1926 else if (IS_ACTIVE_BOMB(element))
1927 DrawLevelElement(jx, jy, EL_EMPTY);
1930 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
1932 int old_element = GfxElement[jx][jy];
1933 int old_graphic = el_act_dir2img(old_element, action, move_dir);
1934 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
1936 if (GFX_CRUMBLED(old_element))
1937 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
1939 DrawGraphic(sx, sy, old_graphic, frame);
1941 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
1942 player_is_opaque = TRUE;
1946 GfxElement[jx][jy] = EL_UNDEFINED;
1948 /* make sure that pushed elements are drawn with correct frame rate */
1949 if (player->is_pushing && player->is_moving)
1950 GfxFrame[jx][jy] = player->StepFrame;
1952 DrawLevelField(jx, jy);
1956 /* ----------------------------------------------------------------------- */
1957 /* draw player himself */
1958 /* ----------------------------------------------------------------------- */
1960 graphic = getPlayerGraphic(player, move_dir);
1962 /* in the case of changed player action or direction, prevent the current
1963 animation frame from being restarted for identical animations */
1964 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
1965 player->Frame = last_player_frame;
1967 frame = getGraphicAnimationFrame(graphic, player->Frame);
1971 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1972 sxx = player->GfxPos;
1974 syy = player->GfxPos;
1977 if (!setup.soft_scrolling && ScreenMovPos)
1980 if (player_is_opaque)
1981 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
1983 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1985 if (SHIELD_ON(player))
1987 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
1988 IMG_SHIELD_NORMAL_ACTIVE);
1989 int frame = getGraphicAnimationFrame(graphic, -1);
1991 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1994 /* ----------------------------------------------------------------------- */
1995 /* draw things the player is pushing, if needed */
1996 /* ----------------------------------------------------------------------- */
1999 printf("::: %d, %d [%d, %d] [%d]\n",
2000 player->is_pushing, player_is_moving, player->GfxAction,
2001 player->is_moving, player_is_moving);
2005 if (player->is_pushing && player->is_moving)
2007 int px = SCREENX(jx), py = SCREENY(jy);
2008 int pxx = (TILEX - ABS(sxx)) * dx;
2009 int pyy = (TILEY - ABS(syy)) * dy;
2014 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2015 element = Feld[next_jx][next_jy];
2017 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2018 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2020 /* draw background element under pushed element (like the Sokoban field) */
2021 if (Back[next_jx][next_jy])
2022 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2024 /* masked drawing is needed for EMC style (double) movement graphics */
2025 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2029 /* ----------------------------------------------------------------------- */
2030 /* draw things in front of player (active dynamite or dynabombs) */
2031 /* ----------------------------------------------------------------------- */
2033 if (IS_ACTIVE_BOMB(element))
2035 graphic = el2img(element);
2036 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2038 if (game.emulation == EMU_SUPAPLEX)
2039 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2041 DrawGraphicThruMask(sx, sy, graphic, frame);
2044 if (player_is_moving && last_element == EL_EXPLOSION)
2046 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2047 GfxElement[last_jx][last_jy] : EL_EMPTY);
2048 int graphic = el_act2img(element, ACTION_EXPLODING);
2049 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2050 int phase = ExplodePhase[last_jx][last_jy] - 1;
2051 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2054 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2057 /* ----------------------------------------------------------------------- */
2058 /* draw elements the player is just walking/passing through/under */
2059 /* ----------------------------------------------------------------------- */
2061 if (player_is_moving)
2063 /* handle the field the player is leaving ... */
2064 if (IS_ACCESSIBLE_INSIDE(last_element))
2065 DrawLevelField(last_jx, last_jy);
2066 else if (IS_ACCESSIBLE_UNDER(last_element))
2067 DrawLevelFieldThruMask(last_jx, last_jy);
2070 /* do not redraw accessible elements if the player is just pushing them */
2071 if (!player_is_moving || !player->is_pushing)
2073 /* ... and the field the player is entering */
2074 if (IS_ACCESSIBLE_INSIDE(element))
2075 DrawLevelField(jx, jy);
2076 else if (IS_ACCESSIBLE_UNDER(element))
2077 DrawLevelFieldThruMask(jx, jy);
2080 if (setup.direct_draw)
2082 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2083 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2084 int x_size = TILEX * (1 + ABS(jx - last_jx));
2085 int y_size = TILEY * (1 + ABS(jy - last_jy));
2087 BlitBitmap(drawto_field, window,
2088 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2089 SetDrawtoField(DRAW_DIRECT);
2092 MarkTileDirty(sx, sy);
2095 /* ------------------------------------------------------------------------- */
2097 void WaitForEventToContinue()
2099 boolean still_wait = TRUE;
2101 /* simulate releasing mouse button over last gadget, if still pressed */
2103 HandleGadgets(-1, -1, 0);
2105 button_status = MB_RELEASED;
2117 case EVENT_BUTTONPRESS:
2118 case EVENT_KEYPRESS:
2122 case EVENT_KEYRELEASE:
2123 ClearPlayerAction();
2127 HandleOtherEvents(&event);
2131 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2138 /* don't eat all CPU time */
2143 #define MAX_REQUEST_LINES 13
2144 #define MAX_REQUEST_LINE_FONT1_LEN 7
2145 #define MAX_REQUEST_LINE_FONT2_LEN 10
2147 boolean Request(char *text, unsigned int req_state)
2149 int mx, my, ty, result = -1;
2150 unsigned int old_door_state;
2151 int last_game_status = game_status; /* save current game status */
2152 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2153 int font_nr = FONT_TEXT_2;
2154 int max_word_len = 0;
2157 for (text_ptr = text; *text_ptr; text_ptr++)
2159 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2161 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2163 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2164 font_nr = FONT_LEVEL_NUMBER;
2170 if (game_status == GAME_MODE_PLAYING &&
2171 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2172 BlitScreenToBitmap_EM(backbuffer);
2174 /* disable deactivated drawing when quick-loading level tape recording */
2175 if (tape.playing && tape.deactivate_display)
2176 TapeDeactivateDisplayOff(TRUE);
2178 SetMouseCursor(CURSOR_DEFAULT);
2180 #if defined(NETWORK_AVALIABLE)
2181 /* pause network game while waiting for request to answer */
2182 if (options.network &&
2183 game_status == GAME_MODE_PLAYING &&
2184 req_state & REQUEST_WAIT_FOR_INPUT)
2185 SendToServer_PausePlaying();
2188 old_door_state = GetDoorState();
2190 /* simulate releasing mouse button over last gadget, if still pressed */
2192 HandleGadgets(-1, -1, 0);
2196 if (old_door_state & DOOR_OPEN_1)
2198 CloseDoor(DOOR_CLOSE_1);
2200 /* save old door content */
2201 BlitBitmap(bitmap_db_door, bitmap_db_door,
2202 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2203 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2206 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2208 /* clear door drawing field */
2209 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2211 /* force DOOR font on preview level */
2212 game_status = GAME_MODE_PSEUDO_DOOR;
2214 /* write text for request */
2215 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2217 char text_line[max_request_line_len + 1];
2223 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2226 if (!tc || tc == ' ')
2237 strncpy(text_line, text, tl);
2240 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2241 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2242 text_line, font_nr);
2244 text += tl + (tc == ' ' ? 1 : 0);
2247 game_status = last_game_status; /* restore current game status */
2249 if (req_state & REQ_ASK)
2251 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2252 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2254 else if (req_state & REQ_CONFIRM)
2256 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2258 else if (req_state & REQ_PLAYER)
2260 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2261 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2262 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2263 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2266 /* copy request gadgets to door backbuffer */
2267 BlitBitmap(drawto, bitmap_db_door,
2268 DX, DY, DXSIZE, DYSIZE,
2269 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2271 OpenDoor(DOOR_OPEN_1);
2273 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2275 SetDrawBackgroundMask(REDRAW_FIELD);
2280 if (game_status != GAME_MODE_MAIN)
2283 button_status = MB_RELEASED;
2285 request_gadget_id = -1;
2287 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2299 case EVENT_BUTTONPRESS:
2300 case EVENT_BUTTONRELEASE:
2301 case EVENT_MOTIONNOTIFY:
2303 if (event.type == EVENT_MOTIONNOTIFY)
2305 if (!PointerInWindow(window))
2306 continue; /* window and pointer are on different screens */
2311 motion_status = TRUE;
2312 mx = ((MotionEvent *) &event)->x;
2313 my = ((MotionEvent *) &event)->y;
2317 motion_status = FALSE;
2318 mx = ((ButtonEvent *) &event)->x;
2319 my = ((ButtonEvent *) &event)->y;
2320 if (event.type == EVENT_BUTTONPRESS)
2321 button_status = ((ButtonEvent *) &event)->button;
2323 button_status = MB_RELEASED;
2326 /* this sets 'request_gadget_id' */
2327 HandleGadgets(mx, my, button_status);
2329 switch(request_gadget_id)
2331 case TOOL_CTRL_ID_YES:
2334 case TOOL_CTRL_ID_NO:
2337 case TOOL_CTRL_ID_CONFIRM:
2338 result = TRUE | FALSE;
2341 case TOOL_CTRL_ID_PLAYER_1:
2344 case TOOL_CTRL_ID_PLAYER_2:
2347 case TOOL_CTRL_ID_PLAYER_3:
2350 case TOOL_CTRL_ID_PLAYER_4:
2361 case EVENT_KEYPRESS:
2362 switch(GetEventKey((KeyEvent *)&event, TRUE))
2375 if (req_state & REQ_PLAYER)
2379 case EVENT_KEYRELEASE:
2380 ClearPlayerAction();
2384 HandleOtherEvents(&event);
2388 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2390 int joy = AnyJoystick();
2392 if (joy & JOY_BUTTON_1)
2394 else if (joy & JOY_BUTTON_2)
2400 /* don't eat all CPU time */
2404 if (game_status != GAME_MODE_MAIN)
2409 if (!(req_state & REQ_STAY_OPEN))
2411 CloseDoor(DOOR_CLOSE_1);
2413 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2414 (req_state & REQ_REOPEN))
2415 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2420 SetDrawBackgroundMask(REDRAW_FIELD);
2422 #if defined(NETWORK_AVALIABLE)
2423 /* continue network game after request */
2424 if (options.network &&
2425 game_status == GAME_MODE_PLAYING &&
2426 req_state & REQUEST_WAIT_FOR_INPUT)
2427 SendToServer_ContinuePlaying();
2430 /* restore deactivated drawing when quick-loading level tape recording */
2431 if (tape.playing && tape.deactivate_display)
2432 TapeDeactivateDisplayOn();
2437 unsigned int OpenDoor(unsigned int door_state)
2439 if (door_state & DOOR_COPY_BACK)
2441 if (door_state & DOOR_OPEN_1)
2442 BlitBitmap(bitmap_db_door, bitmap_db_door,
2443 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2444 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2446 if (door_state & DOOR_OPEN_2)
2447 BlitBitmap(bitmap_db_door, bitmap_db_door,
2448 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2449 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2451 door_state &= ~DOOR_COPY_BACK;
2454 return MoveDoor(door_state);
2457 unsigned int CloseDoor(unsigned int door_state)
2459 unsigned int old_door_state = GetDoorState();
2461 if (!(door_state & DOOR_NO_COPY_BACK))
2463 if (old_door_state & DOOR_OPEN_1)
2464 BlitBitmap(backbuffer, bitmap_db_door,
2465 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2467 if (old_door_state & DOOR_OPEN_2)
2468 BlitBitmap(backbuffer, bitmap_db_door,
2469 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2471 door_state &= ~DOOR_NO_COPY_BACK;
2474 return MoveDoor(door_state);
2477 unsigned int GetDoorState()
2479 return MoveDoor(DOOR_GET_STATE);
2482 unsigned int SetDoorState(unsigned int door_state)
2484 return MoveDoor(door_state | DOOR_SET_STATE);
2487 unsigned int MoveDoor(unsigned int door_state)
2489 static int door1 = DOOR_OPEN_1;
2490 static int door2 = DOOR_CLOSE_2;
2491 unsigned long door_delay = 0;
2492 unsigned long door_delay_value;
2495 if (door_1.width < 0 || door_1.width > DXSIZE)
2496 door_1.width = DXSIZE;
2497 if (door_1.height < 0 || door_1.height > DYSIZE)
2498 door_1.height = DYSIZE;
2499 if (door_2.width < 0 || door_2.width > VXSIZE)
2500 door_2.width = VXSIZE;
2501 if (door_2.height < 0 || door_2.height > VYSIZE)
2502 door_2.height = VYSIZE;
2504 if (door_state == DOOR_GET_STATE)
2505 return(door1 | door2);
2507 if (door_state & DOOR_SET_STATE)
2509 if (door_state & DOOR_ACTION_1)
2510 door1 = door_state & DOOR_ACTION_1;
2511 if (door_state & DOOR_ACTION_2)
2512 door2 = door_state & DOOR_ACTION_2;
2514 return(door1 | door2);
2517 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2518 door_state &= ~DOOR_OPEN_1;
2519 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2520 door_state &= ~DOOR_CLOSE_1;
2521 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2522 door_state &= ~DOOR_OPEN_2;
2523 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2524 door_state &= ~DOOR_CLOSE_2;
2526 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2529 if (setup.quick_doors)
2531 stepsize = 20; /* must be choosen to always draw last frame */
2532 door_delay_value = 0;
2535 if (global.autoplay_leveldir)
2537 door_state |= DOOR_NO_DELAY;
2538 door_state &= ~DOOR_CLOSE_ALL;
2541 if (door_state & DOOR_ACTION)
2543 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2544 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2545 boolean door_1_done = (!handle_door_1);
2546 boolean door_2_done = (!handle_door_2);
2547 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2548 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2549 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2550 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2551 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2552 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2553 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2554 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2555 int door_skip = max_door_size - door_size;
2557 int end = door_size;
2559 int end = (door_state & DOOR_ACTION_1 &&
2560 door_1.anim_mode & ANIM_VERTICAL ? DYSIZE : DXSIZE);
2563 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2565 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2569 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2571 /* opening door sound has priority over simultaneously closing door */
2572 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2573 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2574 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2575 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2578 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2581 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2582 GC gc = bitmap->stored_clip_gc;
2584 if (door_state & DOOR_ACTION_1)
2586 int a = MIN(x * door_1.step_offset, end);
2587 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2588 int i = p + door_skip;
2590 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2592 BlitBitmap(bitmap_db_door, drawto,
2593 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2594 DXSIZE, DYSIZE, DX, DY);
2598 BlitBitmap(bitmap_db_door, drawto,
2599 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2600 DXSIZE, DYSIZE - p / 2, DX, DY);
2602 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2605 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2607 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2608 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2609 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2610 int dst2_x = DX, dst2_y = DY;
2611 int width = i, height = DYSIZE;
2613 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2614 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2617 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2618 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2621 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2623 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2624 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2625 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2626 int dst2_x = DX, dst2_y = DY;
2627 int width = DXSIZE, height = i;
2629 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2630 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2633 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2634 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2637 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2639 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2641 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2642 BlitBitmapMasked(bitmap, drawto,
2643 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2644 DX + DXSIZE - i, DY + j);
2645 BlitBitmapMasked(bitmap, drawto,
2646 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2647 DX + DXSIZE - i, DY + 140 + j);
2648 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2649 DY - (DOOR_GFX_PAGEY1 + j));
2650 BlitBitmapMasked(bitmap, drawto,
2651 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2653 BlitBitmapMasked(bitmap, drawto,
2654 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2657 BlitBitmapMasked(bitmap, drawto,
2658 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2660 BlitBitmapMasked(bitmap, drawto,
2661 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2663 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2664 BlitBitmapMasked(bitmap, drawto,
2665 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2666 DX + DXSIZE - i, DY + 77 + j);
2667 BlitBitmapMasked(bitmap, drawto,
2668 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2669 DX + DXSIZE - i, DY + 203 + j);
2672 redraw_mask |= REDRAW_DOOR_1;
2673 door_1_done = (a == end);
2676 if (door_state & DOOR_ACTION_2)
2678 int a = MIN(x * door_2.step_offset, door_size_2);
2679 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2680 int i = p + door_skip;
2682 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2684 BlitBitmap(bitmap_db_door, drawto,
2685 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2686 VXSIZE, VYSIZE, VX, VY);
2688 else if (x <= VYSIZE)
2690 BlitBitmap(bitmap_db_door, drawto,
2691 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2692 VXSIZE, VYSIZE - p / 2, VX, VY);
2694 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2697 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2699 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2700 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2701 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2702 int dst2_x = VX, dst2_y = VY;
2703 int width = i, height = VYSIZE;
2705 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2706 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2709 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2710 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2713 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2715 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2716 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2717 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2718 int dst2_x = VX, dst2_y = VY;
2719 int width = VXSIZE, height = i;
2721 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2722 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2725 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2726 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2729 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2731 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2733 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2734 BlitBitmapMasked(bitmap, drawto,
2735 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2736 VX + VXSIZE - i, VY + j);
2737 SetClipOrigin(bitmap, gc,
2738 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2739 BlitBitmapMasked(bitmap, drawto,
2740 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2743 BlitBitmapMasked(bitmap, drawto,
2744 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2745 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2746 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2747 BlitBitmapMasked(bitmap, drawto,
2748 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2750 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2753 redraw_mask |= REDRAW_DOOR_2;
2754 door_2_done = (a == VXSIZE);
2759 if (game_status == GAME_MODE_MAIN)
2762 if (!(door_state & DOOR_NO_DELAY))
2763 WaitUntilDelayReached(&door_delay, door_delay_value);
2767 if (door_state & DOOR_ACTION_1)
2768 door1 = door_state & DOOR_ACTION_1;
2769 if (door_state & DOOR_ACTION_2)
2770 door2 = door_state & DOOR_ACTION_2;
2772 return (door1 | door2);
2775 void DrawSpecialEditorDoor()
2777 /* draw bigger toolbox window */
2778 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2779 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2781 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2782 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2785 redraw_mask |= REDRAW_ALL;
2788 void UndrawSpecialEditorDoor()
2790 /* draw normal tape recorder window */
2791 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2792 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2795 redraw_mask |= REDRAW_ALL;
2799 /* ---------- new tool button stuff ---------------------------------------- */
2801 /* graphic position values for tool buttons */
2802 #define TOOL_BUTTON_YES_XPOS 2
2803 #define TOOL_BUTTON_YES_YPOS 250
2804 #define TOOL_BUTTON_YES_GFX_YPOS 0
2805 #define TOOL_BUTTON_YES_XSIZE 46
2806 #define TOOL_BUTTON_YES_YSIZE 28
2807 #define TOOL_BUTTON_NO_XPOS 52
2808 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2809 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2810 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2811 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2812 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2813 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2814 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2815 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2816 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2817 #define TOOL_BUTTON_PLAYER_XSIZE 30
2818 #define TOOL_BUTTON_PLAYER_YSIZE 30
2819 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2820 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2821 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2822 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2823 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2824 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2825 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2826 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2827 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2828 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2829 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2830 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2831 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2832 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2833 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2834 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2835 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2836 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2837 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2838 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2847 } toolbutton_info[NUM_TOOL_BUTTONS] =
2850 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2851 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2852 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2857 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2858 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2859 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2864 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2865 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2866 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2867 TOOL_CTRL_ID_CONFIRM,
2871 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2872 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2873 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2874 TOOL_CTRL_ID_PLAYER_1,
2878 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2879 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2880 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2881 TOOL_CTRL_ID_PLAYER_2,
2885 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2886 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2887 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2888 TOOL_CTRL_ID_PLAYER_3,
2892 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2893 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2894 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2895 TOOL_CTRL_ID_PLAYER_4,
2900 void CreateToolButtons()
2904 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2906 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2907 Bitmap *deco_bitmap = None;
2908 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2909 struct GadgetInfo *gi;
2910 unsigned long event_mask;
2911 int gd_xoffset, gd_yoffset;
2912 int gd_x1, gd_x2, gd_y;
2915 event_mask = GD_EVENT_RELEASED;
2917 gd_xoffset = toolbutton_info[i].xpos;
2918 gd_yoffset = toolbutton_info[i].ypos;
2919 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2920 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2921 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2923 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2925 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2927 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2928 &deco_bitmap, &deco_x, &deco_y);
2929 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2930 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2933 gi = CreateGadget(GDI_CUSTOM_ID, id,
2934 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2935 GDI_X, DX + toolbutton_info[i].x,
2936 GDI_Y, DY + toolbutton_info[i].y,
2937 GDI_WIDTH, toolbutton_info[i].width,
2938 GDI_HEIGHT, toolbutton_info[i].height,
2939 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2940 GDI_STATE, GD_BUTTON_UNPRESSED,
2941 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2942 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2943 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2944 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2945 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2946 GDI_DECORATION_SHIFTING, 1, 1,
2947 GDI_EVENT_MASK, event_mask,
2948 GDI_CALLBACK_ACTION, HandleToolButtons,
2952 Error(ERR_EXIT, "cannot create gadget");
2954 tool_gadget[id] = gi;
2958 void FreeToolButtons()
2962 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2963 FreeGadget(tool_gadget[i]);
2966 static void UnmapToolButtons()
2970 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2971 UnmapGadget(tool_gadget[i]);
2974 static void HandleToolButtons(struct GadgetInfo *gi)
2976 request_gadget_id = gi->custom_id;
2979 static struct Mapping_EM_to_RND_object
2982 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
2983 boolean is_backside; /* backside of moving element */
2989 em_object_mapping_list[] =
2992 Xblank, TRUE, FALSE,
2996 Yacid_splash_eB, FALSE, FALSE,
2997 EL_ACID_SPLASH_RIGHT, -1, -1
3000 Yacid_splash_wB, FALSE, FALSE,
3001 EL_ACID_SPLASH_LEFT, -1, -1
3004 #ifdef EM_ENGINE_BAD_ROLL
3006 Xstone_force_e, FALSE, FALSE,
3007 EL_ROCK, -1, MV_BIT_RIGHT
3010 Xstone_force_w, FALSE, FALSE,
3011 EL_ROCK, -1, MV_BIT_LEFT
3014 Xnut_force_e, FALSE, FALSE,
3015 EL_NUT, -1, MV_BIT_RIGHT
3018 Xnut_force_w, FALSE, FALSE,
3019 EL_NUT, -1, MV_BIT_LEFT
3022 Xspring_force_e, FALSE, FALSE,
3023 EL_SPRING, -1, MV_BIT_RIGHT
3026 Xspring_force_w, FALSE, FALSE,
3027 EL_SPRING, -1, MV_BIT_LEFT
3030 Xemerald_force_e, FALSE, FALSE,
3031 EL_EMERALD, -1, MV_BIT_RIGHT
3034 Xemerald_force_w, FALSE, FALSE,
3035 EL_EMERALD, -1, MV_BIT_LEFT
3038 Xdiamond_force_e, FALSE, FALSE,
3039 EL_DIAMOND, -1, MV_BIT_RIGHT
3042 Xdiamond_force_w, FALSE, FALSE,
3043 EL_DIAMOND, -1, MV_BIT_LEFT
3046 Xbomb_force_e, FALSE, FALSE,
3047 EL_BOMB, -1, MV_BIT_RIGHT
3050 Xbomb_force_w, FALSE, FALSE,
3051 EL_BOMB, -1, MV_BIT_LEFT
3053 #endif /* EM_ENGINE_BAD_ROLL */
3056 Xstone, TRUE, FALSE,
3060 Xstone_pause, FALSE, FALSE,
3064 Xstone_fall, FALSE, FALSE,
3068 Ystone_s, FALSE, FALSE,
3069 EL_ROCK, ACTION_FALLING, -1
3072 Ystone_sB, FALSE, TRUE,
3073 EL_ROCK, ACTION_FALLING, -1
3076 Ystone_e, FALSE, FALSE,
3077 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3080 Ystone_eB, FALSE, TRUE,
3081 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3084 Ystone_w, FALSE, FALSE,
3085 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3088 Ystone_wB, FALSE, TRUE,
3089 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3096 Xnut_pause, FALSE, FALSE,
3100 Xnut_fall, FALSE, FALSE,
3104 Ynut_s, FALSE, FALSE,
3105 EL_NUT, ACTION_FALLING, -1
3108 Ynut_sB, FALSE, TRUE,
3109 EL_NUT, ACTION_FALLING, -1
3112 Ynut_e, FALSE, FALSE,
3113 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3116 Ynut_eB, FALSE, TRUE,
3117 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3120 Ynut_w, FALSE, FALSE,
3121 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3124 Ynut_wB, FALSE, TRUE,
3125 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3128 Xbug_n, TRUE, FALSE,
3132 Xbug_e, TRUE, FALSE,
3133 EL_BUG_RIGHT, -1, -1
3136 Xbug_s, TRUE, FALSE,
3140 Xbug_w, TRUE, FALSE,
3144 Xbug_gon, FALSE, FALSE,
3148 Xbug_goe, FALSE, FALSE,
3149 EL_BUG_RIGHT, -1, -1
3152 Xbug_gos, FALSE, FALSE,
3156 Xbug_gow, FALSE, FALSE,
3160 Ybug_n, FALSE, FALSE,
3161 EL_BUG, ACTION_MOVING, MV_BIT_UP
3164 Ybug_nB, FALSE, TRUE,
3165 EL_BUG, ACTION_MOVING, MV_BIT_UP
3168 Ybug_e, FALSE, FALSE,
3169 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3172 Ybug_eB, FALSE, TRUE,
3173 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3176 Ybug_s, FALSE, FALSE,
3177 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3180 Ybug_sB, FALSE, TRUE,
3181 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3184 Ybug_w, FALSE, FALSE,
3185 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3188 Ybug_wB, FALSE, TRUE,
3189 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3192 Ybug_w_n, FALSE, FALSE,
3193 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3196 Ybug_n_e, FALSE, FALSE,
3197 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3200 Ybug_e_s, FALSE, FALSE,
3201 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3204 Ybug_s_w, FALSE, FALSE,
3205 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3208 Ybug_e_n, FALSE, FALSE,
3209 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3212 Ybug_s_e, FALSE, FALSE,
3213 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3216 Ybug_w_s, FALSE, FALSE,
3217 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3220 Ybug_n_w, FALSE, FALSE,
3221 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3224 Ybug_stone, FALSE, FALSE,
3225 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3228 Ybug_spring, FALSE, FALSE,
3229 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3232 Xtank_n, TRUE, FALSE,
3233 EL_SPACESHIP_UP, -1, -1
3236 Xtank_e, TRUE, FALSE,
3237 EL_SPACESHIP_RIGHT, -1, -1
3240 Xtank_s, TRUE, FALSE,
3241 EL_SPACESHIP_DOWN, -1, -1
3244 Xtank_w, TRUE, FALSE,
3245 EL_SPACESHIP_LEFT, -1, -1
3248 Xtank_gon, FALSE, FALSE,
3249 EL_SPACESHIP_UP, -1, -1
3252 Xtank_goe, FALSE, FALSE,
3253 EL_SPACESHIP_RIGHT, -1, -1
3256 Xtank_gos, FALSE, FALSE,
3257 EL_SPACESHIP_DOWN, -1, -1
3260 Xtank_gow, FALSE, FALSE,
3261 EL_SPACESHIP_LEFT, -1, -1
3264 Ytank_n, FALSE, FALSE,
3265 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3268 Ytank_nB, FALSE, TRUE,
3269 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3272 Ytank_e, FALSE, FALSE,
3273 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3276 Ytank_eB, FALSE, TRUE,
3277 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3280 Ytank_s, FALSE, FALSE,
3281 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3284 Ytank_sB, FALSE, TRUE,
3285 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3288 Ytank_w, FALSE, FALSE,
3289 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3292 Ytank_wB, FALSE, TRUE,
3293 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3296 Ytank_w_n, FALSE, FALSE,
3297 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3300 Ytank_n_e, FALSE, FALSE,
3301 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3304 Ytank_e_s, FALSE, FALSE,
3305 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3308 Ytank_s_w, FALSE, FALSE,
3309 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3312 Ytank_e_n, FALSE, FALSE,
3313 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3316 Ytank_s_e, FALSE, FALSE,
3317 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3320 Ytank_w_s, FALSE, FALSE,
3321 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3324 Ytank_n_w, FALSE, FALSE,
3325 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3328 Ytank_stone, FALSE, FALSE,
3329 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3332 Ytank_spring, FALSE, FALSE,
3333 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3336 Xandroid, TRUE, FALSE,
3337 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3340 Xandroid_1_n, FALSE, FALSE,
3341 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3344 Xandroid_2_n, FALSE, FALSE,
3345 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3348 Xandroid_1_e, FALSE, FALSE,
3349 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3352 Xandroid_2_e, FALSE, FALSE,
3353 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3356 Xandroid_1_w, FALSE, FALSE,
3357 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3360 Xandroid_2_w, FALSE, FALSE,
3361 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3364 Xandroid_1_s, FALSE, FALSE,
3365 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3368 Xandroid_2_s, FALSE, FALSE,
3369 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3372 Yandroid_n, FALSE, FALSE,
3373 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3376 Yandroid_nB, FALSE, TRUE,
3377 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3380 Yandroid_ne, FALSE, FALSE,
3381 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3384 Yandroid_neB, FALSE, TRUE,
3385 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3388 Yandroid_e, FALSE, FALSE,
3389 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3392 Yandroid_eB, FALSE, TRUE,
3393 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3396 Yandroid_se, FALSE, FALSE,
3397 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3400 Yandroid_seB, FALSE, TRUE,
3401 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3404 Yandroid_s, FALSE, FALSE,
3405 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3408 Yandroid_sB, FALSE, TRUE,
3409 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3412 Yandroid_sw, FALSE, FALSE,
3413 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3416 Yandroid_swB, FALSE, TRUE,
3417 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3420 Yandroid_w, FALSE, FALSE,
3421 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3424 Yandroid_wB, FALSE, TRUE,
3425 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3428 Yandroid_nw, FALSE, FALSE,
3429 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3432 Yandroid_nwB, FALSE, TRUE,
3433 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3436 Xspring, TRUE, FALSE,
3440 Xspring_pause, FALSE, FALSE,
3444 Xspring_e, FALSE, FALSE,
3448 Xspring_w, FALSE, FALSE,
3452 Xspring_fall, FALSE, FALSE,
3456 Yspring_s, FALSE, FALSE,
3457 EL_SPRING, ACTION_FALLING, -1
3460 Yspring_sB, FALSE, TRUE,
3461 EL_SPRING, ACTION_FALLING, -1
3464 Yspring_e, FALSE, FALSE,
3465 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3468 Yspring_eB, FALSE, TRUE,
3469 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3472 Yspring_w, FALSE, FALSE,
3473 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3476 Yspring_wB, FALSE, TRUE,
3477 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3480 Yspring_kill_e, FALSE, FALSE,
3481 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3484 Yspring_kill_eB, FALSE, TRUE,
3485 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3488 Yspring_kill_w, FALSE, FALSE,
3489 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3492 Yspring_kill_wB, FALSE, TRUE,
3493 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3496 Xeater_n, TRUE, FALSE,
3497 EL_YAMYAM_UP, -1, -1
3500 Xeater_e, TRUE, FALSE,
3501 EL_YAMYAM_RIGHT, -1, -1
3504 Xeater_w, TRUE, FALSE,
3505 EL_YAMYAM_LEFT, -1, -1
3508 Xeater_s, TRUE, FALSE,
3509 EL_YAMYAM_DOWN, -1, -1
3512 Yeater_n, FALSE, FALSE,
3513 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3516 Yeater_nB, FALSE, TRUE,
3517 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3520 Yeater_e, FALSE, FALSE,
3521 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3524 Yeater_eB, FALSE, TRUE,
3525 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3528 Yeater_s, FALSE, FALSE,
3529 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3532 Yeater_sB, FALSE, TRUE,
3533 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3536 Yeater_w, FALSE, FALSE,
3537 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3540 Yeater_wB, FALSE, TRUE,
3541 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3544 Yeater_stone, FALSE, FALSE,
3545 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3548 Yeater_spring, FALSE, FALSE,
3549 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3552 Xalien, TRUE, FALSE,
3556 Xalien_pause, FALSE, FALSE,
3560 Yalien_n, FALSE, FALSE,
3561 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3564 Yalien_nB, FALSE, TRUE,
3565 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3568 Yalien_e, FALSE, FALSE,
3569 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3572 Yalien_eB, FALSE, TRUE,
3573 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3576 Yalien_s, FALSE, FALSE,
3577 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3580 Yalien_sB, FALSE, TRUE,
3581 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3584 Yalien_w, FALSE, FALSE,
3585 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3588 Yalien_wB, FALSE, TRUE,
3589 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3592 Yalien_stone, FALSE, FALSE,
3593 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3596 Yalien_spring, FALSE, FALSE,
3597 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3600 Xemerald, TRUE, FALSE,
3604 Xemerald_pause, FALSE, FALSE,
3608 Xemerald_fall, FALSE, FALSE,
3612 Xemerald_shine, FALSE, FALSE,
3613 EL_EMERALD, ACTION_TWINKLING, -1
3616 Yemerald_s, FALSE, FALSE,
3617 EL_EMERALD, ACTION_FALLING, -1
3620 Yemerald_sB, FALSE, TRUE,
3621 EL_EMERALD, ACTION_FALLING, -1
3624 Yemerald_e, FALSE, FALSE,
3625 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3628 Yemerald_eB, FALSE, TRUE,
3629 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3632 Yemerald_w, FALSE, FALSE,
3633 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3636 Yemerald_wB, FALSE, TRUE,
3637 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3640 Yemerald_eat, FALSE, FALSE,
3641 EL_EMERALD, ACTION_COLLECTING, -1
3644 Yemerald_stone, FALSE, FALSE,
3645 EL_NUT, ACTION_BREAKING, -1
3648 Xdiamond, TRUE, FALSE,
3652 Xdiamond_pause, FALSE, FALSE,
3656 Xdiamond_fall, FALSE, FALSE,
3660 Xdiamond_shine, FALSE, FALSE,
3661 EL_DIAMOND, ACTION_TWINKLING, -1
3664 Ydiamond_s, FALSE, FALSE,
3665 EL_DIAMOND, ACTION_FALLING, -1
3668 Ydiamond_sB, FALSE, TRUE,
3669 EL_DIAMOND, ACTION_FALLING, -1
3672 Ydiamond_e, FALSE, FALSE,
3673 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3676 Ydiamond_eB, FALSE, TRUE,
3677 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3680 Ydiamond_w, FALSE, FALSE,
3681 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3684 Ydiamond_wB, FALSE, TRUE,
3685 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3688 Ydiamond_eat, FALSE, FALSE,
3689 EL_DIAMOND, ACTION_COLLECTING, -1
3692 Ydiamond_stone, FALSE, FALSE,
3693 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3696 Xdrip_fall, TRUE, FALSE,
3697 EL_AMOEBA_DROP, -1, -1
3700 Xdrip_stretch, FALSE, FALSE,
3701 EL_AMOEBA_DROP, ACTION_FALLING, -1
3704 Xdrip_stretchB, FALSE, TRUE,
3705 EL_AMOEBA_DROP, ACTION_FALLING, -1
3708 Xdrip_eat, FALSE, FALSE,
3709 EL_AMOEBA_DROP, ACTION_GROWING, -1
3712 Ydrip_s1, FALSE, FALSE,
3713 EL_AMOEBA_DROP, ACTION_FALLING, -1
3716 Ydrip_s1B, FALSE, TRUE,
3717 EL_AMOEBA_DROP, ACTION_FALLING, -1
3720 Ydrip_s2, FALSE, FALSE,
3721 EL_AMOEBA_DROP, ACTION_FALLING, -1
3724 Ydrip_s2B, FALSE, TRUE,
3725 EL_AMOEBA_DROP, ACTION_FALLING, -1
3732 Xbomb_pause, FALSE, FALSE,
3736 Xbomb_fall, FALSE, FALSE,
3740 Ybomb_s, FALSE, FALSE,
3741 EL_BOMB, ACTION_FALLING, -1
3744 Ybomb_sB, FALSE, TRUE,
3745 EL_BOMB, ACTION_FALLING, -1
3748 Ybomb_e, FALSE, FALSE,
3749 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3752 Ybomb_eB, FALSE, TRUE,
3753 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3756 Ybomb_w, FALSE, FALSE,
3757 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3760 Ybomb_wB, FALSE, TRUE,
3761 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3764 Ybomb_eat, FALSE, FALSE,
3765 EL_BOMB, ACTION_ACTIVATING, -1
3768 Xballoon, TRUE, FALSE,
3772 Yballoon_n, FALSE, FALSE,
3773 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3776 Yballoon_nB, FALSE, TRUE,
3777 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3780 Yballoon_e, FALSE, FALSE,
3781 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3784 Yballoon_eB, FALSE, TRUE,
3785 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3788 Yballoon_s, FALSE, FALSE,
3789 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3792 Yballoon_sB, FALSE, TRUE,
3793 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3796 Yballoon_w, FALSE, FALSE,
3797 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3800 Yballoon_wB, FALSE, TRUE,
3801 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3804 Xgrass, TRUE, FALSE,
3805 EL_EMC_GRASS, -1, -1
3808 Ygrass_nB, FALSE, FALSE,
3809 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3812 Ygrass_eB, FALSE, FALSE,
3813 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3816 Ygrass_sB, FALSE, FALSE,
3817 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3820 Ygrass_wB, FALSE, FALSE,
3821 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3828 Ydirt_nB, FALSE, FALSE,
3829 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3832 Ydirt_eB, FALSE, FALSE,
3833 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3836 Ydirt_sB, FALSE, FALSE,
3837 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3840 Ydirt_wB, FALSE, FALSE,
3841 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3844 Xacid_ne, TRUE, FALSE,
3845 EL_ACID_POOL_TOPRIGHT, -1, -1
3848 Xacid_se, TRUE, FALSE,
3849 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3852 Xacid_s, TRUE, FALSE,
3853 EL_ACID_POOL_BOTTOM, -1, -1
3856 Xacid_sw, TRUE, FALSE,
3857 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3860 Xacid_nw, TRUE, FALSE,
3861 EL_ACID_POOL_TOPLEFT, -1, -1
3864 Xacid_1, TRUE, FALSE,
3868 Xacid_2, FALSE, FALSE,
3872 Xacid_3, FALSE, FALSE,
3876 Xacid_4, FALSE, FALSE,
3880 Xacid_5, FALSE, FALSE,
3884 Xacid_6, FALSE, FALSE,
3888 Xacid_7, FALSE, FALSE,
3892 Xacid_8, FALSE, FALSE,
3896 Xball_1, TRUE, FALSE,
3897 EL_EMC_MAGIC_BALL, -1, -1
3900 Xball_1B, FALSE, FALSE,
3901 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3904 Xball_2, FALSE, FALSE,
3905 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3908 Xball_2B, FALSE, FALSE,
3909 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3912 Yball_eat, FALSE, FALSE,
3913 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
3916 Ykey_1_eat, FALSE, FALSE,
3917 EL_EM_KEY_1, ACTION_COLLECTING, -1
3920 Ykey_2_eat, FALSE, FALSE,
3921 EL_EM_KEY_2, ACTION_COLLECTING, -1
3924 Ykey_3_eat, FALSE, FALSE,
3925 EL_EM_KEY_3, ACTION_COLLECTING, -1
3928 Ykey_4_eat, FALSE, FALSE,
3929 EL_EM_KEY_4, ACTION_COLLECTING, -1
3932 Ykey_5_eat, FALSE, FALSE,
3933 EL_EMC_KEY_5, ACTION_COLLECTING, -1
3936 Ykey_6_eat, FALSE, FALSE,
3937 EL_EMC_KEY_6, ACTION_COLLECTING, -1
3940 Ykey_7_eat, FALSE, FALSE,
3941 EL_EMC_KEY_7, ACTION_COLLECTING, -1
3944 Ykey_8_eat, FALSE, FALSE,
3945 EL_EMC_KEY_8, ACTION_COLLECTING, -1
3948 Ylenses_eat, FALSE, FALSE,
3949 EL_EMC_LENSES, ACTION_COLLECTING, -1
3952 Ymagnify_eat, FALSE, FALSE,
3953 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
3956 Ygrass_eat, FALSE, FALSE,
3957 EL_EMC_GRASS, ACTION_SNAPPING, -1
3960 Ydirt_eat, FALSE, FALSE,
3961 EL_SAND, ACTION_SNAPPING, -1
3964 Xgrow_ns, TRUE, FALSE,
3965 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
3968 Ygrow_ns_eat, FALSE, FALSE,
3969 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
3972 Xgrow_ew, TRUE, FALSE,
3973 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
3976 Ygrow_ew_eat, FALSE, FALSE,
3977 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
3980 Xwonderwall, TRUE, FALSE,
3981 EL_MAGIC_WALL, -1, -1
3984 XwonderwallB, FALSE, FALSE,
3985 EL_MAGIC_WALL, ACTION_ACTIVE, -1
3988 Xamoeba_1, TRUE, FALSE,
3989 EL_AMOEBA_DRY, ACTION_OTHER, -1
3992 Xamoeba_2, FALSE, FALSE,
3993 EL_AMOEBA_DRY, ACTION_OTHER, -1
3996 Xamoeba_3, FALSE, FALSE,
3997 EL_AMOEBA_DRY, ACTION_OTHER, -1
4000 Xamoeba_4, FALSE, FALSE,
4001 EL_AMOEBA_DRY, ACTION_OTHER, -1
4004 Xamoeba_5, TRUE, FALSE,
4005 EL_AMOEBA_WET, ACTION_OTHER, -1
4008 Xamoeba_6, FALSE, FALSE,
4009 EL_AMOEBA_WET, ACTION_OTHER, -1
4012 Xamoeba_7, FALSE, FALSE,
4013 EL_AMOEBA_WET, ACTION_OTHER, -1
4016 Xamoeba_8, FALSE, FALSE,
4017 EL_AMOEBA_WET, ACTION_OTHER, -1
4020 Xdoor_1, TRUE, FALSE,
4021 EL_EM_GATE_1, -1, -1
4024 Xdoor_2, TRUE, FALSE,
4025 EL_EM_GATE_2, -1, -1
4028 Xdoor_3, TRUE, FALSE,
4029 EL_EM_GATE_3, -1, -1
4032 Xdoor_4, TRUE, FALSE,
4033 EL_EM_GATE_4, -1, -1
4036 Xdoor_5, TRUE, FALSE,
4037 EL_EMC_GATE_5, -1, -1
4040 Xdoor_6, TRUE, FALSE,
4041 EL_EMC_GATE_6, -1, -1
4044 Xdoor_7, TRUE, FALSE,
4045 EL_EMC_GATE_7, -1, -1
4048 Xdoor_8, TRUE, FALSE,
4049 EL_EMC_GATE_8, -1, -1
4052 Xkey_1, TRUE, FALSE,
4056 Xkey_2, TRUE, FALSE,
4060 Xkey_3, TRUE, FALSE,
4064 Xkey_4, TRUE, FALSE,
4068 Xkey_5, TRUE, FALSE,
4069 EL_EMC_KEY_5, -1, -1
4072 Xkey_6, TRUE, FALSE,
4073 EL_EMC_KEY_6, -1, -1
4076 Xkey_7, TRUE, FALSE,
4077 EL_EMC_KEY_7, -1, -1
4080 Xkey_8, TRUE, FALSE,
4081 EL_EMC_KEY_8, -1, -1
4084 Xwind_n, TRUE, FALSE,
4085 EL_BALLOON_SWITCH_UP, -1, -1
4088 Xwind_e, TRUE, FALSE,
4089 EL_BALLOON_SWITCH_RIGHT, -1, -1
4092 Xwind_s, TRUE, FALSE,
4093 EL_BALLOON_SWITCH_DOWN, -1, -1
4096 Xwind_w, TRUE, FALSE,
4097 EL_BALLOON_SWITCH_LEFT, -1, -1
4100 Xwind_nesw, TRUE, FALSE,
4101 EL_BALLOON_SWITCH_ANY, -1, -1
4104 Xwind_stop, TRUE, FALSE,
4105 EL_BALLOON_SWITCH_NONE, -1, -1
4109 EL_EXIT_CLOSED, -1, -1
4112 Xexit_1, TRUE, FALSE,
4113 EL_EXIT_OPEN, -1, -1
4116 Xexit_2, FALSE, FALSE,
4117 EL_EXIT_OPEN, -1, -1
4120 Xexit_3, FALSE, FALSE,
4121 EL_EXIT_OPEN, -1, -1
4124 Xdynamite, TRUE, FALSE,
4125 EL_EM_DYNAMITE, -1, -1
4128 Ydynamite_eat, FALSE, FALSE,
4129 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4132 Xdynamite_1, TRUE, FALSE,
4133 EL_EM_DYNAMITE_ACTIVE, -1, -1
4136 Xdynamite_2, FALSE, FALSE,
4137 EL_EM_DYNAMITE_ACTIVE, -1, -1
4140 Xdynamite_3, FALSE, FALSE,
4141 EL_EM_DYNAMITE_ACTIVE, -1, -1
4144 Xdynamite_4, FALSE, FALSE,
4145 EL_EM_DYNAMITE_ACTIVE, -1, -1
4148 Xbumper, TRUE, FALSE,
4149 EL_EMC_SPRING_BUMPER, -1, -1
4152 XbumperB, FALSE, FALSE,
4153 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4156 Xwheel, TRUE, FALSE,
4157 EL_ROBOT_WHEEL, -1, -1
4160 XwheelB, FALSE, FALSE,
4161 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4164 Xswitch, TRUE, FALSE,
4165 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4168 XswitchB, FALSE, FALSE,
4169 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4173 EL_QUICKSAND_EMPTY, -1, -1
4176 Xsand_stone, TRUE, FALSE,
4177 EL_QUICKSAND_FULL, -1, -1
4180 Xsand_stonein_1, FALSE, TRUE,
4181 EL_ROCK, ACTION_FILLING, -1
4184 Xsand_stonein_2, FALSE, TRUE,
4185 EL_ROCK, ACTION_FILLING, -1
4188 Xsand_stonein_3, FALSE, TRUE,
4189 EL_ROCK, ACTION_FILLING, -1
4192 Xsand_stonein_4, FALSE, TRUE,
4193 EL_ROCK, ACTION_FILLING, -1
4196 Xsand_stonesand_1, FALSE, FALSE,
4197 EL_QUICKSAND_FULL, -1, -1
4200 Xsand_stonesand_2, FALSE, FALSE,
4201 EL_QUICKSAND_FULL, -1, -1
4204 Xsand_stonesand_3, FALSE, FALSE,
4205 EL_QUICKSAND_FULL, -1, -1
4208 Xsand_stonesand_4, FALSE, FALSE,
4209 EL_QUICKSAND_FULL, -1, -1
4212 Xsand_stoneout_1, FALSE, FALSE,
4213 EL_ROCK, ACTION_EMPTYING, -1
4216 Xsand_stoneout_2, FALSE, FALSE,
4217 EL_ROCK, ACTION_EMPTYING, -1
4220 Xsand_sandstone_1, FALSE, FALSE,
4221 EL_QUICKSAND_FULL, -1, -1
4224 Xsand_sandstone_2, FALSE, FALSE,
4225 EL_QUICKSAND_FULL, -1, -1
4228 Xsand_sandstone_3, FALSE, FALSE,
4229 EL_QUICKSAND_FULL, -1, -1
4232 Xsand_sandstone_4, FALSE, FALSE,
4233 EL_QUICKSAND_FULL, -1, -1
4236 Xplant, TRUE, FALSE,
4237 EL_EMC_PLANT, -1, -1
4240 Yplant, FALSE, FALSE,
4241 EL_EMC_PLANT, -1, -1
4244 Xlenses, TRUE, FALSE,
4245 EL_EMC_LENSES, -1, -1
4248 Xmagnify, TRUE, FALSE,
4249 EL_EMC_MAGNIFIER, -1, -1
4252 Xdripper, TRUE, FALSE,
4253 EL_EMC_DRIPPER, -1, -1
4256 XdripperB, FALSE, FALSE,
4257 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4260 Xfake_blank, TRUE, FALSE,
4261 EL_INVISIBLE_WALL, -1, -1
4264 Xfake_blankB, FALSE, FALSE,
4265 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4268 Xfake_grass, TRUE, FALSE,
4269 EL_EMC_FAKE_GRASS, -1, -1
4272 Xfake_grassB, FALSE, FALSE,
4273 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4276 Xfake_door_1, TRUE, FALSE,
4277 EL_EM_GATE_1_GRAY, -1, -1
4280 Xfake_door_2, TRUE, FALSE,
4281 EL_EM_GATE_2_GRAY, -1, -1
4284 Xfake_door_3, TRUE, FALSE,
4285 EL_EM_GATE_3_GRAY, -1, -1
4288 Xfake_door_4, TRUE, FALSE,
4289 EL_EM_GATE_4_GRAY, -1, -1
4292 Xfake_door_5, TRUE, FALSE,
4293 EL_EMC_GATE_5_GRAY, -1, -1
4296 Xfake_door_6, TRUE, FALSE,
4297 EL_EMC_GATE_6_GRAY, -1, -1
4300 Xfake_door_7, TRUE, FALSE,
4301 EL_EMC_GATE_7_GRAY, -1, -1
4304 Xfake_door_8, TRUE, FALSE,
4305 EL_EMC_GATE_8_GRAY, -1, -1
4308 Xfake_acid_1, TRUE, FALSE,
4309 EL_EMC_FAKE_ACID, -1, -1
4312 Xfake_acid_2, FALSE, FALSE,
4313 EL_EMC_FAKE_ACID, -1, -1
4316 Xfake_acid_3, FALSE, FALSE,
4317 EL_EMC_FAKE_ACID, -1, -1
4320 Xfake_acid_4, FALSE, FALSE,
4321 EL_EMC_FAKE_ACID, -1, -1
4324 Xfake_acid_5, FALSE, FALSE,
4325 EL_EMC_FAKE_ACID, -1, -1
4328 Xfake_acid_6, FALSE, FALSE,
4329 EL_EMC_FAKE_ACID, -1, -1
4332 Xfake_acid_7, FALSE, FALSE,
4333 EL_EMC_FAKE_ACID, -1, -1
4336 Xfake_acid_8, FALSE, FALSE,
4337 EL_EMC_FAKE_ACID, -1, -1
4340 Xsteel_1, TRUE, FALSE,
4341 EL_STEELWALL, -1, -1
4344 Xsteel_2, TRUE, FALSE,
4345 EL_EMC_STEELWALL_2, -1, -1
4348 Xsteel_3, TRUE, FALSE,
4349 EL_EMC_STEELWALL_3, -1, -1
4352 Xsteel_4, TRUE, FALSE,
4353 EL_EMC_STEELWALL_4, -1, -1
4356 Xwall_1, TRUE, FALSE,
4360 Xwall_2, TRUE, FALSE,
4361 EL_EMC_WALL_14, -1, -1
4364 Xwall_3, TRUE, FALSE,
4365 EL_EMC_WALL_15, -1, -1
4368 Xwall_4, TRUE, FALSE,
4369 EL_EMC_WALL_16, -1, -1
4372 Xround_wall_1, TRUE, FALSE,
4373 EL_WALL_SLIPPERY, -1, -1
4376 Xround_wall_2, TRUE, FALSE,
4377 EL_EMC_WALL_SLIPPERY_2, -1, -1
4380 Xround_wall_3, TRUE, FALSE,
4381 EL_EMC_WALL_SLIPPERY_3, -1, -1
4384 Xround_wall_4, TRUE, FALSE,
4385 EL_EMC_WALL_SLIPPERY_4, -1, -1
4388 Xdecor_1, TRUE, FALSE,
4389 EL_EMC_WALL_8, -1, -1
4392 Xdecor_2, TRUE, FALSE,
4393 EL_EMC_WALL_6, -1, -1
4396 Xdecor_3, TRUE, FALSE,
4397 EL_EMC_WALL_4, -1, -1
4400 Xdecor_4, TRUE, FALSE,
4401 EL_EMC_WALL_7, -1, -1
4404 Xdecor_5, TRUE, FALSE,
4405 EL_EMC_WALL_5, -1, -1
4408 Xdecor_6, TRUE, FALSE,
4409 EL_EMC_WALL_9, -1, -1
4412 Xdecor_7, TRUE, FALSE,
4413 EL_EMC_WALL_10, -1, -1
4416 Xdecor_8, TRUE, FALSE,
4417 EL_EMC_WALL_1, -1, -1
4420 Xdecor_9, TRUE, FALSE,
4421 EL_EMC_WALL_2, -1, -1
4424 Xdecor_10, TRUE, FALSE,
4425 EL_EMC_WALL_3, -1, -1
4428 Xdecor_11, TRUE, FALSE,
4429 EL_EMC_WALL_11, -1, -1
4432 Xdecor_12, TRUE, FALSE,
4433 EL_EMC_WALL_12, -1, -1
4436 Xalpha_0, TRUE, FALSE,
4437 EL_CHAR('0'), -1, -1
4440 Xalpha_1, TRUE, FALSE,
4441 EL_CHAR('1'), -1, -1
4444 Xalpha_2, TRUE, FALSE,
4445 EL_CHAR('2'), -1, -1
4448 Xalpha_3, TRUE, FALSE,
4449 EL_CHAR('3'), -1, -1
4452 Xalpha_4, TRUE, FALSE,
4453 EL_CHAR('4'), -1, -1
4456 Xalpha_5, TRUE, FALSE,
4457 EL_CHAR('5'), -1, -1
4460 Xalpha_6, TRUE, FALSE,
4461 EL_CHAR('6'), -1, -1
4464 Xalpha_7, TRUE, FALSE,
4465 EL_CHAR('7'), -1, -1
4468 Xalpha_8, TRUE, FALSE,
4469 EL_CHAR('8'), -1, -1
4472 Xalpha_9, TRUE, FALSE,
4473 EL_CHAR('9'), -1, -1
4476 Xalpha_excla, TRUE, FALSE,
4477 EL_CHAR('!'), -1, -1
4480 Xalpha_quote, TRUE, FALSE,
4481 EL_CHAR('"'), -1, -1
4484 Xalpha_comma, TRUE, FALSE,
4485 EL_CHAR(','), -1, -1
4488 Xalpha_minus, TRUE, FALSE,
4489 EL_CHAR('-'), -1, -1
4492 Xalpha_perio, TRUE, FALSE,
4493 EL_CHAR('.'), -1, -1
4496 Xalpha_colon, TRUE, FALSE,
4497 EL_CHAR(':'), -1, -1
4500 Xalpha_quest, TRUE, FALSE,
4501 EL_CHAR('?'), -1, -1
4504 Xalpha_a, TRUE, FALSE,
4505 EL_CHAR('A'), -1, -1
4508 Xalpha_b, TRUE, FALSE,
4509 EL_CHAR('B'), -1, -1
4512 Xalpha_c, TRUE, FALSE,
4513 EL_CHAR('C'), -1, -1
4516 Xalpha_d, TRUE, FALSE,
4517 EL_CHAR('D'), -1, -1
4520 Xalpha_e, TRUE, FALSE,
4521 EL_CHAR('E'), -1, -1
4524 Xalpha_f, TRUE, FALSE,
4525 EL_CHAR('F'), -1, -1
4528 Xalpha_g, TRUE, FALSE,
4529 EL_CHAR('G'), -1, -1
4532 Xalpha_h, TRUE, FALSE,
4533 EL_CHAR('H'), -1, -1
4536 Xalpha_i, TRUE, FALSE,
4537 EL_CHAR('I'), -1, -1
4540 Xalpha_j, TRUE, FALSE,
4541 EL_CHAR('J'), -1, -1
4544 Xalpha_k, TRUE, FALSE,
4545 EL_CHAR('K'), -1, -1
4548 Xalpha_l, TRUE, FALSE,
4549 EL_CHAR('L'), -1, -1
4552 Xalpha_m, TRUE, FALSE,
4553 EL_CHAR('M'), -1, -1
4556 Xalpha_n, TRUE, FALSE,
4557 EL_CHAR('N'), -1, -1
4560 Xalpha_o, TRUE, FALSE,
4561 EL_CHAR('O'), -1, -1
4564 Xalpha_p, TRUE, FALSE,
4565 EL_CHAR('P'), -1, -1
4568 Xalpha_q, TRUE, FALSE,
4569 EL_CHAR('Q'), -1, -1
4572 Xalpha_r, TRUE, FALSE,
4573 EL_CHAR('R'), -1, -1
4576 Xalpha_s, TRUE, FALSE,
4577 EL_CHAR('S'), -1, -1
4580 Xalpha_t, TRUE, FALSE,
4581 EL_CHAR('T'), -1, -1
4584 Xalpha_u, TRUE, FALSE,
4585 EL_CHAR('U'), -1, -1
4588 Xalpha_v, TRUE, FALSE,
4589 EL_CHAR('V'), -1, -1
4592 Xalpha_w, TRUE, FALSE,
4593 EL_CHAR('W'), -1, -1
4596 Xalpha_x, TRUE, FALSE,
4597 EL_CHAR('X'), -1, -1
4600 Xalpha_y, TRUE, FALSE,
4601 EL_CHAR('Y'), -1, -1
4604 Xalpha_z, TRUE, FALSE,
4605 EL_CHAR('Z'), -1, -1
4608 Xalpha_arrow_e, TRUE, FALSE,
4609 EL_CHAR('>'), -1, -1
4612 Xalpha_arrow_w, TRUE, FALSE,
4613 EL_CHAR('<'), -1, -1
4616 Xalpha_copyr, TRUE, FALSE,
4617 EL_CHAR('©'), -1, -1
4621 Xboom_bug, FALSE, FALSE,
4622 EL_BUG, ACTION_EXPLODING, -1
4625 Xboom_bomb, FALSE, FALSE,
4626 EL_BOMB, ACTION_EXPLODING, -1
4629 Xboom_android, FALSE, FALSE,
4630 EL_EMC_ANDROID, ACTION_OTHER, -1
4633 Xboom_1, FALSE, FALSE,
4634 EL_DEFAULT, ACTION_EXPLODING, -1
4637 Xboom_2, FALSE, FALSE,
4638 EL_DEFAULT, ACTION_EXPLODING, -1
4641 Znormal, FALSE, FALSE,
4645 Zdynamite, FALSE, FALSE,
4649 Zplayer, FALSE, FALSE,
4653 ZBORDER, FALSE, FALSE,
4663 static struct Mapping_EM_to_RND_player
4672 em_player_mapping_list[] =
4676 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4680 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4684 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4688 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4692 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4696 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4700 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4704 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4708 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4712 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4716 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4720 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4724 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4728 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4732 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4736 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4740 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4744 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4748 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4752 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4756 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4760 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4764 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4768 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4772 EL_PLAYER_1, ACTION_DEFAULT, -1,
4776 EL_PLAYER_2, ACTION_DEFAULT, -1,
4780 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4784 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4788 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4792 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4796 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4800 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4804 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4808 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4812 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4816 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4820 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4824 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4828 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4832 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4836 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4840 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4844 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4848 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4852 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4856 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4860 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4864 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4868 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4872 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
4876 EL_PLAYER_3, ACTION_DEFAULT, -1,
4880 EL_PLAYER_4, ACTION_DEFAULT, -1,
4889 int map_element_RND_to_EM(int element_rnd)
4891 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4892 static boolean mapping_initialized = FALSE;
4894 if (!mapping_initialized)
4898 /* return "Xalpha_quest" for all undefined elements in mapping array */
4899 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4900 mapping_RND_to_EM[i] = Xalpha_quest;
4902 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4903 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
4904 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
4905 em_object_mapping_list[i].element_em;
4907 mapping_initialized = TRUE;
4910 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4911 return mapping_RND_to_EM[element_rnd];
4913 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4918 int map_element_EM_to_RND(int element_em)
4920 static unsigned short mapping_EM_to_RND[TILE_MAX];
4921 static boolean mapping_initialized = FALSE;
4923 if (!mapping_initialized)
4927 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
4928 for (i = 0; i < TILE_MAX; i++)
4929 mapping_EM_to_RND[i] = EL_UNKNOWN;
4931 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4932 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
4933 em_object_mapping_list[i].element_rnd;
4935 mapping_initialized = TRUE;
4938 if (element_em >= 0 && element_em < TILE_MAX)
4939 return mapping_EM_to_RND[element_em];
4941 Error(ERR_WARN, "invalid EM level element %d", element_em);
4946 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
4948 struct LevelInfo_EM *level_em = level->native_em_level;
4949 struct LEVEL *lev = level_em->lev;
4952 for (i = 0; i < TILE_MAX; i++)
4953 lev->android_array[i] = Xblank;
4955 for (i = 0; i < level->num_android_clone_elements; i++)
4957 int element_rnd = level->android_clone_element[i];
4958 int element_em = map_element_RND_to_EM(element_rnd);
4960 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
4961 if (em_object_mapping_list[j].element_rnd == element_rnd)
4962 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
4966 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
4968 struct LevelInfo_EM *level_em = level->native_em_level;
4969 struct LEVEL *lev = level_em->lev;
4972 level->num_android_clone_elements = 0;
4974 for (i = 0; i < TILE_MAX; i++)
4976 int element_em = lev->android_array[i];
4978 boolean element_found = FALSE;
4980 if (element_em == Xblank)
4983 element_rnd = map_element_EM_to_RND(element_em);
4985 for (j = 0; j < level->num_android_clone_elements; j++)
4986 if (level->android_clone_element[j] == element_rnd)
4987 element_found = TRUE;
4991 level->android_clone_element[level->num_android_clone_elements++] =
4994 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
4999 if (level->num_android_clone_elements == 0)
5001 level->num_android_clone_elements = 1;
5002 level->android_clone_element[0] = EL_EMPTY;
5006 int map_direction_RND_to_EM(int direction)
5008 return (direction == MV_UP ? 0 :
5009 direction == MV_RIGHT ? 1 :
5010 direction == MV_DOWN ? 2 :
5011 direction == MV_LEFT ? 3 :
5015 int map_direction_EM_to_RND(int direction)
5017 return (direction == 0 ? MV_UP :
5018 direction == 1 ? MV_RIGHT :
5019 direction == 2 ? MV_DOWN :
5020 direction == 3 ? MV_LEFT :
5024 int get_next_element(int element)
5028 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5029 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5030 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5031 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5032 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5033 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5034 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5036 default: return element;
5041 int el_act_dir2img(int element, int action, int direction)
5043 element = GFX_ELEMENT(element);
5045 if (direction == MV_NONE)
5046 return element_info[element].graphic[action];
5048 direction = MV_DIR_TO_BIT(direction);
5050 return element_info[element].direction_graphic[action][direction];
5053 int el_act_dir2img(int element, int action, int direction)
5055 element = GFX_ELEMENT(element);
5056 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5058 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5059 return element_info[element].direction_graphic[action][direction];
5064 static int el_act_dir2crm(int element, int action, int direction)
5066 element = GFX_ELEMENT(element);
5068 if (direction == MV_NONE)
5069 return element_info[element].crumbled[action];
5071 direction = MV_DIR_TO_BIT(direction);
5073 return element_info[element].direction_crumbled[action][direction];
5076 static int el_act_dir2crm(int element, int action, int direction)
5078 element = GFX_ELEMENT(element);
5079 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5081 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5082 return element_info[element].direction_crumbled[action][direction];
5086 int el_act2img(int element, int action)
5088 element = GFX_ELEMENT(element);
5090 return element_info[element].graphic[action];
5093 int el_act2crm(int element, int action)
5095 element = GFX_ELEMENT(element);
5097 return element_info[element].crumbled[action];
5100 int el_dir2img(int element, int direction)
5102 element = GFX_ELEMENT(element);
5104 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5107 int el2baseimg(int element)
5109 return element_info[element].graphic[ACTION_DEFAULT];
5112 int el2img(int element)
5114 element = GFX_ELEMENT(element);
5116 return element_info[element].graphic[ACTION_DEFAULT];
5119 int el2edimg(int element)
5121 element = GFX_ELEMENT(element);
5123 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5126 int el2preimg(int element)
5128 element = GFX_ELEMENT(element);
5130 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5133 int font2baseimg(int font_nr)
5135 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5139 void setCenteredPlayerNr_EM(int centered_player_nr)
5141 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5144 int getCenteredPlayerNr_EM()
5147 if (game.centered_player_nr_next >= 0 &&
5148 !native_em_level.ply[game.centered_player_nr_next]->alive)
5149 game.centered_player_nr_next = game.centered_player_nr;
5152 if (game.centered_player_nr != game.centered_player_nr_next)
5153 game.centered_player_nr = game.centered_player_nr_next;
5155 return game.centered_player_nr;
5158 void setSetCenteredPlayer_EM(boolean set_centered_player)
5160 game.set_centered_player = set_centered_player;
5163 boolean getSetCenteredPlayer_EM()
5165 return game.set_centered_player;
5169 int getNumActivePlayers_EM()
5171 int num_players = 0;
5177 for (i = 0; i < MAX_PLAYERS; i++)
5178 if (tape.player_participates[i])
5185 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5187 int game_frame_delay_value;
5189 game_frame_delay_value =
5190 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5191 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5194 if (tape.playing && tape.warp_forward && !tape.pausing)
5195 game_frame_delay_value = 0;
5197 return game_frame_delay_value;
5201 unsigned int InitRND(long seed)
5203 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5204 return InitEngineRND_EM(seed);
5206 return InitEngineRND(seed);
5209 void InitGraphicInfo_EM(void)
5211 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5212 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5216 int num_em_gfx_errors = 0;
5218 if (graphic_info_em_object[0][0].bitmap == NULL)
5220 /* EM graphics not yet initialized in em_open_all() */
5225 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5228 /* always start with reliable default values */
5229 for (i = 0; i < TILE_MAX; i++)
5231 object_mapping[i].element_rnd = EL_UNKNOWN;
5232 object_mapping[i].is_backside = FALSE;
5233 object_mapping[i].action = ACTION_DEFAULT;
5234 object_mapping[i].direction = MV_NONE;
5237 /* always start with reliable default values */
5238 for (p = 0; p < MAX_PLAYERS; p++)
5240 for (i = 0; i < SPR_MAX; i++)
5242 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5243 player_mapping[p][i].action = ACTION_DEFAULT;
5244 player_mapping[p][i].direction = MV_NONE;
5248 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5250 int e = em_object_mapping_list[i].element_em;
5252 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5253 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5255 if (em_object_mapping_list[i].action != -1)
5256 object_mapping[e].action = em_object_mapping_list[i].action;
5258 if (em_object_mapping_list[i].direction != -1)
5259 object_mapping[e].direction =
5260 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5263 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5265 int a = em_player_mapping_list[i].action_em;
5266 int p = em_player_mapping_list[i].player_nr;
5268 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5270 if (em_player_mapping_list[i].action != -1)
5271 player_mapping[p][a].action = em_player_mapping_list[i].action;
5273 if (em_player_mapping_list[i].direction != -1)
5274 player_mapping[p][a].direction =
5275 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5278 for (i = 0; i < TILE_MAX; i++)
5280 int element = object_mapping[i].element_rnd;
5281 int action = object_mapping[i].action;
5282 int direction = object_mapping[i].direction;
5283 boolean is_backside = object_mapping[i].is_backside;
5284 boolean action_removing = (action == ACTION_DIGGING ||
5285 action == ACTION_SNAPPING ||
5286 action == ACTION_COLLECTING);
5287 boolean action_exploding = ((action == ACTION_EXPLODING ||
5288 action == ACTION_SMASHED_BY_ROCK ||
5289 action == ACTION_SMASHED_BY_SPRING) &&
5290 element != EL_DIAMOND);
5291 boolean action_active = (action == ACTION_ACTIVE);
5292 boolean action_other = (action == ACTION_OTHER);
5294 for (j = 0; j < 8; j++)
5296 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5297 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5299 i == Xdrip_stretch ? element :
5300 i == Xdrip_stretchB ? element :
5301 i == Ydrip_s1 ? element :
5302 i == Ydrip_s1B ? element :
5303 i == Xball_1B ? element :
5304 i == Xball_2 ? element :
5305 i == Xball_2B ? element :
5306 i == Yball_eat ? element :
5307 i == Ykey_1_eat ? element :
5308 i == Ykey_2_eat ? element :
5309 i == Ykey_3_eat ? element :
5310 i == Ykey_4_eat ? element :
5311 i == Ykey_5_eat ? element :
5312 i == Ykey_6_eat ? element :
5313 i == Ykey_7_eat ? element :
5314 i == Ykey_8_eat ? element :
5315 i == Ylenses_eat ? element :
5316 i == Ymagnify_eat ? element :
5317 i == Ygrass_eat ? element :
5318 i == Ydirt_eat ? element :
5319 i == Yemerald_stone ? EL_EMERALD :
5320 i == Ydiamond_stone ? EL_ROCK :
5321 i == Xsand_stonein_1 ? element :
5322 i == Xsand_stonein_2 ? element :
5323 i == Xsand_stonein_3 ? element :
5324 i == Xsand_stonein_4 ? element :
5325 is_backside ? EL_EMPTY :
5326 action_removing ? EL_EMPTY :
5328 int effective_action = (j < 7 ? action :
5329 i == Xdrip_stretch ? action :
5330 i == Xdrip_stretchB ? action :
5331 i == Ydrip_s1 ? action :
5332 i == Ydrip_s1B ? action :
5333 i == Xball_1B ? action :
5334 i == Xball_2 ? action :
5335 i == Xball_2B ? action :
5336 i == Yball_eat ? action :
5337 i == Ykey_1_eat ? action :
5338 i == Ykey_2_eat ? action :
5339 i == Ykey_3_eat ? action :
5340 i == Ykey_4_eat ? action :
5341 i == Ykey_5_eat ? action :
5342 i == Ykey_6_eat ? action :
5343 i == Ykey_7_eat ? action :
5344 i == Ykey_8_eat ? action :
5345 i == Ylenses_eat ? action :
5346 i == Ymagnify_eat ? action :
5347 i == Ygrass_eat ? action :
5348 i == Ydirt_eat ? action :
5349 i == Xsand_stonein_1 ? action :
5350 i == Xsand_stonein_2 ? action :
5351 i == Xsand_stonein_3 ? action :
5352 i == Xsand_stonein_4 ? action :
5353 i == Xsand_stoneout_1 ? action :
5354 i == Xsand_stoneout_2 ? action :
5355 i == Xboom_android ? ACTION_EXPLODING :
5356 action_exploding ? ACTION_EXPLODING :
5357 action_active ? action :
5358 action_other ? action :
5360 int graphic = (el_act_dir2img(effective_element, effective_action,
5362 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5364 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5365 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5366 boolean has_action_graphics = (graphic != base_graphic);
5367 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5368 struct GraphicInfo *g = &graphic_info[graphic];
5369 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5372 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5373 boolean special_animation = (action != ACTION_DEFAULT &&
5374 g->anim_frames == 3 &&
5375 g->anim_delay == 2 &&
5376 g->anim_mode & ANIM_LINEAR);
5377 int sync_frame = (i == Xdrip_stretch ? 7 :
5378 i == Xdrip_stretchB ? 7 :
5379 i == Ydrip_s2 ? j + 8 :
5380 i == Ydrip_s2B ? j + 8 :
5389 i == Xfake_acid_1 ? 0 :
5390 i == Xfake_acid_2 ? 10 :
5391 i == Xfake_acid_3 ? 20 :
5392 i == Xfake_acid_4 ? 30 :
5393 i == Xfake_acid_5 ? 40 :
5394 i == Xfake_acid_6 ? 50 :
5395 i == Xfake_acid_7 ? 60 :
5396 i == Xfake_acid_8 ? 70 :
5398 i == Xball_2B ? j + 8 :
5399 i == Yball_eat ? j + 1 :
5400 i == Ykey_1_eat ? j + 1 :
5401 i == Ykey_2_eat ? j + 1 :
5402 i == Ykey_3_eat ? j + 1 :
5403 i == Ykey_4_eat ? j + 1 :
5404 i == Ykey_5_eat ? j + 1 :
5405 i == Ykey_6_eat ? j + 1 :
5406 i == Ykey_7_eat ? j + 1 :
5407 i == Ykey_8_eat ? j + 1 :
5408 i == Ylenses_eat ? j + 1 :
5409 i == Ymagnify_eat ? j + 1 :
5410 i == Ygrass_eat ? j + 1 :
5411 i == Ydirt_eat ? j + 1 :
5412 i == Xamoeba_1 ? 0 :
5413 i == Xamoeba_2 ? 1 :
5414 i == Xamoeba_3 ? 2 :
5415 i == Xamoeba_4 ? 3 :
5416 i == Xamoeba_5 ? 0 :
5417 i == Xamoeba_6 ? 1 :
5418 i == Xamoeba_7 ? 2 :
5419 i == Xamoeba_8 ? 3 :
5420 i == Xexit_2 ? j + 8 :
5421 i == Xexit_3 ? j + 16 :
5422 i == Xdynamite_1 ? 0 :
5423 i == Xdynamite_2 ? 8 :
5424 i == Xdynamite_3 ? 16 :
5425 i == Xdynamite_4 ? 24 :
5426 i == Xsand_stonein_1 ? j + 1 :
5427 i == Xsand_stonein_2 ? j + 9 :
5428 i == Xsand_stonein_3 ? j + 17 :
5429 i == Xsand_stonein_4 ? j + 25 :
5430 i == Xsand_stoneout_1 && j == 0 ? 0 :
5431 i == Xsand_stoneout_1 && j == 1 ? 0 :
5432 i == Xsand_stoneout_1 && j == 2 ? 1 :
5433 i == Xsand_stoneout_1 && j == 3 ? 2 :
5434 i == Xsand_stoneout_1 && j == 4 ? 2 :
5435 i == Xsand_stoneout_1 && j == 5 ? 3 :
5436 i == Xsand_stoneout_1 && j == 6 ? 4 :
5437 i == Xsand_stoneout_1 && j == 7 ? 4 :
5438 i == Xsand_stoneout_2 && j == 0 ? 5 :
5439 i == Xsand_stoneout_2 && j == 1 ? 6 :
5440 i == Xsand_stoneout_2 && j == 2 ? 7 :
5441 i == Xsand_stoneout_2 && j == 3 ? 8 :
5442 i == Xsand_stoneout_2 && j == 4 ? 9 :
5443 i == Xsand_stoneout_2 && j == 5 ? 11 :
5444 i == Xsand_stoneout_2 && j == 6 ? 13 :
5445 i == Xsand_stoneout_2 && j == 7 ? 15 :
5446 i == Xboom_bug && j == 1 ? 2 :
5447 i == Xboom_bug && j == 2 ? 2 :
5448 i == Xboom_bug && j == 3 ? 4 :
5449 i == Xboom_bug && j == 4 ? 4 :
5450 i == Xboom_bug && j == 5 ? 2 :
5451 i == Xboom_bug && j == 6 ? 2 :
5452 i == Xboom_bug && j == 7 ? 0 :
5453 i == Xboom_bomb && j == 1 ? 2 :
5454 i == Xboom_bomb && j == 2 ? 2 :
5455 i == Xboom_bomb && j == 3 ? 4 :
5456 i == Xboom_bomb && j == 4 ? 4 :
5457 i == Xboom_bomb && j == 5 ? 2 :
5458 i == Xboom_bomb && j == 6 ? 2 :
5459 i == Xboom_bomb && j == 7 ? 0 :
5460 i == Xboom_android && j == 7 ? 6 :
5461 i == Xboom_1 && j == 1 ? 2 :
5462 i == Xboom_1 && j == 2 ? 2 :
5463 i == Xboom_1 && j == 3 ? 4 :
5464 i == Xboom_1 && j == 4 ? 4 :
5465 i == Xboom_1 && j == 5 ? 6 :
5466 i == Xboom_1 && j == 6 ? 6 :
5467 i == Xboom_1 && j == 7 ? 8 :
5468 i == Xboom_2 && j == 0 ? 8 :
5469 i == Xboom_2 && j == 1 ? 8 :
5470 i == Xboom_2 && j == 2 ? 10 :
5471 i == Xboom_2 && j == 3 ? 10 :
5472 i == Xboom_2 && j == 4 ? 10 :
5473 i == Xboom_2 && j == 5 ? 12 :
5474 i == Xboom_2 && j == 6 ? 12 :
5475 i == Xboom_2 && j == 7 ? 12 :
5476 special_animation && j == 4 ? 3 :
5477 effective_action != action ? 0 :
5481 Bitmap *debug_bitmap = g_em->bitmap;
5482 int debug_src_x = g_em->src_x;
5483 int debug_src_y = g_em->src_y;
5486 int frame = getAnimationFrame(g->anim_frames,
5489 g->anim_start_frame,
5492 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5493 g->double_movement && is_backside);
5495 g_em->bitmap = src_bitmap;
5496 g_em->src_x = src_x;
5497 g_em->src_y = src_y;
5498 g_em->src_offset_x = 0;
5499 g_em->src_offset_y = 0;
5500 g_em->dst_offset_x = 0;
5501 g_em->dst_offset_y = 0;
5502 g_em->width = TILEX;
5503 g_em->height = TILEY;
5505 g_em->crumbled_bitmap = NULL;
5506 g_em->crumbled_src_x = 0;
5507 g_em->crumbled_src_y = 0;
5508 g_em->crumbled_border_size = 0;
5510 g_em->has_crumbled_graphics = FALSE;
5511 g_em->preserve_background = FALSE;
5514 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5515 printf("::: empty crumbled: %d [%s], %d, %d\n",
5516 effective_element, element_info[effective_element].token_name,
5517 effective_action, direction);
5520 /* if element can be crumbled, but certain action graphics are just empty
5521 space (like snapping sand with the original R'n'D graphics), do not
5522 treat these empty space graphics as crumbled graphics in EMC engine */
5523 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5525 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5527 g_em->has_crumbled_graphics = TRUE;
5528 g_em->crumbled_bitmap = src_bitmap;
5529 g_em->crumbled_src_x = src_x;
5530 g_em->crumbled_src_y = src_y;
5531 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5535 if (element == EL_ROCK &&
5536 effective_action == ACTION_FILLING)
5537 printf("::: has_action_graphics == %d\n", has_action_graphics);
5540 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5541 effective_action == ACTION_MOVING ||
5542 effective_action == ACTION_PUSHING ||
5543 effective_action == ACTION_EATING)) ||
5544 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5545 effective_action == ACTION_EMPTYING)))
5548 (effective_action == ACTION_FALLING ||
5549 effective_action == ACTION_FILLING ||
5550 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5551 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5552 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5553 int num_steps = (i == Ydrip_s1 ? 16 :
5554 i == Ydrip_s1B ? 16 :
5555 i == Ydrip_s2 ? 16 :
5556 i == Ydrip_s2B ? 16 :
5557 i == Xsand_stonein_1 ? 32 :
5558 i == Xsand_stonein_2 ? 32 :
5559 i == Xsand_stonein_3 ? 32 :
5560 i == Xsand_stonein_4 ? 32 :
5561 i == Xsand_stoneout_1 ? 16 :
5562 i == Xsand_stoneout_2 ? 16 : 8);
5563 int cx = ABS(dx) * (TILEX / num_steps);
5564 int cy = ABS(dy) * (TILEY / num_steps);
5565 int step_frame = (i == Ydrip_s2 ? j + 8 :
5566 i == Ydrip_s2B ? j + 8 :
5567 i == Xsand_stonein_2 ? j + 8 :
5568 i == Xsand_stonein_3 ? j + 16 :
5569 i == Xsand_stonein_4 ? j + 24 :
5570 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5571 int step = (is_backside ? step_frame : num_steps - step_frame);
5573 if (is_backside) /* tile where movement starts */
5575 if (dx < 0 || dy < 0)
5577 g_em->src_offset_x = cx * step;
5578 g_em->src_offset_y = cy * step;
5582 g_em->dst_offset_x = cx * step;
5583 g_em->dst_offset_y = cy * step;
5586 else /* tile where movement ends */
5588 if (dx < 0 || dy < 0)
5590 g_em->dst_offset_x = cx * step;
5591 g_em->dst_offset_y = cy * step;
5595 g_em->src_offset_x = cx * step;
5596 g_em->src_offset_y = cy * step;
5600 g_em->width = TILEX - cx * step;
5601 g_em->height = TILEY - cy * step;
5605 /* create unique graphic identifier to decide if tile must be redrawn */
5606 /* bit 31 - 16 (16 bit): EM style graphic
5607 bit 15 - 12 ( 4 bit): EM style frame
5608 bit 11 - 6 ( 6 bit): graphic width
5609 bit 5 - 0 ( 6 bit): graphic height */
5610 g_em->unique_identifier =
5611 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5613 /* create unique graphic identifier to decide if tile must be redrawn */
5614 /* bit 31 - 16 (16 bit): EM style element
5615 bit 15 - 12 ( 4 bit): EM style frame
5616 bit 11 - 6 ( 6 bit): graphic width
5617 bit 5 - 0 ( 6 bit): graphic height */
5618 g_em->unique_identifier =
5619 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5623 if (effective_element == EL_ROCK)
5624 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5625 effective_action, j, graphic, frame, g_em->unique_identifier);
5631 /* skip check for EMC elements not contained in original EMC artwork */
5632 if (element == EL_EMC_FAKE_ACID)
5636 if (g_em->bitmap != debug_bitmap ||
5637 g_em->src_x != debug_src_x ||
5638 g_em->src_y != debug_src_y ||
5639 g_em->src_offset_x != 0 ||
5640 g_em->src_offset_y != 0 ||
5641 g_em->dst_offset_x != 0 ||
5642 g_em->dst_offset_y != 0 ||
5643 g_em->width != TILEX ||
5644 g_em->height != TILEY)
5646 static int last_i = -1;
5654 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5655 i, element, element_info[element].token_name,
5656 element_action_info[effective_action].suffix, direction);
5658 if (element != effective_element)
5659 printf(" [%d ('%s')]",
5661 element_info[effective_element].token_name);
5665 if (g_em->bitmap != debug_bitmap)
5666 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5667 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5669 if (g_em->src_x != debug_src_x ||
5670 g_em->src_y != debug_src_y)
5671 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5672 j, (is_backside ? 'B' : 'F'),
5673 g_em->src_x, g_em->src_y,
5674 g_em->src_x / 32, g_em->src_y / 32,
5675 debug_src_x, debug_src_y,
5676 debug_src_x / 32, debug_src_y / 32);
5678 if (g_em->src_offset_x != 0 ||
5679 g_em->src_offset_y != 0 ||
5680 g_em->dst_offset_x != 0 ||
5681 g_em->dst_offset_y != 0)
5682 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5684 g_em->src_offset_x, g_em->src_offset_y,
5685 g_em->dst_offset_x, g_em->dst_offset_y);
5687 if (g_em->width != TILEX ||
5688 g_em->height != TILEY)
5689 printf(" %d (%d): size %d,%d should be %d,%d\n",
5691 g_em->width, g_em->height, TILEX, TILEY);
5693 num_em_gfx_errors++;
5700 for (i = 0; i < TILE_MAX; i++)
5702 for (j = 0; j < 8; j++)
5704 int element = object_mapping[i].element_rnd;
5705 int action = object_mapping[i].action;
5706 int direction = object_mapping[i].direction;
5707 boolean is_backside = object_mapping[i].is_backside;
5709 int graphic_action = el_act_dir2img(element, action, direction);
5710 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5712 int graphic_action = element_info[element].graphic[action];
5713 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5716 if ((action == ACTION_SMASHED_BY_ROCK ||
5717 action == ACTION_SMASHED_BY_SPRING ||
5718 action == ACTION_EATING) &&
5719 graphic_action == graphic_default)
5721 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5722 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5723 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5724 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5727 /* no separate animation for "smashed by rock" -- use rock instead */
5728 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5729 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5731 g_em->bitmap = g_xx->bitmap;
5732 g_em->src_x = g_xx->src_x;
5733 g_em->src_y = g_xx->src_y;
5734 g_em->src_offset_x = g_xx->src_offset_x;
5735 g_em->src_offset_y = g_xx->src_offset_y;
5736 g_em->dst_offset_x = g_xx->dst_offset_x;
5737 g_em->dst_offset_y = g_xx->dst_offset_y;
5738 g_em->width = g_xx->width;
5739 g_em->height = g_xx->height;
5741 g_em->unique_identifier = g_xx->unique_identifier;
5745 g_em->preserve_background = TRUE;
5750 for (p = 0; p < MAX_PLAYERS; p++)
5752 for (i = 0; i < SPR_MAX; i++)
5754 int element = player_mapping[p][i].element_rnd;
5755 int action = player_mapping[p][i].action;
5756 int direction = player_mapping[p][i].direction;
5758 for (j = 0; j < 8; j++)
5760 int effective_element = element;
5761 int effective_action = action;
5762 int graphic = (direction == MV_NONE ?
5763 el_act2img(effective_element, effective_action) :
5764 el_act_dir2img(effective_element, effective_action,
5766 struct GraphicInfo *g = &graphic_info[graphic];
5767 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5773 Bitmap *debug_bitmap = g_em->bitmap;
5774 int debug_src_x = g_em->src_x;
5775 int debug_src_y = g_em->src_y;
5778 int frame = getAnimationFrame(g->anim_frames,
5781 g->anim_start_frame,
5784 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5786 g_em->bitmap = src_bitmap;
5787 g_em->src_x = src_x;
5788 g_em->src_y = src_y;
5789 g_em->src_offset_x = 0;
5790 g_em->src_offset_y = 0;
5791 g_em->dst_offset_x = 0;
5792 g_em->dst_offset_y = 0;
5793 g_em->width = TILEX;
5794 g_em->height = TILEY;
5799 /* skip check for EMC elements not contained in original EMC artwork */
5800 if (element == EL_PLAYER_3 ||
5801 element == EL_PLAYER_4)
5805 if (g_em->bitmap != debug_bitmap ||
5806 g_em->src_x != debug_src_x ||
5807 g_em->src_y != debug_src_y)
5809 static int last_i = -1;
5817 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5818 p, i, element, element_info[element].token_name,
5819 element_action_info[effective_action].suffix, direction);
5821 if (element != effective_element)
5822 printf(" [%d ('%s')]",
5824 element_info[effective_element].token_name);
5828 if (g_em->bitmap != debug_bitmap)
5829 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5830 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5832 if (g_em->src_x != debug_src_x ||
5833 g_em->src_y != debug_src_y)
5834 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5836 g_em->src_x, g_em->src_y,
5837 g_em->src_x / 32, g_em->src_y / 32,
5838 debug_src_x, debug_src_y,
5839 debug_src_x / 32, debug_src_y / 32);
5841 num_em_gfx_errors++;
5851 printf("::: [%d errors found]\n", num_em_gfx_errors);