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"
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES 0
25 #define TOOL_CTRL_ID_NO 1
26 #define TOOL_CTRL_ID_CONFIRM 2
27 #define TOOL_CTRL_ID_PLAYER_1 3
28 #define TOOL_CTRL_ID_PLAYER_2 4
29 #define TOOL_CTRL_ID_PLAYER_3 5
30 #define TOOL_CTRL_ID_PLAYER_4 6
32 #define NUM_TOOL_BUTTONS 7
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
37 static int el_act_dir2crm(int, int, int);
38 static int el_act2crm(int, int);
40 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
41 static int request_gadget_id = -1;
43 static char *print_if_not_empty(int element)
45 static char *s = NULL;
46 char *token_name = element_info[element].token_name;
51 s = checked_malloc(strlen(token_name) + 10 + 1);
53 if (element != EL_EMPTY)
54 sprintf(s, "%d\t['%s']", element, token_name);
56 sprintf(s, "%d", element);
61 void DumpTile(int x, int y)
66 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
73 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
76 if (!IN_LEV_FIELD(x, y))
78 printf("(not in level field)\n");
84 printf(" Feld: %d\t['%s']\n", Feld[x][y],
85 element_info[Feld[x][y]].token_name);
86 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
87 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
88 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
89 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
90 printf(" MovPos: %d\n", MovPos[x][y]);
91 printf(" MovDir: %d\n", MovDir[x][y]);
92 printf(" MovDelay: %d\n", MovDelay[x][y]);
93 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
94 printf(" CustomValue: %d\n", CustomValue[x][y]);
95 printf(" GfxElement: %d\n", GfxElement[x][y]);
96 printf(" GfxAction: %d\n", GfxAction[x][y]);
97 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
101 void SetDrawtoField(int mode)
103 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
114 drawto_field = fieldbuffer;
116 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
122 BX2 = SCR_FIELDX - 1;
123 BY2 = SCR_FIELDY - 1;
127 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
131 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
133 if (game_status == GAME_MODE_PLAYING &&
134 level.game_engine_type == GAME_ENGINE_TYPE_EM)
136 /* currently there is no partial redraw -- always redraw whole playfield */
138 RedrawPlayfield_EM(TRUE);
140 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
146 width = gfx.sxsize + 2 * TILEX;
147 height = gfx.sysize + 2 * TILEY;
150 if (force_redraw || setup.direct_draw)
153 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
154 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
156 if (setup.direct_draw)
157 SetDrawtoField(DRAW_BACKBUFFER);
159 for (xx = BX1; xx <= BX2; xx++)
160 for (yy = BY1; yy <= BY2; yy++)
161 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
162 DrawScreenField(xx, yy);
165 if (setup.direct_draw)
166 SetDrawtoField(DRAW_DIRECT);
169 if (setup.soft_scrolling)
171 int fx = FX, fy = FY;
173 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
174 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
176 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
180 BlitBitmap(drawto, window, x, y, width, height, x, y);
186 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
188 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
189 redraw_mask &= ~REDRAW_MAIN;
191 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
192 redraw_mask |= REDRAW_FIELD;
194 if (redraw_mask & REDRAW_FIELD)
195 redraw_mask &= ~REDRAW_TILES;
197 if (redraw_mask == REDRAW_NONE)
200 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
202 static boolean last_frame_skipped = FALSE;
203 boolean skip_even_when_not_scrolling = TRUE;
204 boolean just_scrolling = (ScreenMovDir != 0);
205 boolean verbose = FALSE;
207 if (global.fps_slowdown_factor > 1 &&
208 (FrameCounter % global.fps_slowdown_factor) &&
209 (just_scrolling || skip_even_when_not_scrolling))
211 redraw_mask &= ~REDRAW_MAIN;
213 last_frame_skipped = TRUE;
216 printf("FRAME SKIPPED\n");
220 if (last_frame_skipped)
221 redraw_mask |= REDRAW_FIELD;
223 last_frame_skipped = FALSE;
226 printf("frame not skipped\n");
230 /* synchronize X11 graphics at this point; if we would synchronize the
231 display immediately after the buffer switching (after the XFlush),
232 this could mean that we have to wait for the graphics to complete,
233 although we could go on doing calculations for the next frame */
237 if (redraw_mask & REDRAW_ALL)
239 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
243 if (redraw_mask & REDRAW_FIELD)
245 if (game_status != GAME_MODE_PLAYING ||
246 redraw_mask & REDRAW_FROM_BACKBUFFER)
248 BlitBitmap(backbuffer, window,
249 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
253 int fx = FX, fy = FY;
255 if (setup.soft_scrolling)
257 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
258 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
261 if (setup.soft_scrolling ||
262 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
263 ABS(ScreenMovPos) == ScrollStepSize ||
264 redraw_tiles > REDRAWTILES_THRESHOLD)
266 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
270 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
272 (setup.soft_scrolling ?
273 "setup.soft_scrolling" :
274 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
275 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
276 ABS(ScreenGfxPos) == ScrollStepSize ?
277 "ABS(ScreenGfxPos) == ScrollStepSize" :
278 "redraw_tiles > REDRAWTILES_THRESHOLD"));
284 redraw_mask &= ~REDRAW_MAIN;
287 if (redraw_mask & REDRAW_DOORS)
289 if (redraw_mask & REDRAW_DOOR_1)
290 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
292 if (redraw_mask & REDRAW_DOOR_2)
293 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
295 if (redraw_mask & REDRAW_DOOR_3)
296 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
298 redraw_mask &= ~REDRAW_DOORS;
301 if (redraw_mask & REDRAW_MICROLEVEL)
303 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
304 SX, SY + 10 * TILEY);
306 redraw_mask &= ~REDRAW_MICROLEVEL;
309 if (redraw_mask & REDRAW_TILES)
311 for (x = 0; x < SCR_FIELDX; x++)
312 for (y = 0 ; y < SCR_FIELDY; y++)
313 if (redraw[redraw_x1 + x][redraw_y1 + y])
314 BlitBitmap(buffer, window,
315 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
316 SX + x * TILEX, SY + y * TILEY);
319 if (redraw_mask & REDRAW_FPS) /* display frames per second */
324 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
325 if (!global.fps_slowdown)
328 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
329 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
334 for (x = 0; x < MAX_BUF_XSIZE; x++)
335 for (y = 0; y < MAX_BUF_YSIZE; y++)
338 redraw_mask = REDRAW_NONE;
344 long fading_delay = 300;
346 if (setup.fading && (redraw_mask & REDRAW_FIELD))
353 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
356 for (i = 0; i < 2 * FULL_SYSIZE; i++)
358 for (y = 0; y < FULL_SYSIZE; y++)
360 BlitBitmap(backbuffer, window,
361 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
369 for (i = 1; i < FULL_SYSIZE; i+=2)
370 BlitBitmap(backbuffer, window,
371 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
377 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
378 BlitBitmapMasked(backbuffer, window,
379 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
384 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
385 BlitBitmapMasked(backbuffer, window,
386 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
391 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
392 BlitBitmapMasked(backbuffer, window,
393 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
398 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
399 BlitBitmapMasked(backbuffer, window,
400 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
405 redraw_mask &= ~REDRAW_MAIN;
412 void SetMainBackgroundImageIfDefined(int graphic)
414 if (graphic_info[graphic].bitmap)
415 SetMainBackgroundImage(graphic);
418 void SetMainBackgroundImage(int graphic)
420 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
421 graphic_info[graphic].bitmap ?
422 graphic_info[graphic].bitmap :
423 graphic_info[IMG_BACKGROUND].bitmap);
426 void SetDoorBackgroundImage(int graphic)
428 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
429 graphic_info[graphic].bitmap ?
430 graphic_info[graphic].bitmap :
431 graphic_info[IMG_BACKGROUND].bitmap);
434 void DrawBackground(int dst_x, int dst_y, int width, int height)
436 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
438 redraw_mask |= REDRAW_FIELD;
443 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
445 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
447 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
448 SetDrawtoField(DRAW_BUFFERED);
451 SetDrawtoField(DRAW_BACKBUFFER);
453 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
455 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
456 SetDrawtoField(DRAW_DIRECT);
460 void MarkTileDirty(int x, int y)
462 int xx = redraw_x1 + x;
463 int yy = redraw_y1 + y;
468 redraw[xx][yy] = TRUE;
469 redraw_mask |= REDRAW_TILES;
472 void SetBorderElement()
476 BorderElement = EL_EMPTY;
478 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
480 for (x = 0; x < lev_fieldx; x++)
482 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
483 BorderElement = EL_STEELWALL;
485 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
491 void SetRandomAnimationValue(int x, int y)
493 gfx.anim_random_frame = GfxRandom[x][y];
496 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
498 /* animation synchronized with global frame counter, not move position */
499 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
500 sync_frame = FrameCounter;
502 return getAnimationFrame(graphic_info[graphic].anim_frames,
503 graphic_info[graphic].anim_delay,
504 graphic_info[graphic].anim_mode,
505 graphic_info[graphic].anim_start_frame,
509 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
510 int *x, int *y, boolean get_backside)
512 struct GraphicInfo *g = &graphic_info[graphic];
513 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
514 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
518 if (g->offset_y == 0) /* frames are ordered horizontally */
520 int max_width = g->anim_frames_per_line * g->width;
521 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
523 *x = pos % max_width;
524 *y = src_y % g->height + pos / max_width * g->height;
526 else if (g->offset_x == 0) /* frames are ordered vertically */
528 int max_height = g->anim_frames_per_line * g->height;
529 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
531 *x = src_x % g->width + pos / max_height * g->width;
532 *y = pos % max_height;
534 else /* frames are ordered diagonally */
536 *x = src_x + frame * g->offset_x;
537 *y = src_y + frame * g->offset_y;
541 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
543 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
546 void DrawGraphic(int x, int y, int graphic, int frame)
549 if (!IN_SCR_FIELD(x, y))
551 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
552 printf("DrawGraphic(): This should never happen!\n");
557 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
561 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
567 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
568 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
571 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
574 if (!IN_SCR_FIELD(x, y))
576 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
577 printf("DrawGraphicThruMask(): This should never happen!\n");
582 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
587 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
593 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
595 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
596 dst_x - src_x, dst_y - src_y);
597 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
600 void DrawMiniGraphic(int x, int y, int graphic)
602 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
603 MarkTileDirty(x / 2, y / 2);
606 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
608 struct GraphicInfo *g = &graphic_info[graphic];
610 int mini_starty = g->bitmap->height * 2 / 3;
613 *x = mini_startx + g->src_x / 2;
614 *y = mini_starty + g->src_y / 2;
617 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
622 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
623 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
626 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
627 int graphic, int frame,
628 int cut_mode, int mask_mode)
633 int width = TILEX, height = TILEY;
636 if (dx || dy) /* shifted graphic */
638 if (x < BX1) /* object enters playfield from the left */
645 else if (x > BX2) /* object enters playfield from the right */
651 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
657 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
659 else if (dx) /* general horizontal movement */
660 MarkTileDirty(x + SIGN(dx), y);
662 if (y < BY1) /* object enters playfield from the top */
664 if (cut_mode==CUT_BELOW) /* object completely above top border */
672 else if (y > BY2) /* object enters playfield from the bottom */
678 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
684 else if (dy > 0 && cut_mode == CUT_ABOVE)
686 if (y == BY2) /* object completely above bottom border */
692 MarkTileDirty(x, y + 1);
693 } /* object leaves playfield to the bottom */
694 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
696 else if (dy) /* general vertical movement */
697 MarkTileDirty(x, y + SIGN(dy));
701 if (!IN_SCR_FIELD(x, y))
703 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
704 printf("DrawGraphicShifted(): This should never happen!\n");
709 if (width > 0 && height > 0)
711 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
716 dst_x = FX + x * TILEX + dx;
717 dst_y = FY + y * TILEY + dy;
719 if (mask_mode == USE_MASKING)
721 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
722 dst_x - src_x, dst_y - src_y);
723 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
727 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
734 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
735 int graphic, int frame,
736 int cut_mode, int mask_mode)
741 int width = TILEX, height = TILEY;
744 int x2 = x + SIGN(dx);
745 int y2 = y + SIGN(dy);
746 int anim_frames = graphic_info[graphic].anim_frames;
747 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
748 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
749 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
751 /* re-calculate animation frame for two-tile movement animation */
752 frame = getGraphicAnimationFrame(graphic, sync_frame);
754 /* check if movement start graphic inside screen area and should be drawn */
755 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
757 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
759 dst_x = FX + x1 * TILEX;
760 dst_y = FY + y1 * TILEY;
762 if (mask_mode == USE_MASKING)
764 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
765 dst_x - src_x, dst_y - src_y);
766 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
770 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
773 MarkTileDirty(x1, y1);
776 /* check if movement end graphic inside screen area and should be drawn */
777 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
779 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
781 dst_x = FX + x2 * TILEX;
782 dst_y = FY + y2 * TILEY;
784 if (mask_mode == USE_MASKING)
786 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
787 dst_x - src_x, dst_y - src_y);
788 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
792 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
795 MarkTileDirty(x2, y2);
799 static void DrawGraphicShifted(int x, int y, int dx, int dy,
800 int graphic, int frame,
801 int cut_mode, int mask_mode)
805 DrawGraphic(x, y, graphic, frame);
810 if (graphic_info[graphic].double_movement) /* EM style movement images */
811 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
813 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
816 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
817 int frame, int cut_mode)
819 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
822 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
823 int cut_mode, int mask_mode)
825 int lx = LEVELX(x), ly = LEVELY(y);
829 if (IN_LEV_FIELD(lx, ly))
831 SetRandomAnimationValue(lx, ly);
833 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
834 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
836 /* do not use double (EM style) movement graphic when not moving */
837 if (graphic_info[graphic].double_movement && !dx && !dy)
839 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
840 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
843 else /* border element */
845 graphic = el2img(element);
846 frame = getGraphicAnimationFrame(graphic, -1);
849 if (element == EL_EXPANDABLE_WALL)
851 boolean left_stopped = FALSE, right_stopped = FALSE;
853 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
855 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
856 right_stopped = TRUE;
858 if (left_stopped && right_stopped)
860 else if (left_stopped)
862 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
863 frame = graphic_info[graphic].anim_frames - 1;
865 else if (right_stopped)
867 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
868 frame = graphic_info[graphic].anim_frames - 1;
873 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
874 else if (mask_mode == USE_MASKING)
875 DrawGraphicThruMask(x, y, graphic, frame);
877 DrawGraphic(x, y, graphic, frame);
880 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
881 int cut_mode, int mask_mode)
883 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
884 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
885 cut_mode, mask_mode);
888 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
891 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
894 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
897 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
900 void DrawLevelElementThruMask(int x, int y, int element)
902 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
905 void DrawLevelFieldThruMask(int x, int y)
907 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
910 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
914 int sx = SCREENX(x), sy = SCREENY(y);
916 int width, height, cx, cy, i;
917 int crumbled_border_size = graphic_info[graphic].border_size;
918 static int xy[4][2] =
926 if (!IN_LEV_FIELD(x, y))
929 element = TILE_GFX_ELEMENT(x, y);
931 /* crumble field itself */
932 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
934 if (!IN_SCR_FIELD(sx, sy))
937 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
939 for (i = 0; i < 4; i++)
941 int xx = x + xy[i][0];
942 int yy = y + xy[i][1];
944 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
947 /* check if neighbour field is of same type */
948 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
951 if (i == 1 || i == 2)
953 width = crumbled_border_size;
955 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
961 height = crumbled_border_size;
963 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
966 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
967 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
970 MarkTileDirty(sx, sy);
972 else /* crumble neighbour fields */
974 for (i = 0; i < 4; i++)
976 int xx = x + xy[i][0];
977 int yy = y + xy[i][1];
978 int sxx = sx + xy[i][0];
979 int syy = sy + xy[i][1];
982 if (!IN_LEV_FIELD(xx, yy) ||
983 !IN_SCR_FIELD(sxx, syy) ||
988 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
992 element = TILE_GFX_ELEMENT(xx, yy);
994 if (!GFX_CRUMBLED(element))
997 if (!IN_LEV_FIELD(xx, yy) ||
998 !IN_SCR_FIELD(sxx, syy) ||
999 !GFX_CRUMBLED(Feld[xx][yy]) ||
1005 graphic = el_act2crm(element, ACTION_DEFAULT);
1007 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1009 crumbled_border_size = graphic_info[graphic].border_size;
1011 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1013 if (i == 1 || i == 2)
1015 width = crumbled_border_size;
1017 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1023 height = crumbled_border_size;
1025 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1028 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1029 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1031 MarkTileDirty(sxx, syy);
1036 void DrawLevelFieldCrumbledSand(int x, int y)
1040 if (!IN_LEV_FIELD(x, y))
1045 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1046 GFX_CRUMBLED(GfxElement[x][y]))
1049 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1050 GfxElement[x][y] != EL_UNDEFINED &&
1051 GFX_CRUMBLED(GfxElement[x][y]))
1053 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1060 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1062 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1065 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1068 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1071 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1072 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1073 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1074 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1075 int sx = SCREENX(x), sy = SCREENY(y);
1077 DrawGraphic(sx, sy, graphic1, frame1);
1078 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1081 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1083 int sx = SCREENX(x), sy = SCREENY(y);
1084 static int xy[4][2] =
1093 for (i = 0; i < 4; i++)
1095 int xx = x + xy[i][0];
1096 int yy = y + xy[i][1];
1097 int sxx = sx + xy[i][0];
1098 int syy = sy + xy[i][1];
1100 if (!IN_LEV_FIELD(xx, yy) ||
1101 !IN_SCR_FIELD(sxx, syy) ||
1102 !GFX_CRUMBLED(Feld[xx][yy]) ||
1106 DrawLevelField(xx, yy);
1110 static int getBorderElement(int x, int y)
1114 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1115 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1116 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1117 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1118 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1119 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1120 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1122 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1123 int steel_position = (x == -1 && y == -1 ? 0 :
1124 x == lev_fieldx && y == -1 ? 1 :
1125 x == -1 && y == lev_fieldy ? 2 :
1126 x == lev_fieldx && y == lev_fieldy ? 3 :
1127 x == -1 || x == lev_fieldx ? 4 :
1128 y == -1 || y == lev_fieldy ? 5 : 6);
1130 return border[steel_position][steel_type];
1133 void DrawScreenElement(int x, int y, int element)
1135 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1136 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1139 void DrawLevelElement(int x, int y, int element)
1141 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1142 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1145 void DrawScreenField(int x, int y)
1147 int lx = LEVELX(x), ly = LEVELY(y);
1148 int element, content;
1150 if (!IN_LEV_FIELD(lx, ly))
1152 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1155 element = getBorderElement(lx, ly);
1157 DrawScreenElement(x, y, element);
1161 element = Feld[lx][ly];
1162 content = Store[lx][ly];
1164 if (IS_MOVING(lx, ly))
1166 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1167 boolean cut_mode = NO_CUTTING;
1169 if (element == EL_QUICKSAND_EMPTYING ||
1170 element == EL_MAGIC_WALL_EMPTYING ||
1171 element == EL_BD_MAGIC_WALL_EMPTYING ||
1172 element == EL_AMOEBA_DROPPING)
1173 cut_mode = CUT_ABOVE;
1174 else if (element == EL_QUICKSAND_FILLING ||
1175 element == EL_MAGIC_WALL_FILLING ||
1176 element == EL_BD_MAGIC_WALL_FILLING)
1177 cut_mode = CUT_BELOW;
1179 if (cut_mode == CUT_ABOVE)
1180 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1182 DrawScreenElement(x, y, EL_EMPTY);
1185 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1186 else if (cut_mode == NO_CUTTING)
1187 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1189 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1191 if (content == EL_ACID)
1193 int dir = MovDir[lx][ly];
1194 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1195 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1197 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1200 else if (IS_BLOCKED(lx, ly))
1205 boolean cut_mode = NO_CUTTING;
1206 int element_old, content_old;
1208 Blocked2Moving(lx, ly, &oldx, &oldy);
1211 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1212 MovDir[oldx][oldy] == MV_RIGHT);
1214 element_old = Feld[oldx][oldy];
1215 content_old = Store[oldx][oldy];
1217 if (element_old == EL_QUICKSAND_EMPTYING ||
1218 element_old == EL_MAGIC_WALL_EMPTYING ||
1219 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1220 element_old == EL_AMOEBA_DROPPING)
1221 cut_mode = CUT_ABOVE;
1223 DrawScreenElement(x, y, EL_EMPTY);
1226 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1228 else if (cut_mode == NO_CUTTING)
1229 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1232 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1235 else if (IS_DRAWABLE(element))
1236 DrawScreenElement(x, y, element);
1238 DrawScreenElement(x, y, EL_EMPTY);
1241 void DrawLevelField(int x, int y)
1243 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1244 DrawScreenField(SCREENX(x), SCREENY(y));
1245 else if (IS_MOVING(x, y))
1249 Moving2Blocked(x, y, &newx, &newy);
1250 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1251 DrawScreenField(SCREENX(newx), SCREENY(newy));
1253 else if (IS_BLOCKED(x, y))
1257 Blocked2Moving(x, y, &oldx, &oldy);
1258 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1259 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1263 void DrawMiniElement(int x, int y, int element)
1267 graphic = el2edimg(element);
1268 DrawMiniGraphic(x, y, graphic);
1271 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1273 int x = sx + scroll_x, y = sy + scroll_y;
1275 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1276 DrawMiniElement(sx, sy, EL_EMPTY);
1277 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1278 DrawMiniElement(sx, sy, Feld[x][y]);
1280 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1283 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1284 int x, int y, int xsize, int ysize, int font_nr)
1286 int font_width = getFontWidth(font_nr);
1287 int font_height = getFontHeight(font_nr);
1288 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1291 int dst_x = SX + startx + x * font_width;
1292 int dst_y = SY + starty + y * font_height;
1293 int width = graphic_info[graphic].width;
1294 int height = graphic_info[graphic].height;
1295 int inner_width = MAX(width - 2 * font_width, font_width);
1296 int inner_height = MAX(height - 2 * font_height, font_height);
1297 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1298 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1299 boolean draw_masked = graphic_info[graphic].draw_masked;
1301 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1303 if (src_bitmap == NULL || width < font_width || height < font_height)
1305 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1309 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1310 inner_sx + (x - 1) * font_width % inner_width);
1311 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1312 inner_sy + (y - 1) * font_height % inner_height);
1316 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1317 dst_x - src_x, dst_y - src_y);
1318 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1322 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1326 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1328 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1329 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1330 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1331 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1332 boolean no_delay = (tape.warp_forward);
1333 unsigned long anim_delay = 0;
1334 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1335 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1336 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1337 int font_width = getFontWidth(font_nr);
1338 int font_height = getFontHeight(font_nr);
1339 int max_xsize = level.envelope_xsize[envelope_nr];
1340 int max_ysize = level.envelope_ysize[envelope_nr];
1341 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1342 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1343 int xend = max_xsize;
1344 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1345 int xstep = (xstart < xend ? 1 : 0);
1346 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1349 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1351 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1352 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1353 int sx = (SXSIZE - xsize * font_width) / 2;
1354 int sy = (SYSIZE - ysize * font_height) / 2;
1357 SetDrawtoField(DRAW_BUFFERED);
1359 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1361 SetDrawtoField(DRAW_BACKBUFFER);
1363 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1364 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1366 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1367 level.envelope_text[envelope_nr], font_nr, max_xsize,
1368 xsize - 2, ysize - 2, mask_mode);
1370 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1373 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1377 void ShowEnvelope(int envelope_nr)
1379 int element = EL_ENVELOPE_1 + envelope_nr;
1380 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1381 int sound_opening = element_info[element].sound[ACTION_OPENING];
1382 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1383 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1384 boolean no_delay = (tape.warp_forward);
1385 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1386 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1387 int anim_mode = graphic_info[graphic].anim_mode;
1388 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1389 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1391 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1393 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1395 if (anim_mode == ANIM_DEFAULT)
1396 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1398 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1401 Delay(wait_delay_value);
1403 WaitForEventToContinue();
1405 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1407 if (anim_mode != ANIM_NONE)
1408 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1410 if (anim_mode == ANIM_DEFAULT)
1411 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1413 game.envelope_active = FALSE;
1415 SetDrawtoField(DRAW_BUFFERED);
1417 redraw_mask |= REDRAW_FIELD;
1421 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1423 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1424 int mini_startx = src_bitmap->width * 3 / 4;
1425 int mini_starty = src_bitmap->height * 2 / 3;
1426 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1427 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1429 *bitmap = src_bitmap;
1434 void DrawMicroElement(int xpos, int ypos, int element)
1438 int graphic = el2preimg(element);
1440 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1441 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1449 SetDrawBackgroundMask(REDRAW_NONE);
1452 for (x = BX1; x <= BX2; x++)
1453 for (y = BY1; y <= BY2; y++)
1454 DrawScreenField(x, y);
1456 redraw_mask |= REDRAW_FIELD;
1459 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1463 for (x = 0; x < size_x; x++)
1464 for (y = 0; y < size_y; y++)
1465 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1467 redraw_mask |= REDRAW_FIELD;
1470 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1474 DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
1476 if (lev_fieldx < STD_LEV_FIELDX)
1477 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1478 if (lev_fieldy < STD_LEV_FIELDY)
1479 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1481 xpos += MICRO_TILEX;
1482 ypos += MICRO_TILEY;
1484 for (x = -1; x <= STD_LEV_FIELDX; x++)
1486 for (y = -1; y <= STD_LEV_FIELDY; y++)
1488 int lx = from_x + x, ly = from_y + y;
1490 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1491 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1492 level.field[lx][ly]);
1493 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1494 && BorderElement != EL_EMPTY)
1495 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1496 getBorderElement(lx, ly));
1500 redraw_mask |= REDRAW_MICROLEVEL;
1503 #define MICROLABEL_EMPTY 0
1504 #define MICROLABEL_LEVEL_NAME 1
1505 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1506 #define MICROLABEL_LEVEL_AUTHOR 3
1507 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1508 #define MICROLABEL_IMPORTED_FROM 5
1509 #define MICROLABEL_IMPORTED_BY_HEAD 6
1510 #define MICROLABEL_IMPORTED_BY 7
1512 static void DrawMicroLevelLabelExt(int mode)
1514 char label_text[MAX_OUTPUT_LINESIZE + 1];
1515 int max_len_label_text;
1516 int font_nr = FONT_TEXT_2;
1519 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1520 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1521 mode == MICROLABEL_IMPORTED_BY_HEAD)
1522 font_nr = FONT_TEXT_3;
1524 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1526 for (i = 0; i < max_len_label_text; i++)
1527 label_text[i] = ' ';
1528 label_text[max_len_label_text] = '\0';
1530 if (strlen(label_text) > 0)
1532 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1533 int lypos = MICROLABEL2_YPOS;
1535 DrawText(lxpos, lypos, label_text, font_nr);
1539 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1540 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1541 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1542 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1543 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1544 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1545 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1546 max_len_label_text);
1547 label_text[max_len_label_text] = '\0';
1549 if (strlen(label_text) > 0)
1551 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1552 int lypos = MICROLABEL2_YPOS;
1554 DrawText(lxpos, lypos, label_text, font_nr);
1557 redraw_mask |= REDRAW_MICROLEVEL;
1560 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1562 static unsigned long scroll_delay = 0;
1563 static unsigned long label_delay = 0;
1564 static int from_x, from_y, scroll_direction;
1565 static int label_state, label_counter;
1566 int last_game_status = game_status; /* save current game status */
1568 /* force PREVIEW font on preview level */
1569 game_status = GAME_MODE_PSEUDO_PREVIEW;
1573 from_x = from_y = 0;
1574 scroll_direction = MV_RIGHT;
1578 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1579 DrawMicroLevelLabelExt(label_state);
1581 /* initialize delay counters */
1582 DelayReached(&scroll_delay, 0);
1583 DelayReached(&label_delay, 0);
1585 if (leveldir_current->name)
1587 char label_text[MAX_OUTPUT_LINESIZE + 1];
1588 int font_nr = FONT_TEXT_1;
1589 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1592 strncpy(label_text, leveldir_current->name, max_len_label_text);
1593 label_text[max_len_label_text] = '\0';
1595 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1596 lypos = SY + MICROLABEL1_YPOS;
1598 DrawText(lxpos, lypos, label_text, font_nr);
1601 game_status = last_game_status; /* restore current game status */
1606 /* scroll micro level, if needed */
1607 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1608 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1610 switch (scroll_direction)
1616 scroll_direction = MV_UP;
1620 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1623 scroll_direction = MV_DOWN;
1630 scroll_direction = MV_RIGHT;
1634 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1637 scroll_direction = MV_LEFT;
1644 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1647 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1648 /* redraw micro level label, if needed */
1649 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1650 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1651 strcmp(level.author, leveldir_current->name) != 0 &&
1652 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1654 int max_label_counter = 23;
1656 if (leveldir_current->imported_from != NULL &&
1657 strlen(leveldir_current->imported_from) > 0)
1658 max_label_counter += 14;
1659 if (leveldir_current->imported_by != NULL &&
1660 strlen(leveldir_current->imported_by) > 0)
1661 max_label_counter += 14;
1663 label_counter = (label_counter + 1) % max_label_counter;
1664 label_state = (label_counter >= 0 && label_counter <= 7 ?
1665 MICROLABEL_LEVEL_NAME :
1666 label_counter >= 9 && label_counter <= 12 ?
1667 MICROLABEL_LEVEL_AUTHOR_HEAD :
1668 label_counter >= 14 && label_counter <= 21 ?
1669 MICROLABEL_LEVEL_AUTHOR :
1670 label_counter >= 23 && label_counter <= 26 ?
1671 MICROLABEL_IMPORTED_FROM_HEAD :
1672 label_counter >= 28 && label_counter <= 35 ?
1673 MICROLABEL_IMPORTED_FROM :
1674 label_counter >= 37 && label_counter <= 40 ?
1675 MICROLABEL_IMPORTED_BY_HEAD :
1676 label_counter >= 42 && label_counter <= 49 ?
1677 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1679 if (leveldir_current->imported_from == NULL &&
1680 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1681 label_state == MICROLABEL_IMPORTED_FROM))
1682 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1683 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1685 DrawMicroLevelLabelExt(label_state);
1688 game_status = last_game_status; /* restore current game status */
1691 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1692 int graphic, int sync_frame, int mask_mode)
1694 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1696 if (mask_mode == USE_MASKING)
1697 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1699 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1702 inline void DrawGraphicAnimation(int x, int y, int graphic)
1704 int lx = LEVELX(x), ly = LEVELY(y);
1706 if (!IN_SCR_FIELD(x, y))
1709 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1710 graphic, GfxFrame[lx][ly], NO_MASKING);
1711 MarkTileDirty(x, y);
1714 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1716 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1719 void DrawLevelElementAnimation(int x, int y, int element)
1721 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1723 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1726 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1728 int sx = SCREENX(x), sy = SCREENY(y);
1730 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1733 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1736 DrawGraphicAnimation(sx, sy, graphic);
1739 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1740 DrawLevelFieldCrumbledSand(x, y);
1742 if (GFX_CRUMBLED(Feld[x][y]))
1743 DrawLevelFieldCrumbledSand(x, y);
1747 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1749 int sx = SCREENX(x), sy = SCREENY(y);
1752 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1755 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1757 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1760 DrawGraphicAnimation(sx, sy, graphic);
1762 if (GFX_CRUMBLED(element))
1763 DrawLevelFieldCrumbledSand(x, y);
1766 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1768 if (player->use_murphy)
1770 /* this works only because currently only one player can be "murphy" ... */
1771 static int last_horizontal_dir = MV_LEFT;
1772 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1774 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1775 last_horizontal_dir = move_dir;
1777 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1779 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1781 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1787 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1790 static boolean equalGraphics(int graphic1, int graphic2)
1792 struct GraphicInfo *g1 = &graphic_info[graphic1];
1793 struct GraphicInfo *g2 = &graphic_info[graphic2];
1795 return (g1->bitmap == g2->bitmap &&
1796 g1->src_x == g2->src_x &&
1797 g1->src_y == g2->src_y &&
1798 g1->anim_frames == g2->anim_frames &&
1799 g1->anim_delay == g2->anim_delay &&
1800 g1->anim_mode == g2->anim_mode);
1803 void DrawAllPlayers()
1807 for (i = 0; i < MAX_PLAYERS; i++)
1808 if (stored_player[i].active)
1809 DrawPlayer(&stored_player[i]);
1812 void DrawPlayerField(int x, int y)
1814 if (!IS_PLAYER(x, y))
1817 DrawPlayer(PLAYERINFO(x, y));
1820 void DrawPlayer(struct PlayerInfo *player)
1822 int jx = player->jx;
1823 int jy = player->jy;
1824 int move_dir = player->MovDir;
1825 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1826 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1827 int last_jx = (player->is_moving ? jx - dx : jx);
1828 int last_jy = (player->is_moving ? jy - dy : jy);
1829 int next_jx = jx + dx;
1830 int next_jy = jy + dy;
1831 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1832 boolean player_is_opaque = FALSE;
1833 int sx = SCREENX(jx), sy = SCREENY(jy);
1834 int sxx = 0, syy = 0;
1835 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1837 int action = ACTION_DEFAULT;
1838 int last_player_graphic = getPlayerGraphic(player, move_dir);
1839 int last_player_frame = player->Frame;
1843 /* GfxElement[][] is set to the element the player is digging or collecting;
1844 remove also for off-screen player if the player is not moving anymore */
1845 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1846 GfxElement[jx][jy] = EL_UNDEFINED;
1849 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1853 if (!IN_LEV_FIELD(jx, jy))
1855 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1856 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1857 printf("DrawPlayerField(): This should never happen!\n");
1862 if (element == EL_EXPLOSION)
1865 action = (player->is_pushing ? ACTION_PUSHING :
1866 player->is_digging ? ACTION_DIGGING :
1867 player->is_collecting ? ACTION_COLLECTING :
1868 player->is_moving ? ACTION_MOVING :
1869 player->is_snapping ? ACTION_SNAPPING :
1870 player->is_dropping ? ACTION_DROPPING :
1871 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1874 if (player->is_waiting)
1875 move_dir = player->dir_waiting;
1878 InitPlayerGfxAnimation(player, action, move_dir);
1880 /* ----------------------------------------------------------------------- */
1881 /* draw things in the field the player is leaving, if needed */
1882 /* ----------------------------------------------------------------------- */
1884 if (player->is_moving)
1886 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1888 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1890 if (last_element == EL_DYNAMITE_ACTIVE ||
1891 last_element == EL_EM_DYNAMITE_ACTIVE ||
1892 last_element == EL_SP_DISK_RED_ACTIVE)
1893 DrawDynamite(last_jx, last_jy);
1895 DrawLevelFieldThruMask(last_jx, last_jy);
1897 else if (last_element == EL_DYNAMITE_ACTIVE ||
1898 last_element == EL_EM_DYNAMITE_ACTIVE ||
1899 last_element == EL_SP_DISK_RED_ACTIVE)
1900 DrawDynamite(last_jx, last_jy);
1902 DrawLevelField(last_jx, last_jy);
1904 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
1905 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
1908 if (!IN_SCR_FIELD(sx, sy))
1911 if (setup.direct_draw)
1912 SetDrawtoField(DRAW_BUFFERED);
1914 /* ----------------------------------------------------------------------- */
1915 /* draw things behind the player, if needed */
1916 /* ----------------------------------------------------------------------- */
1919 DrawLevelElement(jx, jy, Back[jx][jy]);
1920 else if (IS_ACTIVE_BOMB(element))
1921 DrawLevelElement(jx, jy, EL_EMPTY);
1924 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
1926 int old_element = GfxElement[jx][jy];
1927 int old_graphic = el_act_dir2img(old_element, action, move_dir);
1928 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
1930 if (GFX_CRUMBLED(old_element))
1931 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
1933 DrawGraphic(sx, sy, old_graphic, frame);
1935 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
1936 player_is_opaque = TRUE;
1940 GfxElement[jx][jy] = EL_UNDEFINED;
1942 /* make sure that pushed elements are drawn with correct frame rate */
1943 if (player->is_pushing && player->is_moving)
1944 GfxFrame[jx][jy] = player->StepFrame;
1946 DrawLevelField(jx, jy);
1950 /* ----------------------------------------------------------------------- */
1951 /* draw player himself */
1952 /* ----------------------------------------------------------------------- */
1954 graphic = getPlayerGraphic(player, move_dir);
1956 /* in the case of changed player action or direction, prevent the current
1957 animation frame from being restarted for identical animations */
1958 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
1959 player->Frame = last_player_frame;
1961 frame = getGraphicAnimationFrame(graphic, player->Frame);
1965 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1966 sxx = player->GfxPos;
1968 syy = player->GfxPos;
1971 if (!setup.soft_scrolling && ScreenMovPos)
1974 if (player_is_opaque)
1975 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
1977 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1979 if (SHIELD_ON(player))
1981 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
1982 IMG_SHIELD_NORMAL_ACTIVE);
1983 int frame = getGraphicAnimationFrame(graphic, -1);
1985 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1988 /* ----------------------------------------------------------------------- */
1989 /* draw things the player is pushing, if needed */
1990 /* ----------------------------------------------------------------------- */
1993 printf("::: %d, %d [%d, %d] [%d]\n",
1994 player->is_pushing, player_is_moving, player->GfxAction,
1995 player->is_moving, player_is_moving);
1999 if (player->is_pushing && player->is_moving)
2001 int px = SCREENX(jx), py = SCREENY(jy);
2002 int pxx = (TILEX - ABS(sxx)) * dx;
2003 int pyy = (TILEY - ABS(syy)) * dy;
2008 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2009 element = Feld[next_jx][next_jy];
2011 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2012 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2014 /* draw background element under pushed element (like the Sokoban field) */
2015 if (Back[next_jx][next_jy])
2016 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2018 /* masked drawing is needed for EMC style (double) movement graphics */
2019 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2023 /* ----------------------------------------------------------------------- */
2024 /* draw things in front of player (active dynamite or dynabombs) */
2025 /* ----------------------------------------------------------------------- */
2027 if (IS_ACTIVE_BOMB(element))
2029 graphic = el2img(element);
2030 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2032 if (game.emulation == EMU_SUPAPLEX)
2033 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2035 DrawGraphicThruMask(sx, sy, graphic, frame);
2038 if (player_is_moving && last_element == EL_EXPLOSION)
2040 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2041 GfxElement[last_jx][last_jy] : EL_EMPTY);
2042 int graphic = el_act2img(element, ACTION_EXPLODING);
2043 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2044 int phase = ExplodePhase[last_jx][last_jy] - 1;
2045 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2048 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2051 /* ----------------------------------------------------------------------- */
2052 /* draw elements the player is just walking/passing through/under */
2053 /* ----------------------------------------------------------------------- */
2055 if (player_is_moving)
2057 /* handle the field the player is leaving ... */
2058 if (IS_ACCESSIBLE_INSIDE(last_element))
2059 DrawLevelField(last_jx, last_jy);
2060 else if (IS_ACCESSIBLE_UNDER(last_element))
2061 DrawLevelFieldThruMask(last_jx, last_jy);
2064 /* do not redraw accessible elements if the player is just pushing them */
2065 if (!player_is_moving || !player->is_pushing)
2067 /* ... and the field the player is entering */
2068 if (IS_ACCESSIBLE_INSIDE(element))
2069 DrawLevelField(jx, jy);
2070 else if (IS_ACCESSIBLE_UNDER(element))
2071 DrawLevelFieldThruMask(jx, jy);
2074 if (setup.direct_draw)
2076 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2077 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2078 int x_size = TILEX * (1 + ABS(jx - last_jx));
2079 int y_size = TILEY * (1 + ABS(jy - last_jy));
2081 BlitBitmap(drawto_field, window,
2082 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2083 SetDrawtoField(DRAW_DIRECT);
2086 MarkTileDirty(sx, sy);
2089 /* ------------------------------------------------------------------------- */
2091 void WaitForEventToContinue()
2093 boolean still_wait = TRUE;
2095 /* simulate releasing mouse button over last gadget, if still pressed */
2097 HandleGadgets(-1, -1, 0);
2099 button_status = MB_RELEASED;
2111 case EVENT_BUTTONPRESS:
2112 case EVENT_KEYPRESS:
2116 case EVENT_KEYRELEASE:
2117 ClearPlayerAction();
2121 HandleOtherEvents(&event);
2125 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2132 /* don't eat all CPU time */
2137 #define MAX_REQUEST_LINES 13
2138 #define MAX_REQUEST_LINE_FONT1_LEN 7
2139 #define MAX_REQUEST_LINE_FONT2_LEN 10
2141 boolean Request(char *text, unsigned int req_state)
2143 int mx, my, ty, result = -1;
2144 unsigned int old_door_state;
2145 int last_game_status = game_status; /* save current game status */
2146 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2147 int font_nr = FONT_TEXT_2;
2148 int max_word_len = 0;
2151 for (text_ptr = text; *text_ptr; text_ptr++)
2153 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2155 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2157 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2158 font_nr = FONT_LEVEL_NUMBER;
2164 if (game_status == GAME_MODE_PLAYING &&
2165 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2166 BlitScreenToBitmap_EM(backbuffer);
2168 /* disable deactivated drawing when quick-loading level tape recording */
2169 if (tape.playing && tape.deactivate_display)
2170 TapeDeactivateDisplayOff(TRUE);
2172 SetMouseCursor(CURSOR_DEFAULT);
2174 #if defined(NETWORK_AVALIABLE)
2175 /* pause network game while waiting for request to answer */
2176 if (options.network &&
2177 game_status == GAME_MODE_PLAYING &&
2178 req_state & REQUEST_WAIT_FOR_INPUT)
2179 SendToServer_PausePlaying();
2182 old_door_state = GetDoorState();
2184 /* simulate releasing mouse button over last gadget, if still pressed */
2186 HandleGadgets(-1, -1, 0);
2190 if (old_door_state & DOOR_OPEN_1)
2192 CloseDoor(DOOR_CLOSE_1);
2194 /* save old door content */
2195 BlitBitmap(bitmap_db_door, bitmap_db_door,
2196 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2197 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2200 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2202 /* clear door drawing field */
2203 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2205 /* force DOOR font on preview level */
2206 game_status = GAME_MODE_PSEUDO_DOOR;
2208 /* write text for request */
2209 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2211 char text_line[max_request_line_len + 1];
2217 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2220 if (!tc || tc == ' ')
2231 strncpy(text_line, text, tl);
2234 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2235 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2236 text_line, font_nr);
2238 text += tl + (tc == ' ' ? 1 : 0);
2241 game_status = last_game_status; /* restore current game status */
2243 if (req_state & REQ_ASK)
2245 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2246 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2248 else if (req_state & REQ_CONFIRM)
2250 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2252 else if (req_state & REQ_PLAYER)
2254 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2255 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2256 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2257 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2260 /* copy request gadgets to door backbuffer */
2261 BlitBitmap(drawto, bitmap_db_door,
2262 DX, DY, DXSIZE, DYSIZE,
2263 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2265 OpenDoor(DOOR_OPEN_1);
2267 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2269 SetDrawBackgroundMask(REDRAW_FIELD);
2274 if (game_status != GAME_MODE_MAIN)
2277 button_status = MB_RELEASED;
2279 request_gadget_id = -1;
2281 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2293 case EVENT_BUTTONPRESS:
2294 case EVENT_BUTTONRELEASE:
2295 case EVENT_MOTIONNOTIFY:
2297 if (event.type == EVENT_MOTIONNOTIFY)
2299 if (!PointerInWindow(window))
2300 continue; /* window and pointer are on different screens */
2305 motion_status = TRUE;
2306 mx = ((MotionEvent *) &event)->x;
2307 my = ((MotionEvent *) &event)->y;
2311 motion_status = FALSE;
2312 mx = ((ButtonEvent *) &event)->x;
2313 my = ((ButtonEvent *) &event)->y;
2314 if (event.type == EVENT_BUTTONPRESS)
2315 button_status = ((ButtonEvent *) &event)->button;
2317 button_status = MB_RELEASED;
2320 /* this sets 'request_gadget_id' */
2321 HandleGadgets(mx, my, button_status);
2323 switch(request_gadget_id)
2325 case TOOL_CTRL_ID_YES:
2328 case TOOL_CTRL_ID_NO:
2331 case TOOL_CTRL_ID_CONFIRM:
2332 result = TRUE | FALSE;
2335 case TOOL_CTRL_ID_PLAYER_1:
2338 case TOOL_CTRL_ID_PLAYER_2:
2341 case TOOL_CTRL_ID_PLAYER_3:
2344 case TOOL_CTRL_ID_PLAYER_4:
2355 case EVENT_KEYPRESS:
2356 switch(GetEventKey((KeyEvent *)&event, TRUE))
2369 if (req_state & REQ_PLAYER)
2373 case EVENT_KEYRELEASE:
2374 ClearPlayerAction();
2378 HandleOtherEvents(&event);
2382 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2384 int joy = AnyJoystick();
2386 if (joy & JOY_BUTTON_1)
2388 else if (joy & JOY_BUTTON_2)
2394 /* don't eat all CPU time */
2398 if (game_status != GAME_MODE_MAIN)
2403 if (!(req_state & REQ_STAY_OPEN))
2405 CloseDoor(DOOR_CLOSE_1);
2407 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2408 (req_state & REQ_REOPEN))
2409 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2414 SetDrawBackgroundMask(REDRAW_FIELD);
2416 #if defined(NETWORK_AVALIABLE)
2417 /* continue network game after request */
2418 if (options.network &&
2419 game_status == GAME_MODE_PLAYING &&
2420 req_state & REQUEST_WAIT_FOR_INPUT)
2421 SendToServer_ContinuePlaying();
2424 /* restore deactivated drawing when quick-loading level tape recording */
2425 if (tape.playing && tape.deactivate_display)
2426 TapeDeactivateDisplayOn();
2431 unsigned int OpenDoor(unsigned int door_state)
2433 if (door_state & DOOR_COPY_BACK)
2435 if (door_state & DOOR_OPEN_1)
2436 BlitBitmap(bitmap_db_door, bitmap_db_door,
2437 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2438 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2440 if (door_state & DOOR_OPEN_2)
2441 BlitBitmap(bitmap_db_door, bitmap_db_door,
2442 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2443 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2445 door_state &= ~DOOR_COPY_BACK;
2448 return MoveDoor(door_state);
2451 unsigned int CloseDoor(unsigned int door_state)
2453 unsigned int old_door_state = GetDoorState();
2455 if (!(door_state & DOOR_NO_COPY_BACK))
2457 if (old_door_state & DOOR_OPEN_1)
2458 BlitBitmap(backbuffer, bitmap_db_door,
2459 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2461 if (old_door_state & DOOR_OPEN_2)
2462 BlitBitmap(backbuffer, bitmap_db_door,
2463 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2465 door_state &= ~DOOR_NO_COPY_BACK;
2468 return MoveDoor(door_state);
2471 unsigned int GetDoorState()
2473 return MoveDoor(DOOR_GET_STATE);
2476 unsigned int SetDoorState(unsigned int door_state)
2478 return MoveDoor(door_state | DOOR_SET_STATE);
2481 unsigned int MoveDoor(unsigned int door_state)
2483 static int door1 = DOOR_OPEN_1;
2484 static int door2 = DOOR_CLOSE_2;
2485 unsigned long door_delay = 0;
2486 unsigned long door_delay_value;
2489 if (door_1.width < 0 || door_1.width > DXSIZE)
2490 door_1.width = DXSIZE;
2491 if (door_1.height < 0 || door_1.height > DYSIZE)
2492 door_1.height = DYSIZE;
2493 if (door_2.width < 0 || door_2.width > VXSIZE)
2494 door_2.width = VXSIZE;
2495 if (door_2.height < 0 || door_2.height > VYSIZE)
2496 door_2.height = VYSIZE;
2498 if (door_state == DOOR_GET_STATE)
2499 return(door1 | door2);
2501 if (door_state & DOOR_SET_STATE)
2503 if (door_state & DOOR_ACTION_1)
2504 door1 = door_state & DOOR_ACTION_1;
2505 if (door_state & DOOR_ACTION_2)
2506 door2 = door_state & DOOR_ACTION_2;
2508 return(door1 | door2);
2511 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2512 door_state &= ~DOOR_OPEN_1;
2513 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2514 door_state &= ~DOOR_CLOSE_1;
2515 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2516 door_state &= ~DOOR_OPEN_2;
2517 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2518 door_state &= ~DOOR_CLOSE_2;
2520 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2523 if (setup.quick_doors)
2525 stepsize = 20; /* must be choosen to always draw last frame */
2526 door_delay_value = 0;
2529 if (global.autoplay_leveldir)
2531 door_state |= DOOR_NO_DELAY;
2532 door_state &= ~DOOR_CLOSE_ALL;
2535 if (door_state & DOOR_ACTION)
2537 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2538 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2539 boolean door_1_done = (!handle_door_1);
2540 boolean door_2_done = (!handle_door_2);
2541 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2542 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2543 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2544 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2545 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2546 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2547 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2548 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2549 int door_skip = max_door_size - door_size;
2551 int end = door_size;
2553 int end = (door_state & DOOR_ACTION_1 &&
2554 door_1.anim_mode & ANIM_VERTICAL ? DYSIZE : DXSIZE);
2557 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2559 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2563 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2565 /* opening door sound has priority over simultaneously closing door */
2566 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2567 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2568 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2569 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2572 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2575 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2576 GC gc = bitmap->stored_clip_gc;
2578 if (door_state & DOOR_ACTION_1)
2580 int a = MIN(x * door_1.step_offset, end);
2581 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2582 int i = p + door_skip;
2584 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2586 BlitBitmap(bitmap_db_door, drawto,
2587 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2588 DXSIZE, DYSIZE, DX, DY);
2592 BlitBitmap(bitmap_db_door, drawto,
2593 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2594 DXSIZE, DYSIZE - p / 2, DX, DY);
2596 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2599 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2601 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2602 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2603 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2604 int dst2_x = DX, dst2_y = DY;
2605 int width = i, height = DYSIZE;
2607 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2608 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2611 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2612 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2615 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2617 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2618 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2619 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2620 int dst2_x = DX, dst2_y = DY;
2621 int width = DXSIZE, height = i;
2623 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2624 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2627 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2628 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2631 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2633 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2635 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2636 BlitBitmapMasked(bitmap, drawto,
2637 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2638 DX + DXSIZE - i, DY + j);
2639 BlitBitmapMasked(bitmap, drawto,
2640 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2641 DX + DXSIZE - i, DY + 140 + j);
2642 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2643 DY - (DOOR_GFX_PAGEY1 + j));
2644 BlitBitmapMasked(bitmap, drawto,
2645 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2647 BlitBitmapMasked(bitmap, drawto,
2648 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2651 BlitBitmapMasked(bitmap, drawto,
2652 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2654 BlitBitmapMasked(bitmap, drawto,
2655 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2657 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2658 BlitBitmapMasked(bitmap, drawto,
2659 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2660 DX + DXSIZE - i, DY + 77 + j);
2661 BlitBitmapMasked(bitmap, drawto,
2662 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2663 DX + DXSIZE - i, DY + 203 + j);
2666 redraw_mask |= REDRAW_DOOR_1;
2667 door_1_done = (a == end);
2670 if (door_state & DOOR_ACTION_2)
2672 int a = MIN(x * door_2.step_offset, door_size_2);
2673 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2674 int i = p + door_skip;
2676 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2678 BlitBitmap(bitmap_db_door, drawto,
2679 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2680 VXSIZE, VYSIZE, VX, VY);
2682 else if (x <= VYSIZE)
2684 BlitBitmap(bitmap_db_door, drawto,
2685 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2686 VXSIZE, VYSIZE - p / 2, VX, VY);
2688 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2691 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2693 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2694 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2695 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2696 int dst2_x = VX, dst2_y = VY;
2697 int width = i, height = VYSIZE;
2699 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2700 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2703 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2704 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2707 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2709 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2710 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2711 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2712 int dst2_x = VX, dst2_y = VY;
2713 int width = VXSIZE, height = i;
2715 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2716 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2719 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2720 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2723 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2725 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2727 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2728 BlitBitmapMasked(bitmap, drawto,
2729 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2730 VX + VXSIZE - i, VY + j);
2731 SetClipOrigin(bitmap, gc,
2732 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2733 BlitBitmapMasked(bitmap, drawto,
2734 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2737 BlitBitmapMasked(bitmap, drawto,
2738 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2739 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2740 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2741 BlitBitmapMasked(bitmap, drawto,
2742 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2744 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2747 redraw_mask |= REDRAW_DOOR_2;
2748 door_2_done = (a == VXSIZE);
2753 if (game_status == GAME_MODE_MAIN)
2756 if (!(door_state & DOOR_NO_DELAY))
2757 WaitUntilDelayReached(&door_delay, door_delay_value);
2761 if (door_state & DOOR_ACTION_1)
2762 door1 = door_state & DOOR_ACTION_1;
2763 if (door_state & DOOR_ACTION_2)
2764 door2 = door_state & DOOR_ACTION_2;
2766 return (door1 | door2);
2769 void DrawSpecialEditorDoor()
2771 /* draw bigger toolbox window */
2772 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2773 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2775 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2776 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2779 redraw_mask |= REDRAW_ALL;
2782 void UndrawSpecialEditorDoor()
2784 /* draw normal tape recorder window */
2785 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2786 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2789 redraw_mask |= REDRAW_ALL;
2793 /* ---------- new tool button stuff ---------------------------------------- */
2795 /* graphic position values for tool buttons */
2796 #define TOOL_BUTTON_YES_XPOS 2
2797 #define TOOL_BUTTON_YES_YPOS 250
2798 #define TOOL_BUTTON_YES_GFX_YPOS 0
2799 #define TOOL_BUTTON_YES_XSIZE 46
2800 #define TOOL_BUTTON_YES_YSIZE 28
2801 #define TOOL_BUTTON_NO_XPOS 52
2802 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2803 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2804 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2805 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2806 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2807 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2808 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2809 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2810 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2811 #define TOOL_BUTTON_PLAYER_XSIZE 30
2812 #define TOOL_BUTTON_PLAYER_YSIZE 30
2813 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2814 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2815 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2816 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2817 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2818 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2819 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2820 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2821 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2822 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2823 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2824 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2825 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2826 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2827 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2828 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2829 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2830 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2831 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2832 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2841 } toolbutton_info[NUM_TOOL_BUTTONS] =
2844 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2845 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2846 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2851 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2852 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2853 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2858 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2859 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2860 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2861 TOOL_CTRL_ID_CONFIRM,
2865 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2866 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2867 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2868 TOOL_CTRL_ID_PLAYER_1,
2872 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2873 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2874 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2875 TOOL_CTRL_ID_PLAYER_2,
2879 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2880 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2881 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2882 TOOL_CTRL_ID_PLAYER_3,
2886 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2887 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2888 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2889 TOOL_CTRL_ID_PLAYER_4,
2894 void CreateToolButtons()
2898 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2900 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2901 Bitmap *deco_bitmap = None;
2902 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2903 struct GadgetInfo *gi;
2904 unsigned long event_mask;
2905 int gd_xoffset, gd_yoffset;
2906 int gd_x1, gd_x2, gd_y;
2909 event_mask = GD_EVENT_RELEASED;
2911 gd_xoffset = toolbutton_info[i].xpos;
2912 gd_yoffset = toolbutton_info[i].ypos;
2913 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2914 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2915 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2917 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2919 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2921 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2922 &deco_bitmap, &deco_x, &deco_y);
2923 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2924 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2927 gi = CreateGadget(GDI_CUSTOM_ID, id,
2928 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2929 GDI_X, DX + toolbutton_info[i].x,
2930 GDI_Y, DY + toolbutton_info[i].y,
2931 GDI_WIDTH, toolbutton_info[i].width,
2932 GDI_HEIGHT, toolbutton_info[i].height,
2933 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2934 GDI_STATE, GD_BUTTON_UNPRESSED,
2935 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2936 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2937 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2938 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2939 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2940 GDI_DECORATION_SHIFTING, 1, 1,
2941 GDI_EVENT_MASK, event_mask,
2942 GDI_CALLBACK_ACTION, HandleToolButtons,
2946 Error(ERR_EXIT, "cannot create gadget");
2948 tool_gadget[id] = gi;
2952 void FreeToolButtons()
2956 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2957 FreeGadget(tool_gadget[i]);
2960 static void UnmapToolButtons()
2964 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2965 UnmapGadget(tool_gadget[i]);
2968 static void HandleToolButtons(struct GadgetInfo *gi)
2970 request_gadget_id = gi->custom_id;
2973 static struct Mapping_EM_to_RND_object
2976 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
2977 boolean is_backside; /* backside of moving element */
2983 em_object_mapping_list[] =
2986 Xblank, TRUE, FALSE,
2990 Yacid_splash_eB, FALSE, FALSE,
2991 EL_ACID_SPLASH_RIGHT, -1, -1
2994 Yacid_splash_wB, FALSE, FALSE,
2995 EL_ACID_SPLASH_LEFT, -1, -1
2998 #ifdef EM_ENGINE_BAD_ROLL
3000 Xstone_force_e, FALSE, FALSE,
3001 EL_ROCK, -1, MV_BIT_RIGHT
3004 Xstone_force_w, FALSE, FALSE,
3005 EL_ROCK, -1, MV_BIT_LEFT
3008 Xnut_force_e, FALSE, FALSE,
3009 EL_NUT, -1, MV_BIT_RIGHT
3012 Xnut_force_w, FALSE, FALSE,
3013 EL_NUT, -1, MV_BIT_LEFT
3016 Xspring_force_e, FALSE, FALSE,
3017 EL_SPRING, -1, MV_BIT_RIGHT
3020 Xspring_force_w, FALSE, FALSE,
3021 EL_SPRING, -1, MV_BIT_LEFT
3024 Xemerald_force_e, FALSE, FALSE,
3025 EL_EMERALD, -1, MV_BIT_RIGHT
3028 Xemerald_force_w, FALSE, FALSE,
3029 EL_EMERALD, -1, MV_BIT_LEFT
3032 Xdiamond_force_e, FALSE, FALSE,
3033 EL_DIAMOND, -1, MV_BIT_RIGHT
3036 Xdiamond_force_w, FALSE, FALSE,
3037 EL_DIAMOND, -1, MV_BIT_LEFT
3040 Xbomb_force_e, FALSE, FALSE,
3041 EL_BOMB, -1, MV_BIT_RIGHT
3044 Xbomb_force_w, FALSE, FALSE,
3045 EL_BOMB, -1, MV_BIT_LEFT
3047 #endif /* EM_ENGINE_BAD_ROLL */
3050 Xstone, TRUE, FALSE,
3054 Xstone_pause, FALSE, FALSE,
3058 Xstone_fall, FALSE, FALSE,
3062 Ystone_s, FALSE, FALSE,
3063 EL_ROCK, ACTION_FALLING, -1
3066 Ystone_sB, FALSE, TRUE,
3067 EL_ROCK, ACTION_FALLING, -1
3070 Ystone_e, FALSE, FALSE,
3071 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3074 Ystone_eB, FALSE, TRUE,
3075 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3078 Ystone_w, FALSE, FALSE,
3079 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3082 Ystone_wB, FALSE, TRUE,
3083 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3090 Xnut_pause, FALSE, FALSE,
3094 Xnut_fall, FALSE, FALSE,
3098 Ynut_s, FALSE, FALSE,
3099 EL_NUT, ACTION_FALLING, -1
3102 Ynut_sB, FALSE, TRUE,
3103 EL_NUT, ACTION_FALLING, -1
3106 Ynut_e, FALSE, FALSE,
3107 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3110 Ynut_eB, FALSE, TRUE,
3111 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3114 Ynut_w, FALSE, FALSE,
3115 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3118 Ynut_wB, FALSE, TRUE,
3119 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3122 Xbug_n, TRUE, FALSE,
3126 Xbug_e, TRUE, FALSE,
3127 EL_BUG_RIGHT, -1, -1
3130 Xbug_s, TRUE, FALSE,
3134 Xbug_w, TRUE, FALSE,
3138 Xbug_gon, FALSE, FALSE,
3142 Xbug_goe, FALSE, FALSE,
3143 EL_BUG_RIGHT, -1, -1
3146 Xbug_gos, FALSE, FALSE,
3150 Xbug_gow, FALSE, FALSE,
3154 Ybug_n, FALSE, FALSE,
3155 EL_BUG, ACTION_MOVING, MV_BIT_UP
3158 Ybug_nB, FALSE, TRUE,
3159 EL_BUG, ACTION_MOVING, MV_BIT_UP
3162 Ybug_e, FALSE, FALSE,
3163 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3166 Ybug_eB, FALSE, TRUE,
3167 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3170 Ybug_s, FALSE, FALSE,
3171 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3174 Ybug_sB, FALSE, TRUE,
3175 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3178 Ybug_w, FALSE, FALSE,
3179 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3182 Ybug_wB, FALSE, TRUE,
3183 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3186 Ybug_w_n, FALSE, FALSE,
3187 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3190 Ybug_n_e, FALSE, FALSE,
3191 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3194 Ybug_e_s, FALSE, FALSE,
3195 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3198 Ybug_s_w, FALSE, FALSE,
3199 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3202 Ybug_e_n, FALSE, FALSE,
3203 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3206 Ybug_s_e, FALSE, FALSE,
3207 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3210 Ybug_w_s, FALSE, FALSE,
3211 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3214 Ybug_n_w, FALSE, FALSE,
3215 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3218 Ybug_stone, FALSE, FALSE,
3219 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3222 Ybug_spring, FALSE, FALSE,
3223 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3226 Xtank_n, TRUE, FALSE,
3227 EL_SPACESHIP_UP, -1, -1
3230 Xtank_e, TRUE, FALSE,
3231 EL_SPACESHIP_RIGHT, -1, -1
3234 Xtank_s, TRUE, FALSE,
3235 EL_SPACESHIP_DOWN, -1, -1
3238 Xtank_w, TRUE, FALSE,
3239 EL_SPACESHIP_LEFT, -1, -1
3242 Xtank_gon, FALSE, FALSE,
3243 EL_SPACESHIP_UP, -1, -1
3246 Xtank_goe, FALSE, FALSE,
3247 EL_SPACESHIP_RIGHT, -1, -1
3250 Xtank_gos, FALSE, FALSE,
3251 EL_SPACESHIP_DOWN, -1, -1
3254 Xtank_gow, FALSE, FALSE,
3255 EL_SPACESHIP_LEFT, -1, -1
3258 Ytank_n, FALSE, FALSE,
3259 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3262 Ytank_nB, FALSE, TRUE,
3263 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3266 Ytank_e, FALSE, FALSE,
3267 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3270 Ytank_eB, FALSE, TRUE,
3271 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3274 Ytank_s, FALSE, FALSE,
3275 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3278 Ytank_sB, FALSE, TRUE,
3279 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3282 Ytank_w, FALSE, FALSE,
3283 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3286 Ytank_wB, FALSE, TRUE,
3287 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3290 Ytank_w_n, FALSE, FALSE,
3291 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3294 Ytank_n_e, FALSE, FALSE,
3295 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3298 Ytank_e_s, FALSE, FALSE,
3299 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3302 Ytank_s_w, FALSE, FALSE,
3303 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3306 Ytank_e_n, FALSE, FALSE,
3307 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3310 Ytank_s_e, FALSE, FALSE,
3311 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3314 Ytank_w_s, FALSE, FALSE,
3315 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3318 Ytank_n_w, FALSE, FALSE,
3319 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3322 Ytank_stone, FALSE, FALSE,
3323 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3326 Ytank_spring, FALSE, FALSE,
3327 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3330 Xandroid, TRUE, FALSE,
3331 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3334 Xandroid_1_n, FALSE, FALSE,
3335 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3338 Xandroid_2_n, FALSE, FALSE,
3339 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3342 Xandroid_1_e, FALSE, FALSE,
3343 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3346 Xandroid_2_e, FALSE, FALSE,
3347 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3350 Xandroid_1_w, FALSE, FALSE,
3351 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3354 Xandroid_2_w, FALSE, FALSE,
3355 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3358 Xandroid_1_s, FALSE, FALSE,
3359 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3362 Xandroid_2_s, FALSE, FALSE,
3363 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3366 Yandroid_n, FALSE, FALSE,
3367 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3370 Yandroid_nB, FALSE, TRUE,
3371 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3374 Yandroid_ne, FALSE, FALSE,
3375 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3378 Yandroid_neB, FALSE, TRUE,
3379 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3382 Yandroid_e, FALSE, FALSE,
3383 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3386 Yandroid_eB, FALSE, TRUE,
3387 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3390 Yandroid_se, FALSE, FALSE,
3391 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3394 Yandroid_seB, FALSE, TRUE,
3395 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3398 Yandroid_s, FALSE, FALSE,
3399 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3402 Yandroid_sB, FALSE, TRUE,
3403 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3406 Yandroid_sw, FALSE, FALSE,
3407 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3410 Yandroid_swB, FALSE, TRUE,
3411 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3414 Yandroid_w, FALSE, FALSE,
3415 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3418 Yandroid_wB, FALSE, TRUE,
3419 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3422 Yandroid_nw, FALSE, FALSE,
3423 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3426 Yandroid_nwB, FALSE, TRUE,
3427 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3430 Xspring, TRUE, FALSE,
3434 Xspring_pause, FALSE, FALSE,
3438 Xspring_e, FALSE, FALSE,
3442 Xspring_w, FALSE, FALSE,
3446 Xspring_fall, FALSE, FALSE,
3450 Yspring_s, FALSE, FALSE,
3451 EL_SPRING, ACTION_FALLING, -1
3454 Yspring_sB, FALSE, TRUE,
3455 EL_SPRING, ACTION_FALLING, -1
3458 Yspring_e, FALSE, FALSE,
3459 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3462 Yspring_eB, FALSE, TRUE,
3463 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3466 Yspring_w, FALSE, FALSE,
3467 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3470 Yspring_wB, FALSE, TRUE,
3471 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3474 Yspring_kill_e, FALSE, FALSE,
3475 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3478 Yspring_kill_eB, FALSE, TRUE,
3479 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3482 Yspring_kill_w, FALSE, FALSE,
3483 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3486 Yspring_kill_wB, FALSE, TRUE,
3487 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3490 Xeater_n, TRUE, FALSE,
3491 EL_YAMYAM_UP, -1, -1
3494 Xeater_e, TRUE, FALSE,
3495 EL_YAMYAM_RIGHT, -1, -1
3498 Xeater_w, TRUE, FALSE,
3499 EL_YAMYAM_LEFT, -1, -1
3502 Xeater_s, TRUE, FALSE,
3503 EL_YAMYAM_DOWN, -1, -1
3506 Yeater_n, FALSE, FALSE,
3507 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3510 Yeater_nB, FALSE, TRUE,
3511 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3514 Yeater_e, FALSE, FALSE,
3515 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3518 Yeater_eB, FALSE, TRUE,
3519 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3522 Yeater_s, FALSE, FALSE,
3523 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3526 Yeater_sB, FALSE, TRUE,
3527 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3530 Yeater_w, FALSE, FALSE,
3531 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3534 Yeater_wB, FALSE, TRUE,
3535 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3538 Yeater_stone, FALSE, FALSE,
3539 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3542 Yeater_spring, FALSE, FALSE,
3543 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3546 Xalien, TRUE, FALSE,
3550 Xalien_pause, FALSE, FALSE,
3554 Yalien_n, FALSE, FALSE,
3555 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3558 Yalien_nB, FALSE, TRUE,
3559 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3562 Yalien_e, FALSE, FALSE,
3563 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3566 Yalien_eB, FALSE, TRUE,
3567 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3570 Yalien_s, FALSE, FALSE,
3571 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3574 Yalien_sB, FALSE, TRUE,
3575 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3578 Yalien_w, FALSE, FALSE,
3579 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3582 Yalien_wB, FALSE, TRUE,
3583 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3586 Yalien_stone, FALSE, FALSE,
3587 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3590 Yalien_spring, FALSE, FALSE,
3591 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3594 Xemerald, TRUE, FALSE,
3598 Xemerald_pause, FALSE, FALSE,
3602 Xemerald_fall, FALSE, FALSE,
3606 Xemerald_shine, FALSE, FALSE,
3607 EL_EMERALD, ACTION_TWINKLING, -1
3610 Yemerald_s, FALSE, FALSE,
3611 EL_EMERALD, ACTION_FALLING, -1
3614 Yemerald_sB, FALSE, TRUE,
3615 EL_EMERALD, ACTION_FALLING, -1
3618 Yemerald_e, FALSE, FALSE,
3619 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3622 Yemerald_eB, FALSE, TRUE,
3623 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3626 Yemerald_w, FALSE, FALSE,
3627 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3630 Yemerald_wB, FALSE, TRUE,
3631 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3634 Yemerald_eat, FALSE, FALSE,
3635 EL_EMERALD, ACTION_COLLECTING, -1
3638 Yemerald_stone, FALSE, FALSE,
3639 EL_NUT, ACTION_BREAKING, -1
3642 Xdiamond, TRUE, FALSE,
3646 Xdiamond_pause, FALSE, FALSE,
3650 Xdiamond_fall, FALSE, FALSE,
3654 Xdiamond_shine, FALSE, FALSE,
3655 EL_DIAMOND, ACTION_TWINKLING, -1
3658 Ydiamond_s, FALSE, FALSE,
3659 EL_DIAMOND, ACTION_FALLING, -1
3662 Ydiamond_sB, FALSE, TRUE,
3663 EL_DIAMOND, ACTION_FALLING, -1
3666 Ydiamond_e, FALSE, FALSE,
3667 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3670 Ydiamond_eB, FALSE, TRUE,
3671 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3674 Ydiamond_w, FALSE, FALSE,
3675 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3678 Ydiamond_wB, FALSE, TRUE,
3679 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3682 Ydiamond_eat, FALSE, FALSE,
3683 EL_DIAMOND, ACTION_COLLECTING, -1
3686 Ydiamond_stone, FALSE, FALSE,
3687 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3690 Xdrip_fall, TRUE, FALSE,
3691 EL_AMOEBA_DROP, -1, -1
3694 Xdrip_stretch, FALSE, FALSE,
3695 EL_AMOEBA_DROP, ACTION_FALLING, -1
3698 Xdrip_stretchB, FALSE, TRUE,
3699 EL_AMOEBA_DROP, ACTION_FALLING, -1
3702 Xdrip_eat, FALSE, FALSE,
3703 EL_AMOEBA_DROP, ACTION_GROWING, -1
3706 Ydrip_s1, FALSE, FALSE,
3707 EL_AMOEBA_DROP, ACTION_FALLING, -1
3710 Ydrip_s1B, FALSE, TRUE,
3711 EL_AMOEBA_DROP, ACTION_FALLING, -1
3714 Ydrip_s2, FALSE, FALSE,
3715 EL_AMOEBA_DROP, ACTION_FALLING, -1
3718 Ydrip_s2B, FALSE, TRUE,
3719 EL_AMOEBA_DROP, ACTION_FALLING, -1
3726 Xbomb_pause, FALSE, FALSE,
3730 Xbomb_fall, FALSE, FALSE,
3734 Ybomb_s, FALSE, FALSE,
3735 EL_BOMB, ACTION_FALLING, -1
3738 Ybomb_sB, FALSE, TRUE,
3739 EL_BOMB, ACTION_FALLING, -1
3742 Ybomb_e, FALSE, FALSE,
3743 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3746 Ybomb_eB, FALSE, TRUE,
3747 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3750 Ybomb_w, FALSE, FALSE,
3751 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3754 Ybomb_wB, FALSE, TRUE,
3755 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3758 Ybomb_eat, FALSE, FALSE,
3759 EL_BOMB, ACTION_ACTIVATING, -1
3762 Xballoon, TRUE, FALSE,
3766 Yballoon_n, FALSE, FALSE,
3767 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3770 Yballoon_nB, FALSE, TRUE,
3771 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3774 Yballoon_e, FALSE, FALSE,
3775 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3778 Yballoon_eB, FALSE, TRUE,
3779 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3782 Yballoon_s, FALSE, FALSE,
3783 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3786 Yballoon_sB, FALSE, TRUE,
3787 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3790 Yballoon_w, FALSE, FALSE,
3791 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3794 Yballoon_wB, FALSE, TRUE,
3795 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3798 Xgrass, TRUE, FALSE,
3799 EL_EMC_GRASS, -1, -1
3802 Ygrass_nB, FALSE, FALSE,
3803 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3806 Ygrass_eB, FALSE, FALSE,
3807 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3810 Ygrass_sB, FALSE, FALSE,
3811 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3814 Ygrass_wB, FALSE, FALSE,
3815 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3822 Ydirt_nB, FALSE, FALSE,
3823 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3826 Ydirt_eB, FALSE, FALSE,
3827 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3830 Ydirt_sB, FALSE, FALSE,
3831 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3834 Ydirt_wB, FALSE, FALSE,
3835 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3838 Xacid_ne, TRUE, FALSE,
3839 EL_ACID_POOL_TOPRIGHT, -1, -1
3842 Xacid_se, TRUE, FALSE,
3843 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3846 Xacid_s, TRUE, FALSE,
3847 EL_ACID_POOL_BOTTOM, -1, -1
3850 Xacid_sw, TRUE, FALSE,
3851 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3854 Xacid_nw, TRUE, FALSE,
3855 EL_ACID_POOL_TOPLEFT, -1, -1
3858 Xacid_1, TRUE, FALSE,
3862 Xacid_2, FALSE, FALSE,
3866 Xacid_3, FALSE, FALSE,
3870 Xacid_4, FALSE, FALSE,
3874 Xacid_5, FALSE, FALSE,
3878 Xacid_6, FALSE, FALSE,
3882 Xacid_7, FALSE, FALSE,
3886 Xacid_8, FALSE, FALSE,
3890 Xball_1, TRUE, FALSE,
3891 EL_EMC_MAGIC_BALL, -1, -1
3894 Xball_1B, FALSE, FALSE,
3895 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3898 Xball_2, FALSE, FALSE,
3899 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3902 Xball_2B, FALSE, FALSE,
3903 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3906 Yball_eat, FALSE, FALSE,
3907 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
3910 Ykey_1_eat, FALSE, FALSE,
3911 EL_EM_KEY_1, ACTION_COLLECTING, -1
3914 Ykey_2_eat, FALSE, FALSE,
3915 EL_EM_KEY_2, ACTION_COLLECTING, -1
3918 Ykey_3_eat, FALSE, FALSE,
3919 EL_EM_KEY_3, ACTION_COLLECTING, -1
3922 Ykey_4_eat, FALSE, FALSE,
3923 EL_EM_KEY_4, ACTION_COLLECTING, -1
3926 Ykey_5_eat, FALSE, FALSE,
3927 EL_EMC_KEY_5, ACTION_COLLECTING, -1
3930 Ykey_6_eat, FALSE, FALSE,
3931 EL_EMC_KEY_6, ACTION_COLLECTING, -1
3934 Ykey_7_eat, FALSE, FALSE,
3935 EL_EMC_KEY_7, ACTION_COLLECTING, -1
3938 Ykey_8_eat, FALSE, FALSE,
3939 EL_EMC_KEY_8, ACTION_COLLECTING, -1
3942 Ylenses_eat, FALSE, FALSE,
3943 EL_EMC_LENSES, ACTION_COLLECTING, -1
3946 Ymagnify_eat, FALSE, FALSE,
3947 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
3950 Ygrass_eat, FALSE, FALSE,
3951 EL_EMC_GRASS, ACTION_SNAPPING, -1
3954 Ydirt_eat, FALSE, FALSE,
3955 EL_SAND, ACTION_SNAPPING, -1
3958 Xgrow_ns, TRUE, FALSE,
3959 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
3962 Ygrow_ns_eat, FALSE, FALSE,
3963 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
3966 Xgrow_ew, TRUE, FALSE,
3967 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
3970 Ygrow_ew_eat, FALSE, FALSE,
3971 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
3974 Xwonderwall, TRUE, FALSE,
3975 EL_MAGIC_WALL, -1, -1
3978 XwonderwallB, FALSE, FALSE,
3979 EL_MAGIC_WALL, ACTION_ACTIVE, -1
3982 Xamoeba_1, TRUE, FALSE,
3983 EL_AMOEBA_DRY, ACTION_OTHER, -1
3986 Xamoeba_2, FALSE, FALSE,
3987 EL_AMOEBA_DRY, ACTION_OTHER, -1
3990 Xamoeba_3, FALSE, FALSE,
3991 EL_AMOEBA_DRY, ACTION_OTHER, -1
3994 Xamoeba_4, FALSE, FALSE,
3995 EL_AMOEBA_DRY, ACTION_OTHER, -1
3998 Xamoeba_5, TRUE, FALSE,
3999 EL_AMOEBA_WET, ACTION_OTHER, -1
4002 Xamoeba_6, FALSE, FALSE,
4003 EL_AMOEBA_WET, ACTION_OTHER, -1
4006 Xamoeba_7, FALSE, FALSE,
4007 EL_AMOEBA_WET, ACTION_OTHER, -1
4010 Xamoeba_8, FALSE, FALSE,
4011 EL_AMOEBA_WET, ACTION_OTHER, -1
4014 Xdoor_1, TRUE, FALSE,
4015 EL_EM_GATE_1, -1, -1
4018 Xdoor_2, TRUE, FALSE,
4019 EL_EM_GATE_2, -1, -1
4022 Xdoor_3, TRUE, FALSE,
4023 EL_EM_GATE_3, -1, -1
4026 Xdoor_4, TRUE, FALSE,
4027 EL_EM_GATE_4, -1, -1
4030 Xdoor_5, TRUE, FALSE,
4031 EL_EMC_GATE_5, -1, -1
4034 Xdoor_6, TRUE, FALSE,
4035 EL_EMC_GATE_6, -1, -1
4038 Xdoor_7, TRUE, FALSE,
4039 EL_EMC_GATE_7, -1, -1
4042 Xdoor_8, TRUE, FALSE,
4043 EL_EMC_GATE_8, -1, -1
4046 Xkey_1, TRUE, FALSE,
4050 Xkey_2, TRUE, FALSE,
4054 Xkey_3, TRUE, FALSE,
4058 Xkey_4, TRUE, FALSE,
4062 Xkey_5, TRUE, FALSE,
4063 EL_EMC_KEY_5, -1, -1
4066 Xkey_6, TRUE, FALSE,
4067 EL_EMC_KEY_6, -1, -1
4070 Xkey_7, TRUE, FALSE,
4071 EL_EMC_KEY_7, -1, -1
4074 Xkey_8, TRUE, FALSE,
4075 EL_EMC_KEY_8, -1, -1
4078 Xwind_n, TRUE, FALSE,
4079 EL_BALLOON_SWITCH_UP, -1, -1
4082 Xwind_e, TRUE, FALSE,
4083 EL_BALLOON_SWITCH_RIGHT, -1, -1
4086 Xwind_s, TRUE, FALSE,
4087 EL_BALLOON_SWITCH_DOWN, -1, -1
4090 Xwind_w, TRUE, FALSE,
4091 EL_BALLOON_SWITCH_LEFT, -1, -1
4094 Xwind_nesw, TRUE, FALSE,
4095 EL_BALLOON_SWITCH_ANY, -1, -1
4098 Xwind_stop, TRUE, FALSE,
4099 EL_BALLOON_SWITCH_NONE, -1, -1
4103 EL_EXIT_CLOSED, -1, -1
4106 Xexit_1, TRUE, FALSE,
4107 EL_EXIT_OPEN, -1, -1
4110 Xexit_2, FALSE, FALSE,
4111 EL_EXIT_OPEN, -1, -1
4114 Xexit_3, FALSE, FALSE,
4115 EL_EXIT_OPEN, -1, -1
4118 Xdynamite, TRUE, FALSE,
4119 EL_EM_DYNAMITE, -1, -1
4122 Ydynamite_eat, FALSE, FALSE,
4123 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4126 Xdynamite_1, TRUE, FALSE,
4127 EL_EM_DYNAMITE_ACTIVE, -1, -1
4130 Xdynamite_2, FALSE, FALSE,
4131 EL_EM_DYNAMITE_ACTIVE, -1, -1
4134 Xdynamite_3, FALSE, FALSE,
4135 EL_EM_DYNAMITE_ACTIVE, -1, -1
4138 Xdynamite_4, FALSE, FALSE,
4139 EL_EM_DYNAMITE_ACTIVE, -1, -1
4142 Xbumper, TRUE, FALSE,
4143 EL_EMC_SPRING_BUMPER, -1, -1
4146 XbumperB, FALSE, FALSE,
4147 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4150 Xwheel, TRUE, FALSE,
4151 EL_ROBOT_WHEEL, -1, -1
4154 XwheelB, FALSE, FALSE,
4155 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4158 Xswitch, TRUE, FALSE,
4159 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4162 XswitchB, FALSE, FALSE,
4163 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4167 EL_QUICKSAND_EMPTY, -1, -1
4170 Xsand_stone, TRUE, FALSE,
4171 EL_QUICKSAND_FULL, -1, -1
4174 Xsand_stonein_1, FALSE, FALSE,
4175 EL_ROCK, ACTION_FILLING, -1
4178 Xsand_stonein_2, FALSE, FALSE,
4179 EL_ROCK, ACTION_FILLING, -1
4182 Xsand_stonein_3, FALSE, FALSE,
4183 EL_ROCK, ACTION_FILLING, -1
4186 Xsand_stonein_4, FALSE, FALSE,
4187 EL_ROCK, ACTION_FILLING, -1
4190 Xsand_stonesand_1, FALSE, FALSE,
4191 EL_QUICKSAND_FULL, -1, -1
4194 Xsand_stonesand_2, FALSE, FALSE,
4195 EL_QUICKSAND_FULL, -1, -1
4198 Xsand_stonesand_3, FALSE, FALSE,
4199 EL_QUICKSAND_FULL, -1, -1
4202 Xsand_stonesand_4, FALSE, FALSE,
4203 EL_QUICKSAND_FULL, -1, -1
4206 Xsand_stoneout_1, FALSE, FALSE,
4207 EL_ROCK, ACTION_EMPTYING, -1
4210 Xsand_stoneout_2, FALSE, FALSE,
4211 EL_ROCK, ACTION_EMPTYING, -1
4214 Xsand_sandstone_1, FALSE, FALSE,
4215 EL_QUICKSAND_FULL, -1, -1
4218 Xsand_sandstone_2, FALSE, FALSE,
4219 EL_QUICKSAND_FULL, -1, -1
4222 Xsand_sandstone_3, FALSE, FALSE,
4223 EL_QUICKSAND_FULL, -1, -1
4226 Xsand_sandstone_4, FALSE, FALSE,
4227 EL_QUICKSAND_FULL, -1, -1
4230 Xplant, TRUE, FALSE,
4231 EL_EMC_PLANT, -1, -1
4234 Yplant, FALSE, FALSE,
4235 EL_EMC_PLANT, -1, -1
4238 Xlenses, TRUE, FALSE,
4239 EL_EMC_LENSES, -1, -1
4242 Xmagnify, TRUE, FALSE,
4243 EL_EMC_MAGNIFIER, -1, -1
4246 Xdripper, TRUE, FALSE,
4247 EL_EMC_DRIPPER, -1, -1
4250 XdripperB, FALSE, FALSE,
4251 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4254 Xfake_blank, TRUE, FALSE,
4255 EL_INVISIBLE_WALL, -1, -1
4258 Xfake_blankB, FALSE, FALSE,
4259 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4262 Xfake_grass, TRUE, FALSE,
4263 EL_EMC_FAKE_GRASS, -1, -1
4266 Xfake_grassB, FALSE, FALSE,
4267 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4270 Xfake_door_1, TRUE, FALSE,
4271 EL_EM_GATE_1_GRAY, -1, -1
4274 Xfake_door_2, TRUE, FALSE,
4275 EL_EM_GATE_2_GRAY, -1, -1
4278 Xfake_door_3, TRUE, FALSE,
4279 EL_EM_GATE_3_GRAY, -1, -1
4282 Xfake_door_4, TRUE, FALSE,
4283 EL_EM_GATE_4_GRAY, -1, -1
4286 Xfake_door_5, TRUE, FALSE,
4287 EL_EMC_GATE_5_GRAY, -1, -1
4290 Xfake_door_6, TRUE, FALSE,
4291 EL_EMC_GATE_6_GRAY, -1, -1
4294 Xfake_door_7, TRUE, FALSE,
4295 EL_EMC_GATE_7_GRAY, -1, -1
4298 Xfake_door_8, TRUE, FALSE,
4299 EL_EMC_GATE_8_GRAY, -1, -1
4302 Xfake_acid_1, TRUE, FALSE,
4303 EL_EMC_FAKE_ACID, -1, -1
4306 Xfake_acid_2, FALSE, FALSE,
4307 EL_EMC_FAKE_ACID, -1, -1
4310 Xfake_acid_3, FALSE, FALSE,
4311 EL_EMC_FAKE_ACID, -1, -1
4314 Xfake_acid_4, FALSE, FALSE,
4315 EL_EMC_FAKE_ACID, -1, -1
4318 Xfake_acid_5, FALSE, FALSE,
4319 EL_EMC_FAKE_ACID, -1, -1
4322 Xfake_acid_6, FALSE, FALSE,
4323 EL_EMC_FAKE_ACID, -1, -1
4326 Xfake_acid_7, FALSE, FALSE,
4327 EL_EMC_FAKE_ACID, -1, -1
4330 Xfake_acid_8, FALSE, FALSE,
4331 EL_EMC_FAKE_ACID, -1, -1
4334 Xsteel_1, TRUE, FALSE,
4335 EL_STEELWALL, -1, -1
4338 Xsteel_2, TRUE, FALSE,
4339 EL_EMC_STEELWALL_2, -1, -1
4342 Xsteel_3, TRUE, FALSE,
4343 EL_EMC_STEELWALL_3, -1, -1
4346 Xsteel_4, TRUE, FALSE,
4347 EL_EMC_STEELWALL_4, -1, -1
4350 Xwall_1, TRUE, FALSE,
4354 Xwall_2, TRUE, FALSE,
4355 EL_EMC_WALL_14, -1, -1
4358 Xwall_3, TRUE, FALSE,
4359 EL_EMC_WALL_15, -1, -1
4362 Xwall_4, TRUE, FALSE,
4363 EL_EMC_WALL_16, -1, -1
4366 Xround_wall_1, TRUE, FALSE,
4367 EL_WALL_SLIPPERY, -1, -1
4370 Xround_wall_2, TRUE, FALSE,
4371 EL_EMC_WALL_SLIPPERY_2, -1, -1
4374 Xround_wall_3, TRUE, FALSE,
4375 EL_EMC_WALL_SLIPPERY_3, -1, -1
4378 Xround_wall_4, TRUE, FALSE,
4379 EL_EMC_WALL_SLIPPERY_4, -1, -1
4382 Xdecor_1, TRUE, FALSE,
4383 EL_EMC_WALL_8, -1, -1
4386 Xdecor_2, TRUE, FALSE,
4387 EL_EMC_WALL_6, -1, -1
4390 Xdecor_3, TRUE, FALSE,
4391 EL_EMC_WALL_4, -1, -1
4394 Xdecor_4, TRUE, FALSE,
4395 EL_EMC_WALL_7, -1, -1
4398 Xdecor_5, TRUE, FALSE,
4399 EL_EMC_WALL_5, -1, -1
4402 Xdecor_6, TRUE, FALSE,
4403 EL_EMC_WALL_9, -1, -1
4406 Xdecor_7, TRUE, FALSE,
4407 EL_EMC_WALL_10, -1, -1
4410 Xdecor_8, TRUE, FALSE,
4411 EL_EMC_WALL_1, -1, -1
4414 Xdecor_9, TRUE, FALSE,
4415 EL_EMC_WALL_2, -1, -1
4418 Xdecor_10, TRUE, FALSE,
4419 EL_EMC_WALL_3, -1, -1
4422 Xdecor_11, TRUE, FALSE,
4423 EL_EMC_WALL_11, -1, -1
4426 Xdecor_12, TRUE, FALSE,
4427 EL_EMC_WALL_12, -1, -1
4430 Xalpha_0, TRUE, FALSE,
4431 EL_CHAR('0'), -1, -1
4434 Xalpha_1, TRUE, FALSE,
4435 EL_CHAR('1'), -1, -1
4438 Xalpha_2, TRUE, FALSE,
4439 EL_CHAR('2'), -1, -1
4442 Xalpha_3, TRUE, FALSE,
4443 EL_CHAR('3'), -1, -1
4446 Xalpha_4, TRUE, FALSE,
4447 EL_CHAR('4'), -1, -1
4450 Xalpha_5, TRUE, FALSE,
4451 EL_CHAR('5'), -1, -1
4454 Xalpha_6, TRUE, FALSE,
4455 EL_CHAR('6'), -1, -1
4458 Xalpha_7, TRUE, FALSE,
4459 EL_CHAR('7'), -1, -1
4462 Xalpha_8, TRUE, FALSE,
4463 EL_CHAR('8'), -1, -1
4466 Xalpha_9, TRUE, FALSE,
4467 EL_CHAR('9'), -1, -1
4470 Xalpha_excla, TRUE, FALSE,
4471 EL_CHAR('!'), -1, -1
4474 Xalpha_quote, TRUE, FALSE,
4475 EL_CHAR('"'), -1, -1
4478 Xalpha_comma, TRUE, FALSE,
4479 EL_CHAR(','), -1, -1
4482 Xalpha_minus, TRUE, FALSE,
4483 EL_CHAR('-'), -1, -1
4486 Xalpha_perio, TRUE, FALSE,
4487 EL_CHAR('.'), -1, -1
4490 Xalpha_colon, TRUE, FALSE,
4491 EL_CHAR(':'), -1, -1
4494 Xalpha_quest, TRUE, FALSE,
4495 EL_CHAR('?'), -1, -1
4498 Xalpha_a, TRUE, FALSE,
4499 EL_CHAR('A'), -1, -1
4502 Xalpha_b, TRUE, FALSE,
4503 EL_CHAR('B'), -1, -1
4506 Xalpha_c, TRUE, FALSE,
4507 EL_CHAR('C'), -1, -1
4510 Xalpha_d, TRUE, FALSE,
4511 EL_CHAR('D'), -1, -1
4514 Xalpha_e, TRUE, FALSE,
4515 EL_CHAR('E'), -1, -1
4518 Xalpha_f, TRUE, FALSE,
4519 EL_CHAR('F'), -1, -1
4522 Xalpha_g, TRUE, FALSE,
4523 EL_CHAR('G'), -1, -1
4526 Xalpha_h, TRUE, FALSE,
4527 EL_CHAR('H'), -1, -1
4530 Xalpha_i, TRUE, FALSE,
4531 EL_CHAR('I'), -1, -1
4534 Xalpha_j, TRUE, FALSE,
4535 EL_CHAR('J'), -1, -1
4538 Xalpha_k, TRUE, FALSE,
4539 EL_CHAR('K'), -1, -1
4542 Xalpha_l, TRUE, FALSE,
4543 EL_CHAR('L'), -1, -1
4546 Xalpha_m, TRUE, FALSE,
4547 EL_CHAR('M'), -1, -1
4550 Xalpha_n, TRUE, FALSE,
4551 EL_CHAR('N'), -1, -1
4554 Xalpha_o, TRUE, FALSE,
4555 EL_CHAR('O'), -1, -1
4558 Xalpha_p, TRUE, FALSE,
4559 EL_CHAR('P'), -1, -1
4562 Xalpha_q, TRUE, FALSE,
4563 EL_CHAR('Q'), -1, -1
4566 Xalpha_r, TRUE, FALSE,
4567 EL_CHAR('R'), -1, -1
4570 Xalpha_s, TRUE, FALSE,
4571 EL_CHAR('S'), -1, -1
4574 Xalpha_t, TRUE, FALSE,
4575 EL_CHAR('T'), -1, -1
4578 Xalpha_u, TRUE, FALSE,
4579 EL_CHAR('U'), -1, -1
4582 Xalpha_v, TRUE, FALSE,
4583 EL_CHAR('V'), -1, -1
4586 Xalpha_w, TRUE, FALSE,
4587 EL_CHAR('W'), -1, -1
4590 Xalpha_x, TRUE, FALSE,
4591 EL_CHAR('X'), -1, -1
4594 Xalpha_y, TRUE, FALSE,
4595 EL_CHAR('Y'), -1, -1
4598 Xalpha_z, TRUE, FALSE,
4599 EL_CHAR('Z'), -1, -1
4602 Xalpha_arrow_e, TRUE, FALSE,
4603 EL_CHAR('>'), -1, -1
4606 Xalpha_arrow_w, TRUE, FALSE,
4607 EL_CHAR('<'), -1, -1
4610 Xalpha_copyr, TRUE, FALSE,
4611 EL_CHAR('©'), -1, -1
4615 Xboom_bug, FALSE, FALSE,
4616 EL_BUG, ACTION_EXPLODING, -1
4619 Xboom_bomb, FALSE, FALSE,
4620 EL_BOMB, ACTION_EXPLODING, -1
4623 Xboom_android, FALSE, FALSE,
4624 EL_EMC_ANDROID, ACTION_OTHER, -1
4627 Xboom_1, FALSE, FALSE,
4628 EL_DEFAULT, ACTION_EXPLODING, -1
4631 Xboom_2, FALSE, FALSE,
4632 EL_DEFAULT, ACTION_EXPLODING, -1
4635 Znormal, FALSE, FALSE,
4639 Zdynamite, FALSE, FALSE,
4643 Zplayer, FALSE, FALSE,
4647 ZBORDER, FALSE, FALSE,
4657 static struct Mapping_EM_to_RND_player
4666 em_player_mapping_list[] =
4670 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4674 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4678 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4682 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4686 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4690 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4694 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4698 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4702 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4706 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4710 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4714 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4718 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4722 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4726 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4730 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4734 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4738 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4742 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4746 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4750 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4754 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4758 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4762 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4766 EL_PLAYER_1, ACTION_DEFAULT, -1,
4770 EL_PLAYER_2, ACTION_DEFAULT, -1,
4774 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4778 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4782 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4786 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4790 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4794 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4798 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4802 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4806 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4810 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4814 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4818 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4822 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4826 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4830 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4834 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4838 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4842 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4846 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4850 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4854 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4858 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4862 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4866 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
4870 EL_PLAYER_3, ACTION_DEFAULT, -1,
4874 EL_PLAYER_4, ACTION_DEFAULT, -1,
4883 int map_element_RND_to_EM(int element_rnd)
4885 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4886 static boolean mapping_initialized = FALSE;
4888 if (!mapping_initialized)
4892 /* return "Xalpha_quest" for all undefined elements in mapping array */
4893 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4894 mapping_RND_to_EM[i] = Xalpha_quest;
4896 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4897 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
4898 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
4899 em_object_mapping_list[i].element_em;
4901 mapping_initialized = TRUE;
4904 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4905 return mapping_RND_to_EM[element_rnd];
4907 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4912 int map_element_EM_to_RND(int element_em)
4914 static unsigned short mapping_EM_to_RND[TILE_MAX];
4915 static boolean mapping_initialized = FALSE;
4917 if (!mapping_initialized)
4921 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
4922 for (i = 0; i < TILE_MAX; i++)
4923 mapping_EM_to_RND[i] = EL_UNKNOWN;
4925 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4926 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
4927 em_object_mapping_list[i].element_rnd;
4929 mapping_initialized = TRUE;
4932 if (element_em >= 0 && element_em < TILE_MAX)
4933 return mapping_EM_to_RND[element_em];
4935 Error(ERR_WARN, "invalid EM level element %d", element_em);
4940 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
4942 struct LevelInfo_EM *level_em = level->native_em_level;
4943 struct LEVEL *lev = level_em->lev;
4946 for (i = 0; i < TILE_MAX; i++)
4947 lev->android_array[i] = Xblank;
4949 for (i = 0; i < level->num_android_clone_elements; i++)
4951 int element_rnd = level->android_clone_element[i];
4952 int element_em = map_element_RND_to_EM(element_rnd);
4954 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
4955 if (em_object_mapping_list[j].element_rnd == element_rnd)
4956 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
4960 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
4962 struct LevelInfo_EM *level_em = level->native_em_level;
4963 struct LEVEL *lev = level_em->lev;
4966 level->num_android_clone_elements = 0;
4968 for (i = 0; i < TILE_MAX; i++)
4970 int element_em = lev->android_array[i];
4972 boolean element_found = FALSE;
4974 if (element_em == Xblank)
4977 element_rnd = map_element_EM_to_RND(element_em);
4979 for (j = 0; j < level->num_android_clone_elements; j++)
4980 if (level->android_clone_element[j] == element_rnd)
4981 element_found = TRUE;
4985 level->android_clone_element[level->num_android_clone_elements++] =
4988 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
4993 if (level->num_android_clone_elements == 0)
4995 level->num_android_clone_elements = 1;
4996 level->android_clone_element[0] = EL_EMPTY;
5000 int map_direction_RND_to_EM(int direction)
5002 return (direction == MV_UP ? 0 :
5003 direction == MV_RIGHT ? 1 :
5004 direction == MV_DOWN ? 2 :
5005 direction == MV_LEFT ? 3 :
5009 int map_direction_EM_to_RND(int direction)
5011 return (direction == 0 ? MV_UP :
5012 direction == 1 ? MV_RIGHT :
5013 direction == 2 ? MV_DOWN :
5014 direction == 3 ? MV_LEFT :
5018 int get_next_element(int element)
5022 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5023 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5024 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5025 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5026 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5027 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5028 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5030 default: return element;
5035 int el_act_dir2img(int element, int action, int direction)
5037 element = GFX_ELEMENT(element);
5039 if (direction == MV_NONE)
5040 return element_info[element].graphic[action];
5042 direction = MV_DIR_TO_BIT(direction);
5044 return element_info[element].direction_graphic[action][direction];
5047 int el_act_dir2img(int element, int action, int direction)
5049 element = GFX_ELEMENT(element);
5050 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5052 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5053 return element_info[element].direction_graphic[action][direction];
5058 static int el_act_dir2crm(int element, int action, int direction)
5060 element = GFX_ELEMENT(element);
5062 if (direction == MV_NONE)
5063 return element_info[element].crumbled[action];
5065 direction = MV_DIR_TO_BIT(direction);
5067 return element_info[element].direction_crumbled[action][direction];
5070 static int el_act_dir2crm(int element, int action, int direction)
5072 element = GFX_ELEMENT(element);
5073 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5075 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5076 return element_info[element].direction_crumbled[action][direction];
5080 int el_act2img(int element, int action)
5082 element = GFX_ELEMENT(element);
5084 return element_info[element].graphic[action];
5087 int el_act2crm(int element, int action)
5089 element = GFX_ELEMENT(element);
5091 return element_info[element].crumbled[action];
5094 int el_dir2img(int element, int direction)
5096 element = GFX_ELEMENT(element);
5098 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5101 int el2baseimg(int element)
5103 return element_info[element].graphic[ACTION_DEFAULT];
5106 int el2img(int element)
5108 element = GFX_ELEMENT(element);
5110 return element_info[element].graphic[ACTION_DEFAULT];
5113 int el2edimg(int element)
5115 element = GFX_ELEMENT(element);
5117 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5120 int el2preimg(int element)
5122 element = GFX_ELEMENT(element);
5124 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5127 int font2baseimg(int font_nr)
5129 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5133 void setCenteredPlayerNr_EM(int centered_player_nr)
5135 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5138 int getCenteredPlayerNr_EM()
5141 if (game.centered_player_nr_next >= 0 &&
5142 !native_em_level.ply[game.centered_player_nr_next]->alive)
5143 game.centered_player_nr_next = game.centered_player_nr;
5146 if (game.centered_player_nr != game.centered_player_nr_next)
5147 game.centered_player_nr = game.centered_player_nr_next;
5149 return game.centered_player_nr;
5152 void setSetCenteredPlayer_EM(boolean set_centered_player)
5154 game.set_centered_player = set_centered_player;
5157 boolean getSetCenteredPlayer_EM()
5159 return game.set_centered_player;
5163 int getNumActivePlayers_EM()
5165 int num_players = 0;
5171 for (i = 0; i < MAX_PLAYERS; i++)
5172 if (tape.player_participates[i])
5179 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5181 int game_frame_delay_value;
5183 game_frame_delay_value =
5184 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5185 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5188 if (tape.playing && tape.warp_forward && !tape.pausing)
5189 game_frame_delay_value = 0;
5191 return game_frame_delay_value;
5195 unsigned int InitRND(long seed)
5197 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5198 return InitEngineRND_EM(seed);
5200 return InitEngineRND(seed);
5203 #define DEBUG_EM_GFX 0
5205 void InitGraphicInfo_EM(void)
5207 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5208 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5212 if (graphic_info_em_object[0][0].bitmap == NULL)
5214 /* EM graphics not yet initialized in em_open_all() */
5220 /* always start with reliable default values */
5221 for (i = 0; i < TILE_MAX; i++)
5223 object_mapping[i].element_rnd = EL_UNKNOWN;
5224 object_mapping[i].is_backside = FALSE;
5225 object_mapping[i].action = ACTION_DEFAULT;
5226 object_mapping[i].direction = MV_NONE;
5229 /* always start with reliable default values */
5230 for (p = 0; p < MAX_PLAYERS; p++)
5232 for (i = 0; i < SPR_MAX; i++)
5234 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5235 player_mapping[p][i].action = ACTION_DEFAULT;
5236 player_mapping[p][i].direction = MV_NONE;
5240 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5242 int e = em_object_mapping_list[i].element_em;
5244 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5245 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5247 if (em_object_mapping_list[i].action != -1)
5248 object_mapping[e].action = em_object_mapping_list[i].action;
5250 if (em_object_mapping_list[i].direction != -1)
5251 object_mapping[e].direction =
5252 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5255 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5257 int a = em_player_mapping_list[i].action_em;
5258 int p = em_player_mapping_list[i].player_nr;
5260 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5262 if (em_player_mapping_list[i].action != -1)
5263 player_mapping[p][a].action = em_player_mapping_list[i].action;
5265 if (em_player_mapping_list[i].direction != -1)
5266 player_mapping[p][a].direction =
5267 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5270 for (i = 0; i < TILE_MAX; i++)
5272 int element = object_mapping[i].element_rnd;
5273 int action = object_mapping[i].action;
5274 int direction = object_mapping[i].direction;
5275 boolean is_backside = object_mapping[i].is_backside;
5276 boolean action_removing = (action == ACTION_DIGGING ||
5277 action == ACTION_SNAPPING ||
5278 action == ACTION_COLLECTING);
5279 boolean action_exploding = ((action == ACTION_EXPLODING ||
5280 action == ACTION_SMASHED_BY_ROCK ||
5281 action == ACTION_SMASHED_BY_SPRING) &&
5282 element != EL_DIAMOND);
5283 boolean action_active = (action == ACTION_ACTIVE);
5284 boolean action_other = (action == ACTION_OTHER);
5286 for (j = 0; j < 8; j++)
5288 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5289 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5291 i == Xdrip_stretch ? element :
5292 i == Xdrip_stretchB ? element :
5293 i == Ydrip_s1 ? element :
5294 i == Ydrip_s1B ? element :
5295 i == Xball_1B ? element :
5296 i == Xball_2 ? element :
5297 i == Xball_2B ? element :
5298 i == Yball_eat ? element :
5299 i == Ykey_1_eat ? element :
5300 i == Ykey_2_eat ? element :
5301 i == Ykey_3_eat ? element :
5302 i == Ykey_4_eat ? element :
5303 i == Ykey_5_eat ? element :
5304 i == Ykey_6_eat ? element :
5305 i == Ykey_7_eat ? element :
5306 i == Ykey_8_eat ? element :
5307 i == Ylenses_eat ? element :
5308 i == Ymagnify_eat ? element :
5309 i == Ygrass_eat ? element :
5310 i == Ydirt_eat ? element :
5311 i == Yspring_kill_e ? EL_SPRING :
5312 i == Yspring_kill_w ? EL_SPRING :
5313 i == Yemerald_stone ? EL_EMERALD :
5314 i == Ydiamond_stone ? EL_ROCK :
5315 i == Xsand_stonein_4 ? EL_EMPTY :
5316 i == Xsand_stoneout_2 ? EL_ROCK :
5317 is_backside ? EL_EMPTY :
5318 action_removing ? EL_EMPTY :
5320 int effective_action = (j < 7 ? action :
5321 i == Xdrip_stretch ? action :
5322 i == Xdrip_stretchB ? action :
5323 i == Ydrip_s1 ? action :
5324 i == Ydrip_s1B ? action :
5325 i == Xball_1B ? action :
5326 i == Xball_2 ? action :
5327 i == Xball_2B ? action :
5328 i == Yball_eat ? action :
5329 i == Ykey_1_eat ? action :
5330 i == Ykey_2_eat ? action :
5331 i == Ykey_3_eat ? action :
5332 i == Ykey_4_eat ? action :
5333 i == Ykey_5_eat ? action :
5334 i == Ykey_6_eat ? action :
5335 i == Ykey_7_eat ? action :
5336 i == Ykey_8_eat ? action :
5337 i == Ylenses_eat ? action :
5338 i == Ymagnify_eat ? action :
5339 i == Ygrass_eat ? action :
5340 i == Ydirt_eat ? action :
5341 i == Xsand_stonein_1 ? action :
5342 i == Xsand_stonein_2 ? action :
5343 i == Xsand_stonein_3 ? action :
5344 i == Xsand_stonein_4 ? action :
5345 i == Xsand_stoneout_1 ? action :
5346 i == Xsand_stoneout_2 ? action :
5347 i == Xboom_android ? ACTION_EXPLODING :
5348 action_exploding ? ACTION_EXPLODING :
5349 action_active ? action :
5350 action_other ? action :
5352 int graphic = (el_act_dir2img(effective_element, effective_action,
5354 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5356 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5357 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5358 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5359 struct GraphicInfo *g = &graphic_info[graphic];
5360 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5363 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5364 boolean special_animation = (action != ACTION_DEFAULT &&
5365 g->anim_frames == 3 &&
5366 g->anim_delay == 2 &&
5367 g->anim_mode & ANIM_LINEAR);
5368 int sync_frame = (i == Xdrip_stretch ? 7 :
5369 i == Xdrip_stretchB ? 7 :
5370 i == Ydrip_s2 ? j + 8 :
5371 i == Ydrip_s2B ? j + 8 :
5380 i == Xfake_acid_1 ? 0 :
5381 i == Xfake_acid_2 ? 10 :
5382 i == Xfake_acid_3 ? 20 :
5383 i == Xfake_acid_4 ? 30 :
5384 i == Xfake_acid_5 ? 40 :
5385 i == Xfake_acid_6 ? 50 :
5386 i == Xfake_acid_7 ? 60 :
5387 i == Xfake_acid_8 ? 70 :
5389 i == Xball_2B ? j + 8 :
5390 i == Yball_eat ? j + 1 :
5391 i == Ykey_1_eat ? j + 1 :
5392 i == Ykey_2_eat ? j + 1 :
5393 i == Ykey_3_eat ? j + 1 :
5394 i == Ykey_4_eat ? j + 1 :
5395 i == Ykey_5_eat ? j + 1 :
5396 i == Ykey_6_eat ? j + 1 :
5397 i == Ykey_7_eat ? j + 1 :
5398 i == Ykey_8_eat ? j + 1 :
5399 i == Ylenses_eat ? j + 1 :
5400 i == Ymagnify_eat ? j + 1 :
5401 i == Ygrass_eat ? j + 1 :
5402 i == Ydirt_eat ? j + 1 :
5403 i == Xamoeba_1 ? 0 :
5404 i == Xamoeba_2 ? 1 :
5405 i == Xamoeba_3 ? 2 :
5406 i == Xamoeba_4 ? 3 :
5407 i == Xamoeba_5 ? 0 :
5408 i == Xamoeba_6 ? 1 :
5409 i == Xamoeba_7 ? 2 :
5410 i == Xamoeba_8 ? 3 :
5411 i == Xexit_2 ? j + 8 :
5412 i == Xexit_3 ? j + 16 :
5413 i == Xdynamite_1 ? 0 :
5414 i == Xdynamite_2 ? 8 :
5415 i == Xdynamite_3 ? 16 :
5416 i == Xdynamite_4 ? 24 :
5417 i == Xsand_stonein_1 ? j + 1 :
5418 i == Xsand_stonein_2 ? j + 9 :
5419 i == Xsand_stonein_3 ? j + 17 :
5420 i == Xsand_stonein_4 ? j + 25 :
5421 i == Xsand_stoneout_1 && j == 0 ? 0 :
5422 i == Xsand_stoneout_1 && j == 1 ? 0 :
5423 i == Xsand_stoneout_1 && j == 2 ? 1 :
5424 i == Xsand_stoneout_1 && j == 3 ? 2 :
5425 i == Xsand_stoneout_1 && j == 4 ? 2 :
5426 i == Xsand_stoneout_1 && j == 5 ? 3 :
5427 i == Xsand_stoneout_1 && j == 6 ? 4 :
5428 i == Xsand_stoneout_1 && j == 7 ? 4 :
5429 i == Xsand_stoneout_2 && j == 0 ? 5 :
5430 i == Xsand_stoneout_2 && j == 1 ? 6 :
5431 i == Xsand_stoneout_2 && j == 2 ? 7 :
5432 i == Xsand_stoneout_2 && j == 3 ? 8 :
5433 i == Xsand_stoneout_2 && j == 4 ? 9 :
5434 i == Xsand_stoneout_2 && j == 5 ? 11 :
5435 i == Xsand_stoneout_2 && j == 6 ? 13 :
5436 i == Xsand_stoneout_2 && j == 7 ? 15 :
5437 i == Xboom_bug && j == 1 ? 2 :
5438 i == Xboom_bug && j == 2 ? 2 :
5439 i == Xboom_bug && j == 3 ? 4 :
5440 i == Xboom_bug && j == 4 ? 4 :
5441 i == Xboom_bug && j == 5 ? 2 :
5442 i == Xboom_bug && j == 6 ? 2 :
5443 i == Xboom_bug && j == 7 ? 0 :
5444 i == Xboom_bomb && j == 1 ? 2 :
5445 i == Xboom_bomb && j == 2 ? 2 :
5446 i == Xboom_bomb && j == 3 ? 4 :
5447 i == Xboom_bomb && j == 4 ? 4 :
5448 i == Xboom_bomb && j == 5 ? 2 :
5449 i == Xboom_bomb && j == 6 ? 2 :
5450 i == Xboom_bomb && j == 7 ? 0 :
5451 i == Xboom_android && j == 7 ? 6 :
5452 i == Xboom_1 && j == 1 ? 2 :
5453 i == Xboom_1 && j == 2 ? 2 :
5454 i == Xboom_1 && j == 3 ? 4 :
5455 i == Xboom_1 && j == 4 ? 4 :
5456 i == Xboom_1 && j == 5 ? 6 :
5457 i == Xboom_1 && j == 6 ? 6 :
5458 i == Xboom_1 && j == 7 ? 8 :
5459 i == Xboom_2 && j == 0 ? 8 :
5460 i == Xboom_2 && j == 1 ? 8 :
5461 i == Xboom_2 && j == 2 ? 10 :
5462 i == Xboom_2 && j == 3 ? 10 :
5463 i == Xboom_2 && j == 4 ? 10 :
5464 i == Xboom_2 && j == 5 ? 12 :
5465 i == Xboom_2 && j == 6 ? 12 :
5466 i == Xboom_2 && j == 7 ? 12 :
5467 special_animation && j == 4 ? 3 :
5468 effective_action != action ? 0 :
5472 Bitmap *debug_bitmap = g_em->bitmap;
5473 int debug_src_x = g_em->src_x;
5474 int debug_src_y = g_em->src_y;
5477 int frame = getAnimationFrame(g->anim_frames,
5480 g->anim_start_frame,
5483 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5484 g->double_movement && is_backside);
5486 g_em->bitmap = src_bitmap;
5487 g_em->src_x = src_x;
5488 g_em->src_y = src_y;
5489 g_em->src_offset_x = 0;
5490 g_em->src_offset_y = 0;
5491 g_em->dst_offset_x = 0;
5492 g_em->dst_offset_y = 0;
5493 g_em->width = TILEX;
5494 g_em->height = TILEY;
5496 g_em->crumbled_bitmap = NULL;
5497 g_em->crumbled_src_x = 0;
5498 g_em->crumbled_src_y = 0;
5499 g_em->crumbled_border_size = 0;
5501 g_em->has_crumbled_graphics = FALSE;
5502 g_em->preserve_background = FALSE;
5505 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5506 printf("::: empty crumbled: %d [%s], %d, %d\n",
5507 effective_element, element_info[effective_element].token_name,
5508 effective_action, direction);
5511 /* if element can be crumbled, but certain action graphics are just empty
5512 space (like snapping sand with the original R'n'D graphics), do not
5513 treat these empty space graphics as crumbled graphics in EMC engine */
5514 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5516 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5518 g_em->has_crumbled_graphics = TRUE;
5519 g_em->crumbled_bitmap = src_bitmap;
5520 g_em->crumbled_src_x = src_x;
5521 g_em->crumbled_src_y = src_y;
5522 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5525 if (!g->double_movement && (effective_action == ACTION_FALLING ||
5526 effective_action == ACTION_MOVING ||
5527 effective_action == ACTION_PUSHING ||
5528 effective_action == ACTION_EATING))
5531 (effective_action == ACTION_FALLING ? MV_DOWN : direction);
5532 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5533 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5534 int num_steps = (i == Ydrip_s1 ||
5537 i == Ydrip_s2B ? 16 : 8);
5538 int cx = ABS(dx) * (TILEX / num_steps);
5539 int cy = ABS(dy) * (TILEY / num_steps);
5540 int step_frame = (i == Ydrip_s2 ||
5541 i == Ydrip_s2B ? j + 8 : j) + 1;
5542 int step = (is_backside ? step_frame : num_steps - step_frame);
5544 if (is_backside) /* tile where movement starts */
5546 if (dx < 0 || dy < 0)
5548 g_em->src_offset_x = cx * step;
5549 g_em->src_offset_y = cy * step;
5553 g_em->dst_offset_x = cx * step;
5554 g_em->dst_offset_y = cy * step;
5557 else /* tile where movement ends */
5559 if (dx < 0 || dy < 0)
5561 g_em->dst_offset_x = cx * step;
5562 g_em->dst_offset_y = cy * step;
5566 g_em->src_offset_x = cx * step;
5567 g_em->src_offset_y = cy * step;
5571 g_em->width = TILEX - cx * step;
5572 g_em->height = TILEY - cy * step;
5576 /* create unique graphic identifier to decide if tile must be redrawn */
5577 /* bit 31 - 16 (16 bit): EM style graphic
5578 bit 15 - 12 ( 4 bit): EM style frame
5579 bit 11 - 6 ( 6 bit): graphic width
5580 bit 5 - 0 ( 6 bit): graphic height */
5581 g_em->unique_identifier =
5582 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5584 /* create unique graphic identifier to decide if tile must be redrawn */
5585 /* bit 31 - 16 (16 bit): EM style element
5586 bit 15 - 12 ( 4 bit): EM style frame
5587 bit 11 - 6 ( 6 bit): graphic width
5588 bit 5 - 0 ( 6 bit): graphic height */
5589 g_em->unique_identifier =
5590 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5594 if (effective_element == EL_ROCK)
5595 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5596 effective_action, j, graphic, frame, g_em->unique_identifier);
5602 /* skip check for EMC elements not contained in original EMC artwork */
5603 if (element == EL_EMC_FAKE_ACID)
5607 if (g_em->bitmap != debug_bitmap ||
5608 g_em->src_x != debug_src_x ||
5609 g_em->src_y != debug_src_y ||
5610 g_em->src_offset_x != 0 ||
5611 g_em->src_offset_y != 0 ||
5612 g_em->dst_offset_x != 0 ||
5613 g_em->dst_offset_y != 0 ||
5614 g_em->width != TILEX ||
5615 g_em->height != TILEY)
5617 static int last_i = -1;
5625 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5626 i, element, element_info[element].token_name,
5627 element_action_info[effective_action].suffix, direction);
5629 if (element != effective_element)
5630 printf(" [%d ('%s')]",
5632 element_info[effective_element].token_name);
5636 if (g_em->bitmap != debug_bitmap)
5637 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5638 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5640 if (g_em->src_x != debug_src_x ||
5641 g_em->src_y != debug_src_y)
5642 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5643 j, (is_backside ? 'B' : 'F'),
5644 g_em->src_x, g_em->src_y,
5645 g_em->src_x / 32, g_em->src_y / 32,
5646 debug_src_x, debug_src_y,
5647 debug_src_x / 32, debug_src_y / 32);
5649 if (g_em->src_offset_x != 0 ||
5650 g_em->src_offset_y != 0 ||
5651 g_em->dst_offset_x != 0 ||
5652 g_em->dst_offset_y != 0)
5653 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5655 g_em->src_offset_x, g_em->src_offset_y,
5656 g_em->dst_offset_x, g_em->dst_offset_y);
5658 if (g_em->width != TILEX ||
5659 g_em->height != TILEY)
5660 printf(" %d (%d): size %d,%d should be %d,%d\n",
5662 g_em->width, g_em->height, TILEX, TILEY);
5669 for (i = 0; i < TILE_MAX; i++)
5671 for (j = 0; j < 8; j++)
5673 int element = object_mapping[i].element_rnd;
5674 int action = object_mapping[i].action;
5675 int direction = object_mapping[i].direction;
5676 boolean is_backside = object_mapping[i].is_backside;
5678 int graphic_action = el_act_dir2img(element, action, direction);
5679 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5681 int graphic_action = element_info[element].graphic[action];
5682 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5685 if ((action == ACTION_SMASHED_BY_ROCK ||
5686 action == ACTION_SMASHED_BY_SPRING ||
5687 action == ACTION_EATING) &&
5688 graphic_action == graphic_default)
5690 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5691 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5692 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5693 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5696 /* no separate animation for "smashed by rock" -- use rock instead */
5697 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5698 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5700 g_em->bitmap = g_xx->bitmap;
5701 g_em->src_x = g_xx->src_x;
5702 g_em->src_y = g_xx->src_y;
5703 g_em->src_offset_x = g_xx->src_offset_x;
5704 g_em->src_offset_y = g_xx->src_offset_y;
5705 g_em->dst_offset_x = g_xx->dst_offset_x;
5706 g_em->dst_offset_y = g_xx->dst_offset_y;
5707 g_em->width = g_xx->width;
5708 g_em->height = g_xx->height;
5710 g_em->unique_identifier = g_xx->unique_identifier;
5714 g_em->preserve_background = TRUE;
5719 for (p = 0; p < MAX_PLAYERS; p++)
5721 for (i = 0; i < SPR_MAX; i++)
5723 int element = player_mapping[p][i].element_rnd;
5724 int action = player_mapping[p][i].action;
5725 int direction = player_mapping[p][i].direction;
5727 for (j = 0; j < 8; j++)
5729 int effective_element = element;
5730 int effective_action = action;
5731 int graphic = (direction == MV_NONE ?
5732 el_act2img(effective_element, effective_action) :
5733 el_act_dir2img(effective_element, effective_action,
5735 struct GraphicInfo *g = &graphic_info[graphic];
5736 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5742 Bitmap *debug_bitmap = g_em->bitmap;
5743 int debug_src_x = g_em->src_x;
5744 int debug_src_y = g_em->src_y;
5747 int frame = getAnimationFrame(g->anim_frames,
5750 g->anim_start_frame,
5753 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5755 g_em->bitmap = src_bitmap;
5756 g_em->src_x = src_x;
5757 g_em->src_y = src_y;
5758 g_em->src_offset_x = 0;
5759 g_em->src_offset_y = 0;
5760 g_em->dst_offset_x = 0;
5761 g_em->dst_offset_y = 0;
5762 g_em->width = TILEX;
5763 g_em->height = TILEY;
5768 /* skip check for EMC elements not contained in original EMC artwork */
5769 if (element == EL_PLAYER_3 ||
5770 element == EL_PLAYER_4)
5774 if (g_em->bitmap != debug_bitmap ||
5775 g_em->src_x != debug_src_x ||
5776 g_em->src_y != debug_src_y)
5778 static int last_i = -1;
5786 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5787 p, i, element, element_info[element].token_name,
5788 element_action_info[effective_action].suffix, direction);
5790 if (element != effective_element)
5791 printf(" [%d ('%s')]",
5793 element_info[effective_element].token_name);
5797 if (g_em->bitmap != debug_bitmap)
5798 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5799 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5801 if (g_em->src_x != debug_src_x ||
5802 g_em->src_y != debug_src_y)
5803 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5805 g_em->src_x, g_em->src_y,
5806 g_em->src_x / 32, g_em->src_y / 32,
5807 debug_src_x, debug_src_y,
5808 debug_src_x / 32, debug_src_y / 32);