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)
67 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
70 if (!IN_LEV_FIELD(x, y))
72 printf("(not in level field)\n");
78 printf(" Feld: %d\t['%s']\n", Feld[x][y],
79 element_info[Feld[x][y]].token_name);
80 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
81 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
82 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
83 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
84 printf(" MovPos: %d\n", MovPos[x][y]);
85 printf(" MovDir: %d\n", MovDir[x][y]);
86 printf(" MovDelay: %d\n", MovDelay[x][y]);
87 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
88 printf(" CustomValue: %d\n", CustomValue[x][y]);
89 printf(" GfxElement: %d\n", GfxElement[x][y]);
90 printf(" GfxAction: %d\n", GfxAction[x][y]);
91 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
95 void SetDrawtoField(int mode)
97 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
108 drawto_field = fieldbuffer;
110 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
116 BX2 = SCR_FIELDX - 1;
117 BY2 = SCR_FIELDY - 1;
121 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
125 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
127 if (game_status == GAME_MODE_PLAYING &&
128 level.game_engine_type == GAME_ENGINE_TYPE_EM)
131 RedrawPlayfield_EM(force_redraw);
133 BlitScreenToBitmap_EM(backbuffer);
136 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
142 width = gfx.sxsize + 2 * TILEX;
143 height = gfx.sysize + 2 * TILEY;
146 if (force_redraw || setup.direct_draw)
149 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
150 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
152 if (setup.direct_draw)
153 SetDrawtoField(DRAW_BACKBUFFER);
155 for (xx = BX1; xx <= BX2; xx++)
156 for (yy = BY1; yy <= BY2; yy++)
157 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
158 DrawScreenField(xx, yy);
161 if (setup.direct_draw)
162 SetDrawtoField(DRAW_DIRECT);
165 if (setup.soft_scrolling)
167 int fx = FX, fy = FY;
169 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
170 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
172 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
176 BlitBitmap(drawto, window, x, y, width, height, x, y);
182 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
184 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
185 redraw_mask &= ~REDRAW_MAIN;
187 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
188 redraw_mask |= REDRAW_FIELD;
190 if (redraw_mask & REDRAW_FIELD)
191 redraw_mask &= ~REDRAW_TILES;
193 if (redraw_mask == REDRAW_NONE)
196 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
198 static boolean last_frame_skipped = FALSE;
199 boolean skip_even_when_not_scrolling = TRUE;
200 boolean just_scrolling = (ScreenMovDir != 0);
201 boolean verbose = FALSE;
203 if (global.fps_slowdown_factor > 1 &&
204 (FrameCounter % global.fps_slowdown_factor) &&
205 (just_scrolling || skip_even_when_not_scrolling))
207 redraw_mask &= ~REDRAW_MAIN;
209 last_frame_skipped = TRUE;
212 printf("FRAME SKIPPED\n");
216 if (last_frame_skipped)
217 redraw_mask |= REDRAW_FIELD;
219 last_frame_skipped = FALSE;
222 printf("frame not skipped\n");
226 /* synchronize X11 graphics at this point; if we would synchronize the
227 display immediately after the buffer switching (after the XFlush),
228 this could mean that we have to wait for the graphics to complete,
229 although we could go on doing calculations for the next frame */
233 if (redraw_mask & REDRAW_ALL)
235 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
239 if (redraw_mask & REDRAW_FIELD)
241 if (game_status != GAME_MODE_PLAYING ||
242 redraw_mask & REDRAW_FROM_BACKBUFFER)
244 BlitBitmap(backbuffer, window,
245 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
249 int fx = FX, fy = FY;
251 if (setup.soft_scrolling)
253 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
254 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
257 if (setup.soft_scrolling ||
258 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
259 ABS(ScreenMovPos) == ScrollStepSize ||
260 redraw_tiles > REDRAWTILES_THRESHOLD)
262 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
266 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
268 (setup.soft_scrolling ?
269 "setup.soft_scrolling" :
270 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
271 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
272 ABS(ScreenGfxPos) == ScrollStepSize ?
273 "ABS(ScreenGfxPos) == ScrollStepSize" :
274 "redraw_tiles > REDRAWTILES_THRESHOLD"));
280 redraw_mask &= ~REDRAW_MAIN;
283 if (redraw_mask & REDRAW_DOORS)
285 if (redraw_mask & REDRAW_DOOR_1)
286 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
288 if (redraw_mask & REDRAW_DOOR_2)
289 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
291 if (redraw_mask & REDRAW_DOOR_3)
292 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
294 redraw_mask &= ~REDRAW_DOORS;
297 if (redraw_mask & REDRAW_MICROLEVEL)
299 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
300 SX, SY + 10 * TILEY);
302 redraw_mask &= ~REDRAW_MICROLEVEL;
305 if (redraw_mask & REDRAW_TILES)
307 for (x = 0; x < SCR_FIELDX; x++)
308 for (y = 0 ; y < SCR_FIELDY; y++)
309 if (redraw[redraw_x1 + x][redraw_y1 + y])
310 BlitBitmap(buffer, window,
311 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
312 SX + x * TILEX, SY + y * TILEY);
315 if (redraw_mask & REDRAW_FPS) /* display frames per second */
320 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
321 if (!global.fps_slowdown)
324 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
325 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
330 for (x = 0; x < MAX_BUF_XSIZE; x++)
331 for (y = 0; y < MAX_BUF_YSIZE; y++)
334 redraw_mask = REDRAW_NONE;
340 long fading_delay = 300;
342 if (setup.fading && (redraw_mask & REDRAW_FIELD))
349 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
352 for (i = 0; i < 2 * FULL_SYSIZE; i++)
354 for (y = 0; y < FULL_SYSIZE; y++)
356 BlitBitmap(backbuffer, window,
357 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
365 for (i = 1; i < FULL_SYSIZE; i+=2)
366 BlitBitmap(backbuffer, window,
367 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
373 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
374 BlitBitmapMasked(backbuffer, window,
375 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
380 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
381 BlitBitmapMasked(backbuffer, window,
382 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
387 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
388 BlitBitmapMasked(backbuffer, window,
389 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
394 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
395 BlitBitmapMasked(backbuffer, window,
396 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
401 redraw_mask &= ~REDRAW_MAIN;
408 void SetMainBackgroundImageIfDefined(int graphic)
410 if (graphic_info[graphic].bitmap)
411 SetMainBackgroundImage(graphic);
414 void SetMainBackgroundImage(int graphic)
416 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
417 graphic_info[graphic].bitmap ?
418 graphic_info[graphic].bitmap :
419 graphic_info[IMG_BACKGROUND].bitmap);
422 void SetDoorBackgroundImage(int graphic)
424 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
425 graphic_info[graphic].bitmap ?
426 graphic_info[graphic].bitmap :
427 graphic_info[IMG_BACKGROUND].bitmap);
430 void DrawBackground(int dst_x, int dst_y, int width, int height)
432 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
434 redraw_mask |= REDRAW_FIELD;
439 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
441 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
443 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
444 SetDrawtoField(DRAW_BUFFERED);
447 SetDrawtoField(DRAW_BACKBUFFER);
449 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
451 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
452 SetDrawtoField(DRAW_DIRECT);
456 void MarkTileDirty(int x, int y)
458 int xx = redraw_x1 + x;
459 int yy = redraw_y1 + y;
464 redraw[xx][yy] = TRUE;
465 redraw_mask |= REDRAW_TILES;
468 void SetBorderElement()
472 BorderElement = EL_EMPTY;
474 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
476 for (x = 0; x < lev_fieldx; x++)
478 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
479 BorderElement = EL_STEELWALL;
481 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
487 void SetRandomAnimationValue(int x, int y)
489 gfx.anim_random_frame = GfxRandom[x][y];
492 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
494 /* animation synchronized with global frame counter, not move position */
495 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
496 sync_frame = FrameCounter;
498 return getAnimationFrame(graphic_info[graphic].anim_frames,
499 graphic_info[graphic].anim_delay,
500 graphic_info[graphic].anim_mode,
501 graphic_info[graphic].anim_start_frame,
505 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
506 int *x, int *y, boolean get_backside)
508 struct GraphicInfo *g = &graphic_info[graphic];
509 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
510 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
514 if (g->offset_y == 0) /* frames are ordered horizontally */
516 int max_width = g->anim_frames_per_line * g->width;
517 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
519 *x = pos % max_width;
520 *y = src_y % g->height + pos / max_width * g->height;
522 else if (g->offset_x == 0) /* frames are ordered vertically */
524 int max_height = g->anim_frames_per_line * g->height;
525 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
527 *x = src_x % g->width + pos / max_height * g->width;
528 *y = pos % max_height;
530 else /* frames are ordered diagonally */
532 *x = src_x + frame * g->offset_x;
533 *y = src_y + frame * g->offset_y;
537 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
539 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
542 void DrawGraphic(int x, int y, int graphic, int frame)
545 if (!IN_SCR_FIELD(x, y))
547 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
548 printf("DrawGraphic(): This should never happen!\n");
553 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
557 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
563 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
564 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
567 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
570 if (!IN_SCR_FIELD(x, y))
572 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
573 printf("DrawGraphicThruMask(): This should never happen!\n");
578 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
583 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
589 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
591 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
592 dst_x - src_x, dst_y - src_y);
593 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
596 void DrawMiniGraphic(int x, int y, int graphic)
598 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
599 MarkTileDirty(x / 2, y / 2);
602 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
604 struct GraphicInfo *g = &graphic_info[graphic];
606 int mini_starty = g->bitmap->height * 2 / 3;
609 *x = mini_startx + g->src_x / 2;
610 *y = mini_starty + g->src_y / 2;
613 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
618 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
619 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
622 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
623 int graphic, int frame,
624 int cut_mode, int mask_mode)
629 int width = TILEX, height = TILEY;
632 if (dx || dy) /* shifted graphic */
634 if (x < BX1) /* object enters playfield from the left */
641 else if (x > BX2) /* object enters playfield from the right */
647 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
653 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
655 else if (dx) /* general horizontal movement */
656 MarkTileDirty(x + SIGN(dx), y);
658 if (y < BY1) /* object enters playfield from the top */
660 if (cut_mode==CUT_BELOW) /* object completely above top border */
668 else if (y > BY2) /* object enters playfield from the bottom */
674 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
680 else if (dy > 0 && cut_mode == CUT_ABOVE)
682 if (y == BY2) /* object completely above bottom border */
688 MarkTileDirty(x, y + 1);
689 } /* object leaves playfield to the bottom */
690 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
692 else if (dy) /* general vertical movement */
693 MarkTileDirty(x, y + SIGN(dy));
697 if (!IN_SCR_FIELD(x, y))
699 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
700 printf("DrawGraphicShifted(): This should never happen!\n");
705 if (width > 0 && height > 0)
707 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
712 dst_x = FX + x * TILEX + dx;
713 dst_y = FY + y * TILEY + dy;
715 if (mask_mode == USE_MASKING)
717 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
718 dst_x - src_x, dst_y - src_y);
719 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
723 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
730 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
731 int graphic, int frame,
732 int cut_mode, int mask_mode)
737 int width = TILEX, height = TILEY;
740 int x2 = x + SIGN(dx);
741 int y2 = y + SIGN(dy);
742 int anim_frames = graphic_info[graphic].anim_frames;
743 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
744 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
745 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
747 /* re-calculate animation frame for two-tile movement animation */
748 frame = getGraphicAnimationFrame(graphic, sync_frame);
750 /* check if movement start graphic inside screen area and should be drawn */
751 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
753 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
755 dst_x = FX + x1 * TILEX;
756 dst_y = FY + y1 * TILEY;
758 if (mask_mode == USE_MASKING)
760 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
761 dst_x - src_x, dst_y - src_y);
762 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
766 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
769 MarkTileDirty(x1, y1);
772 /* check if movement end graphic inside screen area and should be drawn */
773 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
775 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
777 dst_x = FX + x2 * TILEX;
778 dst_y = FY + y2 * TILEY;
780 if (mask_mode == USE_MASKING)
782 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
783 dst_x - src_x, dst_y - src_y);
784 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
788 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
791 MarkTileDirty(x2, y2);
795 static void DrawGraphicShifted(int x, int y, int dx, int dy,
796 int graphic, int frame,
797 int cut_mode, int mask_mode)
801 DrawGraphic(x, y, graphic, frame);
806 if (graphic_info[graphic].double_movement) /* EM style movement images */
807 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
809 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
812 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
813 int frame, int cut_mode)
815 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
818 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
819 int cut_mode, int mask_mode)
821 int lx = LEVELX(x), ly = LEVELY(y);
825 if (IN_LEV_FIELD(lx, ly))
827 SetRandomAnimationValue(lx, ly);
829 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
830 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
832 /* do not use double (EM style) movement graphic when not moving */
833 if (graphic_info[graphic].double_movement && !dx && !dy)
835 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
836 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
839 else /* border element */
841 graphic = el2img(element);
842 frame = getGraphicAnimationFrame(graphic, -1);
845 if (element == EL_EXPANDABLE_WALL)
847 boolean left_stopped = FALSE, right_stopped = FALSE;
849 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
851 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
852 right_stopped = TRUE;
854 if (left_stopped && right_stopped)
856 else if (left_stopped)
858 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
859 frame = graphic_info[graphic].anim_frames - 1;
861 else if (right_stopped)
863 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
864 frame = graphic_info[graphic].anim_frames - 1;
869 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
870 else if (mask_mode == USE_MASKING)
871 DrawGraphicThruMask(x, y, graphic, frame);
873 DrawGraphic(x, y, graphic, frame);
876 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
877 int cut_mode, int mask_mode)
879 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
880 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
881 cut_mode, mask_mode);
884 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
887 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
890 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
893 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
896 void DrawLevelElementThruMask(int x, int y, int element)
898 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
901 void DrawLevelFieldThruMask(int x, int y)
903 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
906 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
910 int sx = SCREENX(x), sy = SCREENY(y);
912 int width, height, cx, cy, i;
913 int crumbled_border_size = graphic_info[graphic].border_size;
914 static int xy[4][2] =
922 if (!IN_LEV_FIELD(x, y))
925 element = TILE_GFX_ELEMENT(x, y);
927 /* crumble field itself */
928 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
930 if (!IN_SCR_FIELD(sx, sy))
933 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
935 for (i = 0; i < 4; i++)
937 int xx = x + xy[i][0];
938 int yy = y + xy[i][1];
940 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
943 /* check if neighbour field is of same type */
944 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
947 if (i == 1 || i == 2)
949 width = crumbled_border_size;
951 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
957 height = crumbled_border_size;
959 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
962 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
963 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
966 MarkTileDirty(sx, sy);
968 else /* crumble neighbour fields */
970 for (i = 0; i < 4; i++)
972 int xx = x + xy[i][0];
973 int yy = y + xy[i][1];
974 int sxx = sx + xy[i][0];
975 int syy = sy + xy[i][1];
978 if (!IN_LEV_FIELD(xx, yy) ||
979 !IN_SCR_FIELD(sxx, syy) ||
984 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
988 element = TILE_GFX_ELEMENT(xx, yy);
990 if (!GFX_CRUMBLED(element))
993 if (!IN_LEV_FIELD(xx, yy) ||
994 !IN_SCR_FIELD(sxx, syy) ||
995 !GFX_CRUMBLED(Feld[xx][yy]) ||
1001 graphic = el_act2crm(element, ACTION_DEFAULT);
1003 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1005 crumbled_border_size = graphic_info[graphic].border_size;
1007 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1009 if (i == 1 || i == 2)
1011 width = crumbled_border_size;
1013 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1019 height = crumbled_border_size;
1021 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1024 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1025 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1027 MarkTileDirty(sxx, syy);
1032 void DrawLevelFieldCrumbledSand(int x, int y)
1036 if (!IN_LEV_FIELD(x, y))
1041 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1042 GFX_CRUMBLED(GfxElement[x][y]))
1045 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1046 GfxElement[x][y] != EL_UNDEFINED &&
1047 GFX_CRUMBLED(GfxElement[x][y]))
1049 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1056 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1058 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1061 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1064 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1067 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1068 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1069 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1070 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1071 int sx = SCREENX(x), sy = SCREENY(y);
1073 DrawGraphic(sx, sy, graphic1, frame1);
1074 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1077 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1079 int sx = SCREENX(x), sy = SCREENY(y);
1080 static int xy[4][2] =
1089 for (i = 0; i < 4; i++)
1091 int xx = x + xy[i][0];
1092 int yy = y + xy[i][1];
1093 int sxx = sx + xy[i][0];
1094 int syy = sy + xy[i][1];
1096 if (!IN_LEV_FIELD(xx, yy) ||
1097 !IN_SCR_FIELD(sxx, syy) ||
1098 !GFX_CRUMBLED(Feld[xx][yy]) ||
1102 DrawLevelField(xx, yy);
1106 static int getBorderElement(int x, int y)
1110 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1111 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1112 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1113 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1114 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1115 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1116 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1118 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1119 int steel_position = (x == -1 && y == -1 ? 0 :
1120 x == lev_fieldx && y == -1 ? 1 :
1121 x == -1 && y == lev_fieldy ? 2 :
1122 x == lev_fieldx && y == lev_fieldy ? 3 :
1123 x == -1 || x == lev_fieldx ? 4 :
1124 y == -1 || y == lev_fieldy ? 5 : 6);
1126 return border[steel_position][steel_type];
1129 void DrawScreenElement(int x, int y, int element)
1131 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1132 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1135 void DrawLevelElement(int x, int y, int element)
1137 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1138 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1141 void DrawScreenField(int x, int y)
1143 int lx = LEVELX(x), ly = LEVELY(y);
1144 int element, content;
1146 if (!IN_LEV_FIELD(lx, ly))
1148 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1151 element = getBorderElement(lx, ly);
1153 DrawScreenElement(x, y, element);
1157 element = Feld[lx][ly];
1158 content = Store[lx][ly];
1160 if (IS_MOVING(lx, ly))
1162 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1163 boolean cut_mode = NO_CUTTING;
1165 if (element == EL_QUICKSAND_EMPTYING ||
1166 element == EL_MAGIC_WALL_EMPTYING ||
1167 element == EL_BD_MAGIC_WALL_EMPTYING ||
1168 element == EL_AMOEBA_DROPPING)
1169 cut_mode = CUT_ABOVE;
1170 else if (element == EL_QUICKSAND_FILLING ||
1171 element == EL_MAGIC_WALL_FILLING ||
1172 element == EL_BD_MAGIC_WALL_FILLING)
1173 cut_mode = CUT_BELOW;
1175 if (cut_mode == CUT_ABOVE)
1176 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1178 DrawScreenElement(x, y, EL_EMPTY);
1181 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1182 else if (cut_mode == NO_CUTTING)
1183 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1185 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1187 if (content == EL_ACID)
1189 int dir = MovDir[lx][ly];
1190 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1191 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1193 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1196 else if (IS_BLOCKED(lx, ly))
1201 boolean cut_mode = NO_CUTTING;
1202 int element_old, content_old;
1204 Blocked2Moving(lx, ly, &oldx, &oldy);
1207 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1208 MovDir[oldx][oldy] == MV_RIGHT);
1210 element_old = Feld[oldx][oldy];
1211 content_old = Store[oldx][oldy];
1213 if (element_old == EL_QUICKSAND_EMPTYING ||
1214 element_old == EL_MAGIC_WALL_EMPTYING ||
1215 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1216 element_old == EL_AMOEBA_DROPPING)
1217 cut_mode = CUT_ABOVE;
1219 DrawScreenElement(x, y, EL_EMPTY);
1222 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1224 else if (cut_mode == NO_CUTTING)
1225 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1228 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1231 else if (IS_DRAWABLE(element))
1232 DrawScreenElement(x, y, element);
1234 DrawScreenElement(x, y, EL_EMPTY);
1237 void DrawLevelField(int x, int y)
1239 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1240 DrawScreenField(SCREENX(x), SCREENY(y));
1241 else if (IS_MOVING(x, y))
1245 Moving2Blocked(x, y, &newx, &newy);
1246 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1247 DrawScreenField(SCREENX(newx), SCREENY(newy));
1249 else if (IS_BLOCKED(x, y))
1253 Blocked2Moving(x, y, &oldx, &oldy);
1254 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1255 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1259 void DrawMiniElement(int x, int y, int element)
1263 graphic = el2edimg(element);
1264 DrawMiniGraphic(x, y, graphic);
1267 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1269 int x = sx + scroll_x, y = sy + scroll_y;
1271 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1272 DrawMiniElement(sx, sy, EL_EMPTY);
1273 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1274 DrawMiniElement(sx, sy, Feld[x][y]);
1276 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1279 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1280 int x, int y, int xsize, int ysize, int font_nr)
1282 int font_width = getFontWidth(font_nr);
1283 int font_height = getFontHeight(font_nr);
1284 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1287 int dst_x = SX + startx + x * font_width;
1288 int dst_y = SY + starty + y * font_height;
1289 int width = graphic_info[graphic].width;
1290 int height = graphic_info[graphic].height;
1291 int inner_width = MAX(width - 2 * font_width, font_width);
1292 int inner_height = MAX(height - 2 * font_height, font_height);
1293 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1294 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1295 boolean draw_masked = graphic_info[graphic].draw_masked;
1297 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1299 if (src_bitmap == NULL || width < font_width || height < font_height)
1301 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1305 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1306 inner_sx + (x - 1) * font_width % inner_width);
1307 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1308 inner_sy + (y - 1) * font_height % inner_height);
1312 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1313 dst_x - src_x, dst_y - src_y);
1314 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1318 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1322 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1324 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1325 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1326 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1327 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1328 boolean no_delay = (tape.warp_forward);
1329 unsigned long anim_delay = 0;
1330 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1331 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1332 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1333 int font_width = getFontWidth(font_nr);
1334 int font_height = getFontHeight(font_nr);
1335 int max_xsize = level.envelope_xsize[envelope_nr];
1336 int max_ysize = level.envelope_ysize[envelope_nr];
1337 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1338 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1339 int xend = max_xsize;
1340 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1341 int xstep = (xstart < xend ? 1 : 0);
1342 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1345 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1347 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1348 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1349 int sx = (SXSIZE - xsize * font_width) / 2;
1350 int sy = (SYSIZE - ysize * font_height) / 2;
1353 SetDrawtoField(DRAW_BUFFERED);
1355 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1357 SetDrawtoField(DRAW_BACKBUFFER);
1359 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1360 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1362 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1363 level.envelope_text[envelope_nr], font_nr, max_xsize,
1364 xsize - 2, ysize - 2, mask_mode);
1366 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1369 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1373 void ShowEnvelope(int envelope_nr)
1375 int element = EL_ENVELOPE_1 + envelope_nr;
1376 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1377 int sound_opening = element_info[element].sound[ACTION_OPENING];
1378 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1379 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1380 boolean no_delay = (tape.warp_forward);
1381 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1382 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1383 int anim_mode = graphic_info[graphic].anim_mode;
1384 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1385 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1387 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1389 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1391 if (anim_mode == ANIM_DEFAULT)
1392 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1394 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1397 Delay(wait_delay_value);
1399 WaitForEventToContinue();
1401 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1403 if (anim_mode != ANIM_NONE)
1404 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1406 if (anim_mode == ANIM_DEFAULT)
1407 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1409 game.envelope_active = FALSE;
1411 SetDrawtoField(DRAW_BUFFERED);
1413 redraw_mask |= REDRAW_FIELD;
1417 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1419 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1420 int mini_startx = src_bitmap->width * 3 / 4;
1421 int mini_starty = src_bitmap->height * 2 / 3;
1422 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1423 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1425 *bitmap = src_bitmap;
1430 void DrawMicroElement(int xpos, int ypos, int element)
1434 int graphic = el2preimg(element);
1436 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1437 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1445 SetDrawBackgroundMask(REDRAW_NONE);
1448 for (x = BX1; x <= BX2; x++)
1449 for (y = BY1; y <= BY2; y++)
1450 DrawScreenField(x, y);
1452 redraw_mask |= REDRAW_FIELD;
1455 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1459 for (x = 0; x < size_x; x++)
1460 for (y = 0; y < size_y; y++)
1461 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1463 redraw_mask |= REDRAW_FIELD;
1466 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1470 DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
1472 if (lev_fieldx < STD_LEV_FIELDX)
1473 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1474 if (lev_fieldy < STD_LEV_FIELDY)
1475 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1477 xpos += MICRO_TILEX;
1478 ypos += MICRO_TILEY;
1480 for (x = -1; x <= STD_LEV_FIELDX; x++)
1482 for (y = -1; y <= STD_LEV_FIELDY; y++)
1484 int lx = from_x + x, ly = from_y + y;
1486 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1487 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1488 level.field[lx][ly]);
1489 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1490 && BorderElement != EL_EMPTY)
1491 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1492 getBorderElement(lx, ly));
1496 redraw_mask |= REDRAW_MICROLEVEL;
1499 #define MICROLABEL_EMPTY 0
1500 #define MICROLABEL_LEVEL_NAME 1
1501 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1502 #define MICROLABEL_LEVEL_AUTHOR 3
1503 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1504 #define MICROLABEL_IMPORTED_FROM 5
1505 #define MICROLABEL_IMPORTED_BY_HEAD 6
1506 #define MICROLABEL_IMPORTED_BY 7
1508 static void DrawMicroLevelLabelExt(int mode)
1510 char label_text[MAX_OUTPUT_LINESIZE + 1];
1511 int max_len_label_text;
1512 int font_nr = FONT_TEXT_2;
1515 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1516 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1517 mode == MICROLABEL_IMPORTED_BY_HEAD)
1518 font_nr = FONT_TEXT_3;
1520 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1522 for (i = 0; i < max_len_label_text; i++)
1523 label_text[i] = ' ';
1524 label_text[max_len_label_text] = '\0';
1526 if (strlen(label_text) > 0)
1528 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1529 int lypos = MICROLABEL2_YPOS;
1531 DrawText(lxpos, lypos, label_text, font_nr);
1535 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1536 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1537 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1538 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1539 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1540 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1541 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1542 max_len_label_text);
1543 label_text[max_len_label_text] = '\0';
1545 if (strlen(label_text) > 0)
1547 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1548 int lypos = MICROLABEL2_YPOS;
1550 DrawText(lxpos, lypos, label_text, font_nr);
1553 redraw_mask |= REDRAW_MICROLEVEL;
1556 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1558 static unsigned long scroll_delay = 0;
1559 static unsigned long label_delay = 0;
1560 static int from_x, from_y, scroll_direction;
1561 static int label_state, label_counter;
1562 int last_game_status = game_status; /* save current game status */
1564 /* force PREVIEW font on preview level */
1565 game_status = GAME_MODE_PSEUDO_PREVIEW;
1569 from_x = from_y = 0;
1570 scroll_direction = MV_RIGHT;
1574 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1575 DrawMicroLevelLabelExt(label_state);
1577 /* initialize delay counters */
1578 DelayReached(&scroll_delay, 0);
1579 DelayReached(&label_delay, 0);
1581 if (leveldir_current->name)
1583 char label_text[MAX_OUTPUT_LINESIZE + 1];
1584 int font_nr = FONT_TEXT_1;
1585 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1588 strncpy(label_text, leveldir_current->name, max_len_label_text);
1589 label_text[max_len_label_text] = '\0';
1591 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1592 lypos = SY + MICROLABEL1_YPOS;
1594 DrawText(lxpos, lypos, label_text, font_nr);
1597 game_status = last_game_status; /* restore current game status */
1602 /* scroll micro level, if needed */
1603 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1604 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1606 switch (scroll_direction)
1612 scroll_direction = MV_UP;
1616 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1619 scroll_direction = MV_DOWN;
1626 scroll_direction = MV_RIGHT;
1630 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1633 scroll_direction = MV_LEFT;
1640 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1643 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1644 /* redraw micro level label, if needed */
1645 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1646 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1647 strcmp(level.author, leveldir_current->name) != 0 &&
1648 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1650 int max_label_counter = 23;
1652 if (leveldir_current->imported_from != NULL &&
1653 strlen(leveldir_current->imported_from) > 0)
1654 max_label_counter += 14;
1655 if (leveldir_current->imported_by != NULL &&
1656 strlen(leveldir_current->imported_by) > 0)
1657 max_label_counter += 14;
1659 label_counter = (label_counter + 1) % max_label_counter;
1660 label_state = (label_counter >= 0 && label_counter <= 7 ?
1661 MICROLABEL_LEVEL_NAME :
1662 label_counter >= 9 && label_counter <= 12 ?
1663 MICROLABEL_LEVEL_AUTHOR_HEAD :
1664 label_counter >= 14 && label_counter <= 21 ?
1665 MICROLABEL_LEVEL_AUTHOR :
1666 label_counter >= 23 && label_counter <= 26 ?
1667 MICROLABEL_IMPORTED_FROM_HEAD :
1668 label_counter >= 28 && label_counter <= 35 ?
1669 MICROLABEL_IMPORTED_FROM :
1670 label_counter >= 37 && label_counter <= 40 ?
1671 MICROLABEL_IMPORTED_BY_HEAD :
1672 label_counter >= 42 && label_counter <= 49 ?
1673 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1675 if (leveldir_current->imported_from == NULL &&
1676 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1677 label_state == MICROLABEL_IMPORTED_FROM))
1678 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1679 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1681 DrawMicroLevelLabelExt(label_state);
1684 game_status = last_game_status; /* restore current game status */
1687 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1688 int graphic, int sync_frame, int mask_mode)
1690 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1692 if (mask_mode == USE_MASKING)
1693 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1695 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1698 inline void DrawGraphicAnimation(int x, int y, int graphic)
1700 int lx = LEVELX(x), ly = LEVELY(y);
1702 if (!IN_SCR_FIELD(x, y))
1705 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1706 graphic, GfxFrame[lx][ly], NO_MASKING);
1707 MarkTileDirty(x, y);
1710 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1712 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1715 void DrawLevelElementAnimation(int x, int y, int element)
1717 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1719 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1722 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1724 int sx = SCREENX(x), sy = SCREENY(y);
1726 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1729 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1732 DrawGraphicAnimation(sx, sy, graphic);
1735 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1736 DrawLevelFieldCrumbledSand(x, y);
1738 if (GFX_CRUMBLED(Feld[x][y]))
1739 DrawLevelFieldCrumbledSand(x, y);
1743 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1745 int sx = SCREENX(x), sy = SCREENY(y);
1748 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1751 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1753 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1756 DrawGraphicAnimation(sx, sy, graphic);
1758 if (GFX_CRUMBLED(element))
1759 DrawLevelFieldCrumbledSand(x, y);
1762 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1764 if (player->use_murphy)
1766 /* this works only because currently only one player can be "murphy" ... */
1767 static int last_horizontal_dir = MV_LEFT;
1768 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1770 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1771 last_horizontal_dir = move_dir;
1773 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1775 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1777 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1783 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1786 static boolean equalGraphics(int graphic1, int graphic2)
1788 struct GraphicInfo *g1 = &graphic_info[graphic1];
1789 struct GraphicInfo *g2 = &graphic_info[graphic2];
1791 return (g1->bitmap == g2->bitmap &&
1792 g1->src_x == g2->src_x &&
1793 g1->src_y == g2->src_y &&
1794 g1->anim_frames == g2->anim_frames &&
1795 g1->anim_delay == g2->anim_delay &&
1796 g1->anim_mode == g2->anim_mode);
1799 void DrawAllPlayers()
1803 for (i = 0; i < MAX_PLAYERS; i++)
1804 if (stored_player[i].active)
1805 DrawPlayer(&stored_player[i]);
1808 void DrawPlayerField(int x, int y)
1810 if (!IS_PLAYER(x, y))
1813 DrawPlayer(PLAYERINFO(x, y));
1816 void DrawPlayer(struct PlayerInfo *player)
1818 int jx = player->jx;
1819 int jy = player->jy;
1820 int move_dir = player->MovDir;
1821 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1822 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1823 int last_jx = (player->is_moving ? jx - dx : jx);
1824 int last_jy = (player->is_moving ? jy - dy : jy);
1825 int next_jx = jx + dx;
1826 int next_jy = jy + dy;
1827 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1828 boolean player_is_opaque = FALSE;
1829 int sx = SCREENX(jx), sy = SCREENY(jy);
1830 int sxx = 0, syy = 0;
1831 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1833 int action = ACTION_DEFAULT;
1834 int last_player_graphic = getPlayerGraphic(player, move_dir);
1835 int last_player_frame = player->Frame;
1839 /* GfxElement[][] is set to the element the player is digging or collecting;
1840 remove also for off-screen player if the player is not moving anymore */
1841 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1842 GfxElement[jx][jy] = EL_UNDEFINED;
1845 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1849 if (!IN_LEV_FIELD(jx, jy))
1851 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1852 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1853 printf("DrawPlayerField(): This should never happen!\n");
1858 if (element == EL_EXPLOSION)
1861 action = (player->is_pushing ? ACTION_PUSHING :
1862 player->is_digging ? ACTION_DIGGING :
1863 player->is_collecting ? ACTION_COLLECTING :
1864 player->is_moving ? ACTION_MOVING :
1865 player->is_snapping ? ACTION_SNAPPING :
1866 player->is_dropping ? ACTION_DROPPING :
1867 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1870 if (player->is_waiting)
1871 move_dir = player->dir_waiting;
1874 InitPlayerGfxAnimation(player, action, move_dir);
1876 /* ----------------------------------------------------------------------- */
1877 /* draw things in the field the player is leaving, if needed */
1878 /* ----------------------------------------------------------------------- */
1880 if (player->is_moving)
1882 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1884 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1886 if (last_element == EL_DYNAMITE_ACTIVE ||
1887 last_element == EL_EM_DYNAMITE_ACTIVE ||
1888 last_element == EL_SP_DISK_RED_ACTIVE)
1889 DrawDynamite(last_jx, last_jy);
1891 DrawLevelFieldThruMask(last_jx, last_jy);
1893 else if (last_element == EL_DYNAMITE_ACTIVE ||
1894 last_element == EL_EM_DYNAMITE_ACTIVE ||
1895 last_element == EL_SP_DISK_RED_ACTIVE)
1896 DrawDynamite(last_jx, last_jy);
1898 DrawLevelField(last_jx, last_jy);
1900 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
1901 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
1904 if (!IN_SCR_FIELD(sx, sy))
1907 if (setup.direct_draw)
1908 SetDrawtoField(DRAW_BUFFERED);
1910 /* ----------------------------------------------------------------------- */
1911 /* draw things behind the player, if needed */
1912 /* ----------------------------------------------------------------------- */
1915 DrawLevelElement(jx, jy, Back[jx][jy]);
1916 else if (IS_ACTIVE_BOMB(element))
1917 DrawLevelElement(jx, jy, EL_EMPTY);
1920 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
1922 int old_element = GfxElement[jx][jy];
1923 int old_graphic = el_act_dir2img(old_element, action, move_dir);
1924 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
1926 if (GFX_CRUMBLED(old_element))
1927 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
1929 DrawGraphic(sx, sy, old_graphic, frame);
1931 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
1932 player_is_opaque = TRUE;
1936 GfxElement[jx][jy] = EL_UNDEFINED;
1938 /* make sure that pushed elements are drawn with correct frame rate */
1939 if (player->is_pushing && player->is_moving)
1940 GfxFrame[jx][jy] = player->StepFrame;
1942 DrawLevelField(jx, jy);
1946 /* ----------------------------------------------------------------------- */
1947 /* draw player himself */
1948 /* ----------------------------------------------------------------------- */
1950 graphic = getPlayerGraphic(player, move_dir);
1952 /* in the case of changed player action or direction, prevent the current
1953 animation frame from being restarted for identical animations */
1954 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
1955 player->Frame = last_player_frame;
1957 frame = getGraphicAnimationFrame(graphic, player->Frame);
1961 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1962 sxx = player->GfxPos;
1964 syy = player->GfxPos;
1967 if (!setup.soft_scrolling && ScreenMovPos)
1970 if (player_is_opaque)
1971 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
1973 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1975 if (SHIELD_ON(player))
1977 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
1978 IMG_SHIELD_NORMAL_ACTIVE);
1979 int frame = getGraphicAnimationFrame(graphic, -1);
1981 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1984 /* ----------------------------------------------------------------------- */
1985 /* draw things the player is pushing, if needed */
1986 /* ----------------------------------------------------------------------- */
1989 printf("::: %d, %d [%d, %d] [%d]\n",
1990 player->is_pushing, player_is_moving, player->GfxAction,
1991 player->is_moving, player_is_moving);
1995 if (player->is_pushing && player->is_moving)
1997 int px = SCREENX(jx), py = SCREENY(jy);
1998 int pxx = (TILEX - ABS(sxx)) * dx;
1999 int pyy = (TILEY - ABS(syy)) * dy;
2004 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2005 element = Feld[next_jx][next_jy];
2007 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2008 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2010 /* draw background element under pushed element (like the Sokoban field) */
2011 if (Back[next_jx][next_jy])
2012 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2014 /* masked drawing is needed for EMC style (double) movement graphics */
2015 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2019 /* ----------------------------------------------------------------------- */
2020 /* draw things in front of player (active dynamite or dynabombs) */
2021 /* ----------------------------------------------------------------------- */
2023 if (IS_ACTIVE_BOMB(element))
2025 graphic = el2img(element);
2026 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2028 if (game.emulation == EMU_SUPAPLEX)
2029 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2031 DrawGraphicThruMask(sx, sy, graphic, frame);
2034 if (player_is_moving && last_element == EL_EXPLOSION)
2036 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2037 GfxElement[last_jx][last_jy] : EL_EMPTY);
2038 int graphic = el_act2img(element, ACTION_EXPLODING);
2039 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2040 int phase = ExplodePhase[last_jx][last_jy] - 1;
2041 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2044 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2047 /* ----------------------------------------------------------------------- */
2048 /* draw elements the player is just walking/passing through/under */
2049 /* ----------------------------------------------------------------------- */
2051 if (player_is_moving)
2053 /* handle the field the player is leaving ... */
2054 if (IS_ACCESSIBLE_INSIDE(last_element))
2055 DrawLevelField(last_jx, last_jy);
2056 else if (IS_ACCESSIBLE_UNDER(last_element))
2057 DrawLevelFieldThruMask(last_jx, last_jy);
2060 /* do not redraw accessible elements if the player is just pushing them */
2061 if (!player_is_moving || !player->is_pushing)
2063 /* ... and the field the player is entering */
2064 if (IS_ACCESSIBLE_INSIDE(element))
2065 DrawLevelField(jx, jy);
2066 else if (IS_ACCESSIBLE_UNDER(element))
2067 DrawLevelFieldThruMask(jx, jy);
2070 if (setup.direct_draw)
2072 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2073 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2074 int x_size = TILEX * (1 + ABS(jx - last_jx));
2075 int y_size = TILEY * (1 + ABS(jy - last_jy));
2077 BlitBitmap(drawto_field, window,
2078 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2079 SetDrawtoField(DRAW_DIRECT);
2082 MarkTileDirty(sx, sy);
2085 /* ------------------------------------------------------------------------- */
2087 void WaitForEventToContinue()
2089 boolean still_wait = TRUE;
2091 /* simulate releasing mouse button over last gadget, if still pressed */
2093 HandleGadgets(-1, -1, 0);
2095 button_status = MB_RELEASED;
2107 case EVENT_BUTTONPRESS:
2108 case EVENT_KEYPRESS:
2112 case EVENT_KEYRELEASE:
2113 ClearPlayerAction();
2117 HandleOtherEvents(&event);
2121 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2128 /* don't eat all CPU time */
2133 #define MAX_REQUEST_LINES 13
2134 #define MAX_REQUEST_LINE_FONT1_LEN 7
2135 #define MAX_REQUEST_LINE_FONT2_LEN 10
2137 boolean Request(char *text, unsigned int req_state)
2139 int mx, my, ty, result = -1;
2140 unsigned int old_door_state;
2141 int last_game_status = game_status; /* save current game status */
2142 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2143 int font_nr = FONT_TEXT_2;
2144 int max_word_len = 0;
2147 for (text_ptr = text; *text_ptr; text_ptr++)
2149 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2151 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2153 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2154 font_nr = FONT_LEVEL_NUMBER;
2160 if (game_status == GAME_MODE_PLAYING &&
2161 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2162 BlitScreenToBitmap_EM(backbuffer);
2164 /* disable deactivated drawing when quick-loading level tape recording */
2165 if (tape.playing && tape.deactivate_display)
2166 TapeDeactivateDisplayOff(TRUE);
2168 SetMouseCursor(CURSOR_DEFAULT);
2170 #if defined(NETWORK_AVALIABLE)
2171 /* pause network game while waiting for request to answer */
2172 if (options.network &&
2173 game_status == GAME_MODE_PLAYING &&
2174 req_state & REQUEST_WAIT_FOR_INPUT)
2175 SendToServer_PausePlaying();
2178 old_door_state = GetDoorState();
2180 /* simulate releasing mouse button over last gadget, if still pressed */
2182 HandleGadgets(-1, -1, 0);
2186 if (old_door_state & DOOR_OPEN_1)
2188 CloseDoor(DOOR_CLOSE_1);
2190 /* save old door content */
2191 BlitBitmap(bitmap_db_door, bitmap_db_door,
2192 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2193 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2196 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2198 /* clear door drawing field */
2199 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2201 /* force DOOR font on preview level */
2202 game_status = GAME_MODE_PSEUDO_DOOR;
2204 /* write text for request */
2205 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2207 char text_line[max_request_line_len + 1];
2213 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2216 if (!tc || tc == ' ')
2227 strncpy(text_line, text, tl);
2230 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2231 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2232 text_line, font_nr);
2234 text += tl + (tc == ' ' ? 1 : 0);
2237 game_status = last_game_status; /* restore current game status */
2239 if (req_state & REQ_ASK)
2241 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2242 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2244 else if (req_state & REQ_CONFIRM)
2246 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2248 else if (req_state & REQ_PLAYER)
2250 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2251 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2252 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2253 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2256 /* copy request gadgets to door backbuffer */
2257 BlitBitmap(drawto, bitmap_db_door,
2258 DX, DY, DXSIZE, DYSIZE,
2259 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2261 OpenDoor(DOOR_OPEN_1);
2263 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2265 SetDrawBackgroundMask(REDRAW_FIELD);
2270 if (game_status != GAME_MODE_MAIN)
2273 button_status = MB_RELEASED;
2275 request_gadget_id = -1;
2277 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2289 case EVENT_BUTTONPRESS:
2290 case EVENT_BUTTONRELEASE:
2291 case EVENT_MOTIONNOTIFY:
2293 if (event.type == EVENT_MOTIONNOTIFY)
2295 if (!PointerInWindow(window))
2296 continue; /* window and pointer are on different screens */
2301 motion_status = TRUE;
2302 mx = ((MotionEvent *) &event)->x;
2303 my = ((MotionEvent *) &event)->y;
2307 motion_status = FALSE;
2308 mx = ((ButtonEvent *) &event)->x;
2309 my = ((ButtonEvent *) &event)->y;
2310 if (event.type == EVENT_BUTTONPRESS)
2311 button_status = ((ButtonEvent *) &event)->button;
2313 button_status = MB_RELEASED;
2316 /* this sets 'request_gadget_id' */
2317 HandleGadgets(mx, my, button_status);
2319 switch(request_gadget_id)
2321 case TOOL_CTRL_ID_YES:
2324 case TOOL_CTRL_ID_NO:
2327 case TOOL_CTRL_ID_CONFIRM:
2328 result = TRUE | FALSE;
2331 case TOOL_CTRL_ID_PLAYER_1:
2334 case TOOL_CTRL_ID_PLAYER_2:
2337 case TOOL_CTRL_ID_PLAYER_3:
2340 case TOOL_CTRL_ID_PLAYER_4:
2351 case EVENT_KEYPRESS:
2352 switch(GetEventKey((KeyEvent *)&event, TRUE))
2365 if (req_state & REQ_PLAYER)
2369 case EVENT_KEYRELEASE:
2370 ClearPlayerAction();
2374 HandleOtherEvents(&event);
2378 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2380 int joy = AnyJoystick();
2382 if (joy & JOY_BUTTON_1)
2384 else if (joy & JOY_BUTTON_2)
2390 /* don't eat all CPU time */
2394 if (game_status != GAME_MODE_MAIN)
2399 if (!(req_state & REQ_STAY_OPEN))
2401 CloseDoor(DOOR_CLOSE_1);
2403 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2404 (req_state & REQ_REOPEN))
2405 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2410 SetDrawBackgroundMask(REDRAW_FIELD);
2412 #if defined(NETWORK_AVALIABLE)
2413 /* continue network game after request */
2414 if (options.network &&
2415 game_status == GAME_MODE_PLAYING &&
2416 req_state & REQUEST_WAIT_FOR_INPUT)
2417 SendToServer_ContinuePlaying();
2420 /* restore deactivated drawing when quick-loading level tape recording */
2421 if (tape.playing && tape.deactivate_display)
2422 TapeDeactivateDisplayOn();
2427 unsigned int OpenDoor(unsigned int door_state)
2429 if (door_state & DOOR_COPY_BACK)
2431 if (door_state & DOOR_OPEN_1)
2432 BlitBitmap(bitmap_db_door, bitmap_db_door,
2433 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2434 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2436 if (door_state & DOOR_OPEN_2)
2437 BlitBitmap(bitmap_db_door, bitmap_db_door,
2438 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2439 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2441 door_state &= ~DOOR_COPY_BACK;
2444 return MoveDoor(door_state);
2447 unsigned int CloseDoor(unsigned int door_state)
2449 unsigned int old_door_state = GetDoorState();
2451 if (!(door_state & DOOR_NO_COPY_BACK))
2453 if (old_door_state & DOOR_OPEN_1)
2454 BlitBitmap(backbuffer, bitmap_db_door,
2455 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2457 if (old_door_state & DOOR_OPEN_2)
2458 BlitBitmap(backbuffer, bitmap_db_door,
2459 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2461 door_state &= ~DOOR_NO_COPY_BACK;
2464 return MoveDoor(door_state);
2467 unsigned int GetDoorState()
2469 return MoveDoor(DOOR_GET_STATE);
2472 unsigned int SetDoorState(unsigned int door_state)
2474 return MoveDoor(door_state | DOOR_SET_STATE);
2477 unsigned int MoveDoor(unsigned int door_state)
2479 static int door1 = DOOR_OPEN_1;
2480 static int door2 = DOOR_CLOSE_2;
2481 unsigned long door_delay = 0;
2482 unsigned long door_delay_value;
2485 if (door_1.width < 0 || door_1.width > DXSIZE)
2486 door_1.width = DXSIZE;
2487 if (door_1.height < 0 || door_1.height > DYSIZE)
2488 door_1.height = DYSIZE;
2489 if (door_2.width < 0 || door_2.width > VXSIZE)
2490 door_2.width = VXSIZE;
2491 if (door_2.height < 0 || door_2.height > VYSIZE)
2492 door_2.height = VYSIZE;
2494 if (door_state == DOOR_GET_STATE)
2495 return(door1 | door2);
2497 if (door_state & DOOR_SET_STATE)
2499 if (door_state & DOOR_ACTION_1)
2500 door1 = door_state & DOOR_ACTION_1;
2501 if (door_state & DOOR_ACTION_2)
2502 door2 = door_state & DOOR_ACTION_2;
2504 return(door1 | door2);
2507 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2508 door_state &= ~DOOR_OPEN_1;
2509 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2510 door_state &= ~DOOR_CLOSE_1;
2511 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2512 door_state &= ~DOOR_OPEN_2;
2513 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2514 door_state &= ~DOOR_CLOSE_2;
2516 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2519 if (setup.quick_doors)
2521 stepsize = 20; /* must be choosen to always draw last frame */
2522 door_delay_value = 0;
2525 if (global.autoplay_leveldir)
2527 door_state |= DOOR_NO_DELAY;
2528 door_state &= ~DOOR_CLOSE_ALL;
2531 if (door_state & DOOR_ACTION)
2533 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2534 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2535 boolean door_1_done = (!handle_door_1);
2536 boolean door_2_done = (!handle_door_2);
2537 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2538 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2539 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2540 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2541 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2542 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2543 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2544 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2545 int door_skip = max_door_size - door_size;
2547 int end = door_size;
2549 int end = (door_state & DOOR_ACTION_1 &&
2550 door_1.anim_mode & ANIM_VERTICAL ? DYSIZE : DXSIZE);
2553 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2555 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2559 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2561 /* opening door sound has priority over simultaneously closing door */
2562 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2563 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2564 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2565 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2568 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2571 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2572 GC gc = bitmap->stored_clip_gc;
2574 if (door_state & DOOR_ACTION_1)
2576 int a = MIN(x * door_1.step_offset, end);
2577 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2578 int i = p + door_skip;
2580 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2582 BlitBitmap(bitmap_db_door, drawto,
2583 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2584 DXSIZE, DYSIZE, DX, DY);
2588 BlitBitmap(bitmap_db_door, drawto,
2589 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2590 DXSIZE, DYSIZE - p / 2, DX, DY);
2592 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2595 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2597 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2598 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2599 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2600 int dst2_x = DX, dst2_y = DY;
2601 int width = i, height = DYSIZE;
2603 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2604 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2607 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2608 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2611 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2613 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2614 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2615 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2616 int dst2_x = DX, dst2_y = DY;
2617 int width = DXSIZE, height = i;
2619 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2620 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2623 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2624 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2627 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2629 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2631 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2632 BlitBitmapMasked(bitmap, drawto,
2633 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2634 DX + DXSIZE - i, DY + j);
2635 BlitBitmapMasked(bitmap, drawto,
2636 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2637 DX + DXSIZE - i, DY + 140 + j);
2638 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2639 DY - (DOOR_GFX_PAGEY1 + j));
2640 BlitBitmapMasked(bitmap, drawto,
2641 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2643 BlitBitmapMasked(bitmap, drawto,
2644 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2647 BlitBitmapMasked(bitmap, drawto,
2648 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2650 BlitBitmapMasked(bitmap, drawto,
2651 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2653 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2654 BlitBitmapMasked(bitmap, drawto,
2655 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2656 DX + DXSIZE - i, DY + 77 + j);
2657 BlitBitmapMasked(bitmap, drawto,
2658 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2659 DX + DXSIZE - i, DY + 203 + j);
2662 redraw_mask |= REDRAW_DOOR_1;
2663 door_1_done = (a == end);
2666 if (door_state & DOOR_ACTION_2)
2668 int a = MIN(x * door_2.step_offset, door_size_2);
2669 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2670 int i = p + door_skip;
2672 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2674 BlitBitmap(bitmap_db_door, drawto,
2675 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2676 VXSIZE, VYSIZE, VX, VY);
2678 else if (x <= VYSIZE)
2680 BlitBitmap(bitmap_db_door, drawto,
2681 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2682 VXSIZE, VYSIZE - p / 2, VX, VY);
2684 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2687 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2689 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2690 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2691 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2692 int dst2_x = VX, dst2_y = VY;
2693 int width = i, height = VYSIZE;
2695 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2696 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2699 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2700 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2703 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2705 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2706 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2707 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2708 int dst2_x = VX, dst2_y = VY;
2709 int width = VXSIZE, height = i;
2711 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2712 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2715 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2716 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2719 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2721 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2723 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2724 BlitBitmapMasked(bitmap, drawto,
2725 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2726 VX + VXSIZE - i, VY + j);
2727 SetClipOrigin(bitmap, gc,
2728 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2729 BlitBitmapMasked(bitmap, drawto,
2730 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2733 BlitBitmapMasked(bitmap, drawto,
2734 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2735 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2736 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2737 BlitBitmapMasked(bitmap, drawto,
2738 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2740 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2743 redraw_mask |= REDRAW_DOOR_2;
2744 door_2_done = (a == VXSIZE);
2749 if (game_status == GAME_MODE_MAIN)
2752 if (!(door_state & DOOR_NO_DELAY))
2753 WaitUntilDelayReached(&door_delay, door_delay_value);
2757 if (door_state & DOOR_ACTION_1)
2758 door1 = door_state & DOOR_ACTION_1;
2759 if (door_state & DOOR_ACTION_2)
2760 door2 = door_state & DOOR_ACTION_2;
2762 return (door1 | door2);
2765 void DrawSpecialEditorDoor()
2767 /* draw bigger toolbox window */
2768 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2769 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2771 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2772 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2775 redraw_mask |= REDRAW_ALL;
2778 void UndrawSpecialEditorDoor()
2780 /* draw normal tape recorder window */
2781 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2782 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2785 redraw_mask |= REDRAW_ALL;
2789 /* ---------- new tool button stuff ---------------------------------------- */
2791 /* graphic position values for tool buttons */
2792 #define TOOL_BUTTON_YES_XPOS 2
2793 #define TOOL_BUTTON_YES_YPOS 250
2794 #define TOOL_BUTTON_YES_GFX_YPOS 0
2795 #define TOOL_BUTTON_YES_XSIZE 46
2796 #define TOOL_BUTTON_YES_YSIZE 28
2797 #define TOOL_BUTTON_NO_XPOS 52
2798 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2799 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2800 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2801 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2802 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2803 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2804 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2805 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2806 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2807 #define TOOL_BUTTON_PLAYER_XSIZE 30
2808 #define TOOL_BUTTON_PLAYER_YSIZE 30
2809 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2810 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2811 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2812 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2813 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2814 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2815 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2816 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2817 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2818 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2819 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2820 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2821 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2822 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2823 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2824 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2825 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2826 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2827 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2828 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2837 } toolbutton_info[NUM_TOOL_BUTTONS] =
2840 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2841 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2842 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2847 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2848 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2849 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2854 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2855 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2856 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2857 TOOL_CTRL_ID_CONFIRM,
2861 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2862 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2863 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2864 TOOL_CTRL_ID_PLAYER_1,
2868 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2869 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2870 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2871 TOOL_CTRL_ID_PLAYER_2,
2875 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2876 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2877 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2878 TOOL_CTRL_ID_PLAYER_3,
2882 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2883 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2884 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2885 TOOL_CTRL_ID_PLAYER_4,
2890 void CreateToolButtons()
2894 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2896 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2897 Bitmap *deco_bitmap = None;
2898 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2899 struct GadgetInfo *gi;
2900 unsigned long event_mask;
2901 int gd_xoffset, gd_yoffset;
2902 int gd_x1, gd_x2, gd_y;
2905 event_mask = GD_EVENT_RELEASED;
2907 gd_xoffset = toolbutton_info[i].xpos;
2908 gd_yoffset = toolbutton_info[i].ypos;
2909 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2910 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2911 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2913 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2915 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2917 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2918 &deco_bitmap, &deco_x, &deco_y);
2919 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2920 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2923 gi = CreateGadget(GDI_CUSTOM_ID, id,
2924 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2925 GDI_X, DX + toolbutton_info[i].x,
2926 GDI_Y, DY + toolbutton_info[i].y,
2927 GDI_WIDTH, toolbutton_info[i].width,
2928 GDI_HEIGHT, toolbutton_info[i].height,
2929 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2930 GDI_STATE, GD_BUTTON_UNPRESSED,
2931 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2932 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2933 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2934 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2935 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2936 GDI_DECORATION_SHIFTING, 1, 1,
2937 GDI_EVENT_MASK, event_mask,
2938 GDI_CALLBACK_ACTION, HandleToolButtons,
2942 Error(ERR_EXIT, "cannot create gadget");
2944 tool_gadget[id] = gi;
2948 void FreeToolButtons()
2952 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2953 FreeGadget(tool_gadget[i]);
2956 static void UnmapToolButtons()
2960 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2961 UnmapGadget(tool_gadget[i]);
2964 static void HandleToolButtons(struct GadgetInfo *gi)
2966 request_gadget_id = gi->custom_id;
2969 static struct Mapping_EM_to_RND_object
2972 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
2973 boolean is_backside; /* backside of moving element */
2979 em_object_mapping_list[] =
2982 Xblank, TRUE, FALSE,
2986 Yacid_splash_eB, FALSE, FALSE,
2987 EL_ACID_SPLASH_RIGHT, -1, -1
2990 Yacid_splash_wB, FALSE, FALSE,
2991 EL_ACID_SPLASH_LEFT, -1, -1
2994 #ifdef EM_ENGINE_BAD_ROLL
2996 Xstone_force_e, FALSE, FALSE,
2997 EL_ROCK, -1, MV_BIT_RIGHT
3000 Xstone_force_w, FALSE, FALSE,
3001 EL_ROCK, -1, MV_BIT_LEFT
3004 Xnut_force_e, FALSE, FALSE,
3005 EL_NUT, -1, MV_BIT_RIGHT
3008 Xnut_force_w, FALSE, FALSE,
3009 EL_NUT, -1, MV_BIT_LEFT
3012 Xspring_force_e, FALSE, FALSE,
3013 EL_SPRING, -1, MV_BIT_RIGHT
3016 Xspring_force_w, FALSE, FALSE,
3017 EL_SPRING, -1, MV_BIT_LEFT
3020 Xemerald_force_e, FALSE, FALSE,
3021 EL_EMERALD, -1, MV_BIT_RIGHT
3024 Xemerald_force_w, FALSE, FALSE,
3025 EL_EMERALD, -1, MV_BIT_LEFT
3028 Xdiamond_force_e, FALSE, FALSE,
3029 EL_DIAMOND, -1, MV_BIT_RIGHT
3032 Xdiamond_force_w, FALSE, FALSE,
3033 EL_DIAMOND, -1, MV_BIT_LEFT
3036 Xbomb_force_e, FALSE, FALSE,
3037 EL_BOMB, -1, MV_BIT_RIGHT
3040 Xbomb_force_w, FALSE, FALSE,
3041 EL_BOMB, -1, MV_BIT_LEFT
3043 #endif /* EM_ENGINE_BAD_ROLL */
3046 Xstone, TRUE, FALSE,
3050 Xstone_pause, FALSE, FALSE,
3054 Xstone_fall, FALSE, FALSE,
3058 Ystone_s, FALSE, FALSE,
3059 EL_ROCK, ACTION_FALLING, -1
3062 Ystone_sB, FALSE, TRUE,
3063 EL_ROCK, ACTION_FALLING, -1
3066 Ystone_e, FALSE, FALSE,
3067 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3070 Ystone_eB, FALSE, TRUE,
3071 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3074 Ystone_w, FALSE, FALSE,
3075 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3078 Ystone_wB, FALSE, TRUE,
3079 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3086 Xnut_pause, FALSE, FALSE,
3090 Xnut_fall, FALSE, FALSE,
3094 Ynut_s, FALSE, FALSE,
3095 EL_NUT, ACTION_FALLING, -1
3098 Ynut_sB, FALSE, TRUE,
3099 EL_NUT, ACTION_FALLING, -1
3102 Ynut_e, FALSE, FALSE,
3103 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3106 Ynut_eB, FALSE, TRUE,
3107 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3110 Ynut_w, FALSE, FALSE,
3111 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3114 Ynut_wB, FALSE, TRUE,
3115 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3118 Xbug_n, TRUE, FALSE,
3122 Xbug_e, TRUE, FALSE,
3123 EL_BUG_RIGHT, -1, -1
3126 Xbug_s, TRUE, FALSE,
3130 Xbug_w, TRUE, FALSE,
3134 Xbug_gon, FALSE, FALSE,
3138 Xbug_goe, FALSE, FALSE,
3139 EL_BUG_RIGHT, -1, -1
3142 Xbug_gos, FALSE, FALSE,
3146 Xbug_gow, FALSE, FALSE,
3150 Ybug_n, FALSE, FALSE,
3151 EL_BUG, ACTION_MOVING, MV_BIT_UP
3154 Ybug_nB, FALSE, TRUE,
3155 EL_BUG, ACTION_MOVING, MV_BIT_UP
3158 Ybug_e, FALSE, FALSE,
3159 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3162 Ybug_eB, FALSE, TRUE,
3163 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3166 Ybug_s, FALSE, FALSE,
3167 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3170 Ybug_sB, FALSE, TRUE,
3171 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3174 Ybug_w, FALSE, FALSE,
3175 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3178 Ybug_wB, FALSE, TRUE,
3179 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3182 Ybug_w_n, FALSE, FALSE,
3183 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3186 Ybug_n_e, FALSE, FALSE,
3187 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3190 Ybug_e_s, FALSE, FALSE,
3191 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3194 Ybug_s_w, FALSE, FALSE,
3195 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3198 Ybug_e_n, FALSE, FALSE,
3199 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3202 Ybug_s_e, FALSE, FALSE,
3203 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3206 Ybug_w_s, FALSE, FALSE,
3207 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3210 Ybug_n_w, FALSE, FALSE,
3211 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3214 Ybug_stone, FALSE, FALSE,
3215 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3218 Ybug_spring, FALSE, FALSE,
3219 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3222 Xtank_n, TRUE, FALSE,
3223 EL_SPACESHIP_UP, -1, -1
3226 Xtank_e, TRUE, FALSE,
3227 EL_SPACESHIP_RIGHT, -1, -1
3230 Xtank_s, TRUE, FALSE,
3231 EL_SPACESHIP_DOWN, -1, -1
3234 Xtank_w, TRUE, FALSE,
3235 EL_SPACESHIP_LEFT, -1, -1
3238 Xtank_gon, FALSE, FALSE,
3239 EL_SPACESHIP_UP, -1, -1
3242 Xtank_goe, FALSE, FALSE,
3243 EL_SPACESHIP_RIGHT, -1, -1
3246 Xtank_gos, FALSE, FALSE,
3247 EL_SPACESHIP_DOWN, -1, -1
3250 Xtank_gow, FALSE, FALSE,
3251 EL_SPACESHIP_LEFT, -1, -1
3254 Ytank_n, FALSE, FALSE,
3255 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3258 Ytank_nB, FALSE, TRUE,
3259 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3262 Ytank_e, FALSE, FALSE,
3263 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3266 Ytank_eB, FALSE, TRUE,
3267 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3270 Ytank_s, FALSE, FALSE,
3271 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3274 Ytank_sB, FALSE, TRUE,
3275 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3278 Ytank_w, FALSE, FALSE,
3279 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3282 Ytank_wB, FALSE, TRUE,
3283 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3286 Ytank_w_n, FALSE, FALSE,
3287 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3290 Ytank_n_e, FALSE, FALSE,
3291 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3294 Ytank_e_s, FALSE, FALSE,
3295 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3298 Ytank_s_w, FALSE, FALSE,
3299 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3302 Ytank_e_n, FALSE, FALSE,
3303 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3306 Ytank_s_e, FALSE, FALSE,
3307 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3310 Ytank_w_s, FALSE, FALSE,
3311 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3314 Ytank_n_w, FALSE, FALSE,
3315 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3318 Ytank_stone, FALSE, FALSE,
3319 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3322 Ytank_spring, FALSE, FALSE,
3323 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3326 Xandroid, TRUE, FALSE,
3327 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3330 Xandroid_1_n, FALSE, FALSE,
3331 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3334 Xandroid_2_n, FALSE, FALSE,
3335 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3338 Xandroid_1_e, FALSE, FALSE,
3339 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3342 Xandroid_2_e, FALSE, FALSE,
3343 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3346 Xandroid_1_w, FALSE, FALSE,
3347 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3350 Xandroid_2_w, FALSE, FALSE,
3351 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3354 Xandroid_1_s, FALSE, FALSE,
3355 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3358 Xandroid_2_s, FALSE, FALSE,
3359 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3362 Yandroid_n, FALSE, FALSE,
3363 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3366 Yandroid_nB, FALSE, TRUE,
3367 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3370 Yandroid_ne, FALSE, FALSE,
3371 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3374 Yandroid_neB, FALSE, TRUE,
3375 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3378 Yandroid_e, FALSE, FALSE,
3379 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3382 Yandroid_eB, FALSE, TRUE,
3383 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3386 Yandroid_se, FALSE, FALSE,
3387 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3390 Yandroid_seB, FALSE, TRUE,
3391 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3394 Yandroid_s, FALSE, FALSE,
3395 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3398 Yandroid_sB, FALSE, TRUE,
3399 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3402 Yandroid_sw, FALSE, FALSE,
3403 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3406 Yandroid_swB, FALSE, TRUE,
3407 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3410 Yandroid_w, FALSE, FALSE,
3411 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3414 Yandroid_wB, FALSE, TRUE,
3415 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3418 Yandroid_nw, FALSE, FALSE,
3419 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3422 Yandroid_nwB, FALSE, TRUE,
3423 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3426 Xspring, TRUE, FALSE,
3430 Xspring_pause, FALSE, FALSE,
3434 Xspring_e, FALSE, FALSE,
3438 Xspring_w, FALSE, FALSE,
3442 Xspring_fall, FALSE, FALSE,
3446 Yspring_s, FALSE, FALSE,
3447 EL_SPRING, ACTION_FALLING, -1
3450 Yspring_sB, FALSE, TRUE,
3451 EL_SPRING, ACTION_FALLING, -1
3454 Yspring_e, FALSE, FALSE,
3455 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3458 Yspring_eB, FALSE, TRUE,
3459 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3462 Yspring_w, FALSE, FALSE,
3463 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3466 Yspring_wB, FALSE, TRUE,
3467 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3470 Yspring_kill_e, FALSE, FALSE,
3471 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3474 Yspring_kill_eB, FALSE, TRUE,
3475 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3478 Yspring_kill_w, FALSE, FALSE,
3479 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3482 Yspring_kill_wB, FALSE, TRUE,
3483 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3486 Xeater_n, TRUE, FALSE,
3487 EL_YAMYAM_UP, -1, -1
3490 Xeater_e, TRUE, FALSE,
3491 EL_YAMYAM_RIGHT, -1, -1
3494 Xeater_w, TRUE, FALSE,
3495 EL_YAMYAM_LEFT, -1, -1
3498 Xeater_s, TRUE, FALSE,
3499 EL_YAMYAM_DOWN, -1, -1
3502 Yeater_n, FALSE, FALSE,
3503 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3506 Yeater_nB, FALSE, TRUE,
3507 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3510 Yeater_e, FALSE, FALSE,
3511 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3514 Yeater_eB, FALSE, TRUE,
3515 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3518 Yeater_s, FALSE, FALSE,
3519 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3522 Yeater_sB, FALSE, TRUE,
3523 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3526 Yeater_w, FALSE, FALSE,
3527 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3530 Yeater_wB, FALSE, TRUE,
3531 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3534 Yeater_stone, FALSE, FALSE,
3535 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3538 Yeater_spring, FALSE, FALSE,
3539 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3542 Xalien, TRUE, FALSE,
3546 Xalien_pause, FALSE, FALSE,
3550 Yalien_n, FALSE, FALSE,
3551 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3554 Yalien_nB, FALSE, TRUE,
3555 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3558 Yalien_e, FALSE, FALSE,
3559 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3562 Yalien_eB, FALSE, TRUE,
3563 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3566 Yalien_s, FALSE, FALSE,
3567 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3570 Yalien_sB, FALSE, TRUE,
3571 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3574 Yalien_w, FALSE, FALSE,
3575 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3578 Yalien_wB, FALSE, TRUE,
3579 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3582 Yalien_stone, FALSE, FALSE,
3583 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3586 Yalien_spring, FALSE, FALSE,
3587 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3590 Xemerald, TRUE, FALSE,
3594 Xemerald_pause, FALSE, FALSE,
3598 Xemerald_fall, FALSE, FALSE,
3602 Xemerald_shine, FALSE, FALSE,
3603 EL_EMERALD, ACTION_TWINKLING, -1
3606 Yemerald_s, FALSE, FALSE,
3607 EL_EMERALD, ACTION_FALLING, -1
3610 Yemerald_sB, FALSE, TRUE,
3611 EL_EMERALD, ACTION_FALLING, -1
3614 Yemerald_e, FALSE, FALSE,
3615 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3618 Yemerald_eB, FALSE, TRUE,
3619 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3622 Yemerald_w, FALSE, FALSE,
3623 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3626 Yemerald_wB, FALSE, TRUE,
3627 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3630 Yemerald_eat, FALSE, FALSE,
3631 EL_EMERALD, ACTION_COLLECTING, -1
3634 Yemerald_stone, FALSE, FALSE,
3635 EL_NUT, ACTION_BREAKING, -1
3638 Xdiamond, TRUE, FALSE,
3642 Xdiamond_pause, FALSE, FALSE,
3646 Xdiamond_fall, FALSE, FALSE,
3650 Xdiamond_shine, FALSE, FALSE,
3651 EL_DIAMOND, ACTION_TWINKLING, -1
3654 Ydiamond_s, FALSE, FALSE,
3655 EL_DIAMOND, ACTION_FALLING, -1
3658 Ydiamond_sB, FALSE, TRUE,
3659 EL_DIAMOND, ACTION_FALLING, -1
3662 Ydiamond_e, FALSE, FALSE,
3663 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3666 Ydiamond_eB, FALSE, TRUE,
3667 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3670 Ydiamond_w, FALSE, FALSE,
3671 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3674 Ydiamond_wB, FALSE, TRUE,
3675 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3678 Ydiamond_eat, FALSE, FALSE,
3679 EL_DIAMOND, ACTION_COLLECTING, -1
3682 Ydiamond_stone, FALSE, FALSE,
3683 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3686 Xdrip_fall, TRUE, FALSE,
3687 EL_AMOEBA_DROP, -1, -1
3690 Xdrip_stretch, FALSE, FALSE,
3691 EL_AMOEBA_DROP, ACTION_FALLING, -1
3694 Xdrip_stretchB, FALSE, TRUE,
3695 EL_AMOEBA_DROP, ACTION_FALLING, -1
3698 Xdrip_eat, FALSE, FALSE,
3699 EL_AMOEBA_DROP, ACTION_GROWING, -1
3702 Ydrip_s1, FALSE, FALSE,
3703 EL_AMOEBA_DROP, ACTION_FALLING, -1
3706 Ydrip_s1B, FALSE, TRUE,
3707 EL_AMOEBA_DROP, ACTION_FALLING, -1
3710 Ydrip_s2, FALSE, FALSE,
3711 EL_AMOEBA_DROP, ACTION_FALLING, -1
3714 Ydrip_s2B, FALSE, TRUE,
3715 EL_AMOEBA_DROP, ACTION_FALLING, -1
3722 Xbomb_pause, FALSE, FALSE,
3726 Xbomb_fall, FALSE, FALSE,
3730 Ybomb_s, FALSE, FALSE,
3731 EL_BOMB, ACTION_FALLING, -1
3734 Ybomb_sB, FALSE, TRUE,
3735 EL_BOMB, ACTION_FALLING, -1
3738 Ybomb_e, FALSE, FALSE,
3739 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3742 Ybomb_eB, FALSE, TRUE,
3743 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3746 Ybomb_w, FALSE, FALSE,
3747 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3750 Ybomb_wB, FALSE, TRUE,
3751 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3754 Ybomb_eat, FALSE, FALSE,
3755 EL_BOMB, ACTION_ACTIVATING, -1
3758 Xballoon, TRUE, FALSE,
3762 Yballoon_n, FALSE, FALSE,
3763 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3766 Yballoon_nB, FALSE, TRUE,
3767 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3770 Yballoon_e, FALSE, FALSE,
3771 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3774 Yballoon_eB, FALSE, TRUE,
3775 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3778 Yballoon_s, FALSE, FALSE,
3779 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3782 Yballoon_sB, FALSE, TRUE,
3783 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3786 Yballoon_w, FALSE, FALSE,
3787 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3790 Yballoon_wB, FALSE, TRUE,
3791 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3794 Xgrass, TRUE, FALSE,
3795 EL_EMC_GRASS, -1, -1
3798 Ygrass_nB, FALSE, FALSE,
3799 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3802 Ygrass_eB, FALSE, FALSE,
3803 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3806 Ygrass_sB, FALSE, FALSE,
3807 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3810 Ygrass_wB, FALSE, FALSE,
3811 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3818 Ydirt_nB, FALSE, FALSE,
3819 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3822 Ydirt_eB, FALSE, FALSE,
3823 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3826 Ydirt_sB, FALSE, FALSE,
3827 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3830 Ydirt_wB, FALSE, FALSE,
3831 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3834 Xacid_ne, TRUE, FALSE,
3835 EL_ACID_POOL_TOPRIGHT, -1, -1
3838 Xacid_se, TRUE, FALSE,
3839 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3842 Xacid_s, TRUE, FALSE,
3843 EL_ACID_POOL_BOTTOM, -1, -1
3846 Xacid_sw, TRUE, FALSE,
3847 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3850 Xacid_nw, TRUE, FALSE,
3851 EL_ACID_POOL_TOPLEFT, -1, -1
3854 Xacid_1, TRUE, FALSE,
3858 Xacid_2, FALSE, FALSE,
3862 Xacid_3, FALSE, FALSE,
3866 Xacid_4, FALSE, FALSE,
3870 Xacid_5, FALSE, FALSE,
3874 Xacid_6, FALSE, FALSE,
3878 Xacid_7, FALSE, FALSE,
3882 Xacid_8, FALSE, FALSE,
3886 Xball_1, TRUE, FALSE,
3887 EL_EMC_MAGIC_BALL, -1, -1
3890 Xball_1B, FALSE, FALSE,
3891 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3894 Xball_2, FALSE, FALSE,
3895 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3898 Xball_2B, FALSE, FALSE,
3899 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3902 Yball_eat, FALSE, FALSE,
3903 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
3906 Ykey_1_eat, FALSE, FALSE,
3907 EL_EM_KEY_1, ACTION_COLLECTING, -1
3910 Ykey_2_eat, FALSE, FALSE,
3911 EL_EM_KEY_2, ACTION_COLLECTING, -1
3914 Ykey_3_eat, FALSE, FALSE,
3915 EL_EM_KEY_3, ACTION_COLLECTING, -1
3918 Ykey_4_eat, FALSE, FALSE,
3919 EL_EM_KEY_4, ACTION_COLLECTING, -1
3922 Ykey_5_eat, FALSE, FALSE,
3923 EL_EMC_KEY_5, ACTION_COLLECTING, -1
3926 Ykey_6_eat, FALSE, FALSE,
3927 EL_EMC_KEY_6, ACTION_COLLECTING, -1
3930 Ykey_7_eat, FALSE, FALSE,
3931 EL_EMC_KEY_7, ACTION_COLLECTING, -1
3934 Ykey_8_eat, FALSE, FALSE,
3935 EL_EMC_KEY_8, ACTION_COLLECTING, -1
3938 Ylenses_eat, FALSE, FALSE,
3939 EL_EMC_LENSES, ACTION_COLLECTING, -1
3942 Ymagnify_eat, FALSE, FALSE,
3943 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
3946 Ygrass_eat, FALSE, FALSE,
3947 EL_EMC_GRASS, ACTION_SNAPPING, -1
3950 Ydirt_eat, FALSE, FALSE,
3951 EL_SAND, ACTION_SNAPPING, -1
3954 Xgrow_ns, TRUE, FALSE,
3955 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
3958 Ygrow_ns_eat, FALSE, FALSE,
3959 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
3962 Xgrow_ew, TRUE, FALSE,
3963 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
3966 Ygrow_ew_eat, FALSE, FALSE,
3967 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
3970 Xwonderwall, TRUE, FALSE,
3971 EL_MAGIC_WALL, -1, -1
3974 XwonderwallB, FALSE, FALSE,
3975 EL_MAGIC_WALL, ACTION_ACTIVE, -1
3978 Xamoeba_1, TRUE, FALSE,
3979 EL_AMOEBA_DRY, ACTION_OTHER, -1
3982 Xamoeba_2, FALSE, FALSE,
3983 EL_AMOEBA_DRY, ACTION_OTHER, -1
3986 Xamoeba_3, FALSE, FALSE,
3987 EL_AMOEBA_DRY, ACTION_OTHER, -1
3990 Xamoeba_4, FALSE, FALSE,
3991 EL_AMOEBA_DRY, ACTION_OTHER, -1
3994 Xamoeba_5, TRUE, FALSE,
3995 EL_AMOEBA_WET, ACTION_OTHER, -1
3998 Xamoeba_6, FALSE, FALSE,
3999 EL_AMOEBA_WET, ACTION_OTHER, -1
4002 Xamoeba_7, FALSE, FALSE,
4003 EL_AMOEBA_WET, ACTION_OTHER, -1
4006 Xamoeba_8, FALSE, FALSE,
4007 EL_AMOEBA_WET, ACTION_OTHER, -1
4010 Xdoor_1, TRUE, FALSE,
4011 EL_EM_GATE_1, -1, -1
4014 Xdoor_2, TRUE, FALSE,
4015 EL_EM_GATE_2, -1, -1
4018 Xdoor_3, TRUE, FALSE,
4019 EL_EM_GATE_3, -1, -1
4022 Xdoor_4, TRUE, FALSE,
4023 EL_EM_GATE_4, -1, -1
4026 Xdoor_5, TRUE, FALSE,
4027 EL_EMC_GATE_5, -1, -1
4030 Xdoor_6, TRUE, FALSE,
4031 EL_EMC_GATE_6, -1, -1
4034 Xdoor_7, TRUE, FALSE,
4035 EL_EMC_GATE_7, -1, -1
4038 Xdoor_8, TRUE, FALSE,
4039 EL_EMC_GATE_8, -1, -1
4042 Xkey_1, TRUE, FALSE,
4046 Xkey_2, TRUE, FALSE,
4050 Xkey_3, TRUE, FALSE,
4054 Xkey_4, TRUE, FALSE,
4058 Xkey_5, TRUE, FALSE,
4059 EL_EMC_KEY_5, -1, -1
4062 Xkey_6, TRUE, FALSE,
4063 EL_EMC_KEY_6, -1, -1
4066 Xkey_7, TRUE, FALSE,
4067 EL_EMC_KEY_7, -1, -1
4070 Xkey_8, TRUE, FALSE,
4071 EL_EMC_KEY_8, -1, -1
4074 Xwind_n, TRUE, FALSE,
4075 EL_BALLOON_SWITCH_UP, -1, -1
4078 Xwind_e, TRUE, FALSE,
4079 EL_BALLOON_SWITCH_RIGHT, -1, -1
4082 Xwind_s, TRUE, FALSE,
4083 EL_BALLOON_SWITCH_DOWN, -1, -1
4086 Xwind_w, TRUE, FALSE,
4087 EL_BALLOON_SWITCH_LEFT, -1, -1
4090 Xwind_nesw, TRUE, FALSE,
4091 EL_BALLOON_SWITCH_ANY, -1, -1
4094 Xwind_stop, TRUE, FALSE,
4095 EL_BALLOON_SWITCH_NONE, -1, -1
4099 EL_EXIT_CLOSED, -1, -1
4102 Xexit_1, TRUE, FALSE,
4103 EL_EXIT_OPEN, -1, -1
4106 Xexit_2, FALSE, FALSE,
4107 EL_EXIT_OPEN, -1, -1
4110 Xexit_3, FALSE, FALSE,
4111 EL_EXIT_OPEN, -1, -1
4114 Xdynamite, TRUE, FALSE,
4115 EL_EM_DYNAMITE, -1, -1
4118 Ydynamite_eat, FALSE, FALSE,
4119 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4122 Xdynamite_1, TRUE, FALSE,
4123 EL_EM_DYNAMITE_ACTIVE, -1, -1
4126 Xdynamite_2, FALSE, FALSE,
4127 EL_EM_DYNAMITE_ACTIVE, -1, -1
4130 Xdynamite_3, FALSE, FALSE,
4131 EL_EM_DYNAMITE_ACTIVE, -1, -1
4134 Xdynamite_4, FALSE, FALSE,
4135 EL_EM_DYNAMITE_ACTIVE, -1, -1
4138 Xbumper, TRUE, FALSE,
4139 EL_EMC_SPRING_BUMPER, -1, -1
4142 XbumperB, FALSE, FALSE,
4143 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4146 Xwheel, TRUE, FALSE,
4147 EL_ROBOT_WHEEL, -1, -1
4150 XwheelB, FALSE, FALSE,
4151 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4154 Xswitch, TRUE, FALSE,
4155 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4158 XswitchB, FALSE, FALSE,
4159 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4163 EL_QUICKSAND_EMPTY, -1, -1
4166 Xsand_stone, TRUE, FALSE,
4167 EL_QUICKSAND_FULL, -1, -1
4170 Xsand_stonein_1, FALSE, FALSE,
4171 EL_ROCK, ACTION_FILLING, -1
4174 Xsand_stonein_2, FALSE, FALSE,
4175 EL_ROCK, ACTION_FILLING, -1
4178 Xsand_stonein_3, FALSE, FALSE,
4179 EL_ROCK, ACTION_FILLING, -1
4182 Xsand_stonein_4, FALSE, FALSE,
4183 EL_ROCK, ACTION_FILLING, -1
4186 Xsand_stonesand_1, FALSE, FALSE,
4187 EL_QUICKSAND_FULL, -1, -1
4190 Xsand_stonesand_2, FALSE, FALSE,
4191 EL_QUICKSAND_FULL, -1, -1
4194 Xsand_stonesand_3, FALSE, FALSE,
4195 EL_QUICKSAND_FULL, -1, -1
4198 Xsand_stonesand_4, FALSE, FALSE,
4199 EL_QUICKSAND_FULL, -1, -1
4202 Xsand_stoneout_1, FALSE, FALSE,
4203 EL_ROCK, ACTION_EMPTYING, -1
4206 Xsand_stoneout_2, FALSE, FALSE,
4207 EL_ROCK, ACTION_EMPTYING, -1
4210 Xsand_sandstone_1, FALSE, FALSE,
4211 EL_QUICKSAND_FULL, -1, -1
4214 Xsand_sandstone_2, FALSE, FALSE,
4215 EL_QUICKSAND_FULL, -1, -1
4218 Xsand_sandstone_3, FALSE, FALSE,
4219 EL_QUICKSAND_FULL, -1, -1
4222 Xsand_sandstone_4, FALSE, FALSE,
4223 EL_QUICKSAND_FULL, -1, -1
4226 Xplant, TRUE, FALSE,
4227 EL_EMC_PLANT, -1, -1
4230 Yplant, FALSE, FALSE,
4231 EL_EMC_PLANT, -1, -1
4234 Xlenses, TRUE, FALSE,
4235 EL_EMC_LENSES, -1, -1
4238 Xmagnify, TRUE, FALSE,
4239 EL_EMC_MAGNIFIER, -1, -1
4242 Xdripper, TRUE, FALSE,
4243 EL_EMC_DRIPPER, -1, -1
4246 XdripperB, FALSE, FALSE,
4247 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4250 Xfake_blank, TRUE, FALSE,
4251 EL_INVISIBLE_WALL, -1, -1
4254 Xfake_blankB, FALSE, FALSE,
4255 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4258 Xfake_grass, TRUE, FALSE,
4259 EL_EMC_FAKE_GRASS, -1, -1
4262 Xfake_grassB, FALSE, FALSE,
4263 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4266 Xfake_door_1, TRUE, FALSE,
4267 EL_EM_GATE_1_GRAY, -1, -1
4270 Xfake_door_2, TRUE, FALSE,
4271 EL_EM_GATE_2_GRAY, -1, -1
4274 Xfake_door_3, TRUE, FALSE,
4275 EL_EM_GATE_3_GRAY, -1, -1
4278 Xfake_door_4, TRUE, FALSE,
4279 EL_EM_GATE_4_GRAY, -1, -1
4282 Xfake_door_5, TRUE, FALSE,
4283 EL_EMC_GATE_5_GRAY, -1, -1
4286 Xfake_door_6, TRUE, FALSE,
4287 EL_EMC_GATE_6_GRAY, -1, -1
4290 Xfake_door_7, TRUE, FALSE,
4291 EL_EMC_GATE_7_GRAY, -1, -1
4294 Xfake_door_8, TRUE, FALSE,
4295 EL_EMC_GATE_8_GRAY, -1, -1
4298 Xfake_acid_1, TRUE, FALSE,
4299 EL_EMC_FAKE_ACID, -1, -1
4302 Xfake_acid_2, FALSE, FALSE,
4303 EL_EMC_FAKE_ACID, -1, -1
4306 Xfake_acid_3, FALSE, FALSE,
4307 EL_EMC_FAKE_ACID, -1, -1
4310 Xfake_acid_4, FALSE, FALSE,
4311 EL_EMC_FAKE_ACID, -1, -1
4314 Xfake_acid_5, FALSE, FALSE,
4315 EL_EMC_FAKE_ACID, -1, -1
4318 Xfake_acid_6, FALSE, FALSE,
4319 EL_EMC_FAKE_ACID, -1, -1
4322 Xfake_acid_7, FALSE, FALSE,
4323 EL_EMC_FAKE_ACID, -1, -1
4326 Xfake_acid_8, FALSE, FALSE,
4327 EL_EMC_FAKE_ACID, -1, -1
4330 Xsteel_1, TRUE, FALSE,
4331 EL_STEELWALL, -1, -1
4334 Xsteel_2, TRUE, FALSE,
4335 EL_EMC_STEELWALL_2, -1, -1
4338 Xsteel_3, TRUE, FALSE,
4339 EL_EMC_STEELWALL_3, -1, -1
4342 Xsteel_4, TRUE, FALSE,
4343 EL_EMC_STEELWALL_4, -1, -1
4346 Xwall_1, TRUE, FALSE,
4350 Xwall_2, TRUE, FALSE,
4351 EL_EMC_WALL_14, -1, -1
4354 Xwall_3, TRUE, FALSE,
4355 EL_EMC_WALL_15, -1, -1
4358 Xwall_4, TRUE, FALSE,
4359 EL_EMC_WALL_16, -1, -1
4362 Xround_wall_1, TRUE, FALSE,
4363 EL_WALL_SLIPPERY, -1, -1
4366 Xround_wall_2, TRUE, FALSE,
4367 EL_EMC_WALL_SLIPPERY_2, -1, -1
4370 Xround_wall_3, TRUE, FALSE,
4371 EL_EMC_WALL_SLIPPERY_3, -1, -1
4374 Xround_wall_4, TRUE, FALSE,
4375 EL_EMC_WALL_SLIPPERY_4, -1, -1
4378 Xdecor_1, TRUE, FALSE,
4379 EL_EMC_WALL_8, -1, -1
4382 Xdecor_2, TRUE, FALSE,
4383 EL_EMC_WALL_6, -1, -1
4386 Xdecor_3, TRUE, FALSE,
4387 EL_EMC_WALL_4, -1, -1
4390 Xdecor_4, TRUE, FALSE,
4391 EL_EMC_WALL_7, -1, -1
4394 Xdecor_5, TRUE, FALSE,
4395 EL_EMC_WALL_5, -1, -1
4398 Xdecor_6, TRUE, FALSE,
4399 EL_EMC_WALL_9, -1, -1
4402 Xdecor_7, TRUE, FALSE,
4403 EL_EMC_WALL_10, -1, -1
4406 Xdecor_8, TRUE, FALSE,
4407 EL_EMC_WALL_1, -1, -1
4410 Xdecor_9, TRUE, FALSE,
4411 EL_EMC_WALL_2, -1, -1
4414 Xdecor_10, TRUE, FALSE,
4415 EL_EMC_WALL_3, -1, -1
4418 Xdecor_11, TRUE, FALSE,
4419 EL_EMC_WALL_11, -1, -1
4422 Xdecor_12, TRUE, FALSE,
4423 EL_EMC_WALL_12, -1, -1
4426 Xalpha_0, TRUE, FALSE,
4427 EL_CHAR('0'), -1, -1
4430 Xalpha_1, TRUE, FALSE,
4431 EL_CHAR('1'), -1, -1
4434 Xalpha_2, TRUE, FALSE,
4435 EL_CHAR('2'), -1, -1
4438 Xalpha_3, TRUE, FALSE,
4439 EL_CHAR('3'), -1, -1
4442 Xalpha_4, TRUE, FALSE,
4443 EL_CHAR('4'), -1, -1
4446 Xalpha_5, TRUE, FALSE,
4447 EL_CHAR('5'), -1, -1
4450 Xalpha_6, TRUE, FALSE,
4451 EL_CHAR('6'), -1, -1
4454 Xalpha_7, TRUE, FALSE,
4455 EL_CHAR('7'), -1, -1
4458 Xalpha_8, TRUE, FALSE,
4459 EL_CHAR('8'), -1, -1
4462 Xalpha_9, TRUE, FALSE,
4463 EL_CHAR('9'), -1, -1
4466 Xalpha_excla, TRUE, FALSE,
4467 EL_CHAR('!'), -1, -1
4470 Xalpha_quote, TRUE, FALSE,
4471 EL_CHAR('"'), -1, -1
4474 Xalpha_comma, TRUE, FALSE,
4475 EL_CHAR(','), -1, -1
4478 Xalpha_minus, TRUE, FALSE,
4479 EL_CHAR('-'), -1, -1
4482 Xalpha_perio, TRUE, FALSE,
4483 EL_CHAR('.'), -1, -1
4486 Xalpha_colon, TRUE, FALSE,
4487 EL_CHAR(':'), -1, -1
4490 Xalpha_quest, TRUE, FALSE,
4491 EL_CHAR('?'), -1, -1
4494 Xalpha_a, TRUE, FALSE,
4495 EL_CHAR('A'), -1, -1
4498 Xalpha_b, TRUE, FALSE,
4499 EL_CHAR('B'), -1, -1
4502 Xalpha_c, TRUE, FALSE,
4503 EL_CHAR('C'), -1, -1
4506 Xalpha_d, TRUE, FALSE,
4507 EL_CHAR('D'), -1, -1
4510 Xalpha_e, TRUE, FALSE,
4511 EL_CHAR('E'), -1, -1
4514 Xalpha_f, TRUE, FALSE,
4515 EL_CHAR('F'), -1, -1
4518 Xalpha_g, TRUE, FALSE,
4519 EL_CHAR('G'), -1, -1
4522 Xalpha_h, TRUE, FALSE,
4523 EL_CHAR('H'), -1, -1
4526 Xalpha_i, TRUE, FALSE,
4527 EL_CHAR('I'), -1, -1
4530 Xalpha_j, TRUE, FALSE,
4531 EL_CHAR('J'), -1, -1
4534 Xalpha_k, TRUE, FALSE,
4535 EL_CHAR('K'), -1, -1
4538 Xalpha_l, TRUE, FALSE,
4539 EL_CHAR('L'), -1, -1
4542 Xalpha_m, TRUE, FALSE,
4543 EL_CHAR('M'), -1, -1
4546 Xalpha_n, TRUE, FALSE,
4547 EL_CHAR('N'), -1, -1
4550 Xalpha_o, TRUE, FALSE,
4551 EL_CHAR('O'), -1, -1
4554 Xalpha_p, TRUE, FALSE,
4555 EL_CHAR('P'), -1, -1
4558 Xalpha_q, TRUE, FALSE,
4559 EL_CHAR('Q'), -1, -1
4562 Xalpha_r, TRUE, FALSE,
4563 EL_CHAR('R'), -1, -1
4566 Xalpha_s, TRUE, FALSE,
4567 EL_CHAR('S'), -1, -1
4570 Xalpha_t, TRUE, FALSE,
4571 EL_CHAR('T'), -1, -1
4574 Xalpha_u, TRUE, FALSE,
4575 EL_CHAR('U'), -1, -1
4578 Xalpha_v, TRUE, FALSE,
4579 EL_CHAR('V'), -1, -1
4582 Xalpha_w, TRUE, FALSE,
4583 EL_CHAR('W'), -1, -1
4586 Xalpha_x, TRUE, FALSE,
4587 EL_CHAR('X'), -1, -1
4590 Xalpha_y, TRUE, FALSE,
4591 EL_CHAR('Y'), -1, -1
4594 Xalpha_z, TRUE, FALSE,
4595 EL_CHAR('Z'), -1, -1
4598 Xalpha_arrow_e, TRUE, FALSE,
4599 EL_CHAR('>'), -1, -1
4602 Xalpha_arrow_w, TRUE, FALSE,
4603 EL_CHAR('<'), -1, -1
4606 Xalpha_copyr, TRUE, FALSE,
4607 EL_CHAR('©'), -1, -1
4611 Xboom_bug, FALSE, FALSE,
4612 EL_BUG, ACTION_EXPLODING, -1
4615 Xboom_bomb, FALSE, FALSE,
4616 EL_BOMB, ACTION_EXPLODING, -1
4619 Xboom_android, FALSE, FALSE,
4620 EL_EMC_ANDROID, ACTION_OTHER, -1
4623 Xboom_1, FALSE, FALSE,
4624 EL_DEFAULT, ACTION_EXPLODING, -1
4627 Xboom_2, FALSE, FALSE,
4628 EL_DEFAULT, ACTION_EXPLODING, -1
4631 Znormal, FALSE, FALSE,
4635 Zdynamite, FALSE, FALSE,
4639 Zplayer, FALSE, FALSE,
4643 ZBORDER, FALSE, FALSE,
4653 static struct Mapping_EM_to_RND_player
4662 em_player_mapping_list[] =
4666 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4670 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4674 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4678 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4682 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4686 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4690 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4694 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4698 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4702 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4706 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4710 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4714 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4718 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4722 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4726 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4730 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4734 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4738 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4742 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4746 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4750 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4754 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4758 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4762 EL_PLAYER_1, ACTION_DEFAULT, -1,
4766 EL_PLAYER_2, ACTION_DEFAULT, -1,
4770 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4774 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4778 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4782 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4786 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4790 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4794 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4798 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4802 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4806 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4810 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4814 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4818 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4822 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4826 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4830 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4834 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4838 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4842 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4846 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4850 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4854 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4858 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4862 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
4866 EL_PLAYER_3, ACTION_DEFAULT, -1,
4870 EL_PLAYER_4, ACTION_DEFAULT, -1,
4879 int map_element_RND_to_EM(int element_rnd)
4881 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4882 static boolean mapping_initialized = FALSE;
4884 if (!mapping_initialized)
4888 /* return "Xalpha_quest" for all undefined elements in mapping array */
4889 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4890 mapping_RND_to_EM[i] = Xalpha_quest;
4892 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4893 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
4894 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
4895 em_object_mapping_list[i].element_em;
4897 mapping_initialized = TRUE;
4900 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4901 return mapping_RND_to_EM[element_rnd];
4903 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4908 int map_element_EM_to_RND(int element_em)
4910 static unsigned short mapping_EM_to_RND[TILE_MAX];
4911 static boolean mapping_initialized = FALSE;
4913 if (!mapping_initialized)
4917 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
4918 for (i = 0; i < TILE_MAX; i++)
4919 mapping_EM_to_RND[i] = EL_UNKNOWN;
4921 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4922 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
4923 em_object_mapping_list[i].element_rnd;
4925 mapping_initialized = TRUE;
4928 if (element_em >= 0 && element_em < TILE_MAX)
4929 return mapping_EM_to_RND[element_em];
4931 Error(ERR_WARN, "invalid EM level element %d", element_em);
4936 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
4938 struct LevelInfo_EM *level_em = level->native_em_level;
4939 struct LEVEL *lev = level_em->lev;
4942 for (i = 0; i < TILE_MAX; i++)
4943 lev->android_array[i] = Xblank;
4945 for (i = 0; i < level->num_android_clone_elements; i++)
4947 int element_rnd = level->android_clone_element[i];
4948 int element_em = map_element_RND_to_EM(element_rnd);
4950 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
4951 if (em_object_mapping_list[j].element_rnd == element_rnd)
4952 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
4956 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
4958 struct LevelInfo_EM *level_em = level->native_em_level;
4959 struct LEVEL *lev = level_em->lev;
4962 level->num_android_clone_elements = 0;
4964 for (i = 0; i < TILE_MAX; i++)
4966 int element_em = lev->android_array[i];
4968 boolean element_found = FALSE;
4970 if (element_em == Xblank)
4973 element_rnd = map_element_EM_to_RND(element_em);
4975 for (j = 0; j < level->num_android_clone_elements; j++)
4976 if (level->android_clone_element[j] == element_rnd)
4977 element_found = TRUE;
4981 level->android_clone_element[level->num_android_clone_elements++] =
4984 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
4989 if (level->num_android_clone_elements == 0)
4991 level->num_android_clone_elements = 1;
4992 level->android_clone_element[0] = EL_EMPTY;
4996 int map_direction_RND_to_EM(int direction)
4998 return (direction == MV_UP ? 0 :
4999 direction == MV_RIGHT ? 1 :
5000 direction == MV_DOWN ? 2 :
5001 direction == MV_LEFT ? 3 :
5005 int map_direction_EM_to_RND(int direction)
5007 return (direction == 0 ? MV_UP :
5008 direction == 1 ? MV_RIGHT :
5009 direction == 2 ? MV_DOWN :
5010 direction == 3 ? MV_LEFT :
5014 int get_next_element(int element)
5018 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5019 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5020 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5021 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5022 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5023 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5024 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5026 default: return element;
5031 int el_act_dir2img(int element, int action, int direction)
5033 element = GFX_ELEMENT(element);
5035 if (direction == MV_NONE)
5036 return element_info[element].graphic[action];
5038 direction = MV_DIR_TO_BIT(direction);
5040 return element_info[element].direction_graphic[action][direction];
5043 int el_act_dir2img(int element, int action, int direction)
5045 element = GFX_ELEMENT(element);
5046 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5048 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5049 return element_info[element].direction_graphic[action][direction];
5054 static int el_act_dir2crm(int element, int action, int direction)
5056 element = GFX_ELEMENT(element);
5058 if (direction == MV_NONE)
5059 return element_info[element].crumbled[action];
5061 direction = MV_DIR_TO_BIT(direction);
5063 return element_info[element].direction_crumbled[action][direction];
5066 static int el_act_dir2crm(int element, int action, int direction)
5068 element = GFX_ELEMENT(element);
5069 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5071 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5072 return element_info[element].direction_crumbled[action][direction];
5076 int el_act2img(int element, int action)
5078 element = GFX_ELEMENT(element);
5080 return element_info[element].graphic[action];
5083 int el_act2crm(int element, int action)
5085 element = GFX_ELEMENT(element);
5087 return element_info[element].crumbled[action];
5090 int el_dir2img(int element, int direction)
5092 element = GFX_ELEMENT(element);
5094 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5097 int el2baseimg(int element)
5099 return element_info[element].graphic[ACTION_DEFAULT];
5102 int el2img(int element)
5104 element = GFX_ELEMENT(element);
5106 return element_info[element].graphic[ACTION_DEFAULT];
5109 int el2edimg(int element)
5111 element = GFX_ELEMENT(element);
5113 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5116 int el2preimg(int element)
5118 element = GFX_ELEMENT(element);
5120 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5123 int font2baseimg(int font_nr)
5125 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5128 void setCenteredPlayerNr_EM(int centered_player_nr)
5130 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5133 int getCenteredPlayerNr_EM()
5136 if (game.centered_player_nr_next >= 0 &&
5137 !native_em_level.ply[game.centered_player_nr_next]->alive)
5138 game.centered_player_nr_next = game.centered_player_nr;
5141 if (game.centered_player_nr != game.centered_player_nr_next)
5142 game.centered_player_nr = game.centered_player_nr_next;
5144 return game.centered_player_nr;
5147 void setSetCenteredPlayer_EM(boolean set_centered_player)
5149 game.set_centered_player = set_centered_player;
5152 boolean getSetCenteredPlayer_EM()
5154 return game.set_centered_player;
5157 int getNumActivePlayers_EM()
5159 int num_players = 0;
5165 for (i = 0; i < MAX_PLAYERS; i++)
5166 if (tape.player_participates[i])
5172 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5174 int game_frame_delay_value;
5176 game_frame_delay_value =
5177 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5178 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5181 if (tape.playing && tape.warp_forward && !tape.pausing)
5182 game_frame_delay_value = 0;
5184 return game_frame_delay_value;
5187 unsigned int InitRND(long seed)
5189 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5190 return InitEngineRND_EM(seed);
5192 return InitEngineRND(seed);
5195 #define DEBUG_EM_GFX 0
5197 void InitGraphicInfo_EM(void)
5199 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5200 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5204 if (graphic_info_em_object[0][0].bitmap == NULL)
5206 /* EM graphics not yet initialized in em_open_all() */
5212 /* always start with reliable default values */
5213 for (i = 0; i < TILE_MAX; i++)
5215 object_mapping[i].element_rnd = EL_UNKNOWN;
5216 object_mapping[i].is_backside = FALSE;
5217 object_mapping[i].action = ACTION_DEFAULT;
5218 object_mapping[i].direction = MV_NONE;
5221 /* always start with reliable default values */
5222 for (p = 0; p < MAX_PLAYERS; p++)
5224 for (i = 0; i < SPR_MAX; i++)
5226 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5227 player_mapping[p][i].action = ACTION_DEFAULT;
5228 player_mapping[p][i].direction = MV_NONE;
5232 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5234 int e = em_object_mapping_list[i].element_em;
5236 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5237 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5239 if (em_object_mapping_list[i].action != -1)
5240 object_mapping[e].action = em_object_mapping_list[i].action;
5242 if (em_object_mapping_list[i].direction != -1)
5243 object_mapping[e].direction =
5244 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5247 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5249 int a = em_player_mapping_list[i].action_em;
5250 int p = em_player_mapping_list[i].player_nr;
5252 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5254 if (em_player_mapping_list[i].action != -1)
5255 player_mapping[p][a].action = em_player_mapping_list[i].action;
5257 if (em_player_mapping_list[i].direction != -1)
5258 player_mapping[p][a].direction =
5259 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5262 for (i = 0; i < TILE_MAX; i++)
5264 int element = object_mapping[i].element_rnd;
5265 int action = object_mapping[i].action;
5266 int direction = object_mapping[i].direction;
5267 boolean is_backside = object_mapping[i].is_backside;
5268 boolean action_removing = (action == ACTION_DIGGING ||
5269 action == ACTION_SNAPPING ||
5270 action == ACTION_COLLECTING);
5271 boolean action_exploding = ((action == ACTION_EXPLODING ||
5272 action == ACTION_SMASHED_BY_ROCK ||
5273 action == ACTION_SMASHED_BY_SPRING) &&
5274 element != EL_DIAMOND);
5275 boolean action_active = (action == ACTION_ACTIVE);
5276 boolean action_other = (action == ACTION_OTHER);
5278 for (j = 0; j < 8; j++)
5280 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5281 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5283 i == Xdrip_stretch ? element :
5284 i == Xdrip_stretchB ? element :
5285 i == Ydrip_s1 ? element :
5286 i == Ydrip_s1B ? element :
5287 i == Xball_1B ? element :
5288 i == Xball_2 ? element :
5289 i == Xball_2B ? element :
5290 i == Yball_eat ? element :
5291 i == Ykey_1_eat ? element :
5292 i == Ykey_2_eat ? element :
5293 i == Ykey_3_eat ? element :
5294 i == Ykey_4_eat ? element :
5295 i == Ykey_5_eat ? element :
5296 i == Ykey_6_eat ? element :
5297 i == Ykey_7_eat ? element :
5298 i == Ykey_8_eat ? element :
5299 i == Ylenses_eat ? element :
5300 i == Ymagnify_eat ? element :
5301 i == Ygrass_eat ? element :
5302 i == Ydirt_eat ? element :
5303 i == Yspring_kill_e ? EL_SPRING :
5304 i == Yspring_kill_w ? EL_SPRING :
5305 i == Yemerald_stone ? EL_EMERALD :
5306 i == Ydiamond_stone ? EL_ROCK :
5307 i == Xsand_stonein_4 ? EL_EMPTY :
5308 i == Xsand_stoneout_2 ? EL_ROCK :
5309 is_backside ? EL_EMPTY :
5310 action_removing ? EL_EMPTY :
5312 int effective_action = (j < 7 ? action :
5313 i == Xdrip_stretch ? action :
5314 i == Xdrip_stretchB ? action :
5315 i == Ydrip_s1 ? action :
5316 i == Ydrip_s1B ? action :
5317 i == Xball_1B ? action :
5318 i == Xball_2 ? action :
5319 i == Xball_2B ? action :
5320 i == Yball_eat ? action :
5321 i == Ykey_1_eat ? action :
5322 i == Ykey_2_eat ? action :
5323 i == Ykey_3_eat ? action :
5324 i == Ykey_4_eat ? action :
5325 i == Ykey_5_eat ? action :
5326 i == Ykey_6_eat ? action :
5327 i == Ykey_7_eat ? action :
5328 i == Ykey_8_eat ? action :
5329 i == Ylenses_eat ? action :
5330 i == Ymagnify_eat ? action :
5331 i == Ygrass_eat ? action :
5332 i == Ydirt_eat ? action :
5333 i == Xsand_stonein_1 ? action :
5334 i == Xsand_stonein_2 ? action :
5335 i == Xsand_stonein_3 ? action :
5336 i == Xsand_stonein_4 ? action :
5337 i == Xsand_stoneout_1 ? action :
5338 i == Xsand_stoneout_2 ? action :
5339 i == Xboom_android ? ACTION_EXPLODING :
5340 action_exploding ? ACTION_EXPLODING :
5341 action_active ? action :
5342 action_other ? action :
5344 int graphic = (el_act_dir2img(effective_element, effective_action,
5346 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5348 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5349 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5350 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5351 struct GraphicInfo *g = &graphic_info[graphic];
5352 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5355 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5356 boolean special_animation = (action != ACTION_DEFAULT &&
5357 g->anim_frames == 3 &&
5358 g->anim_delay == 2 &&
5359 g->anim_mode & ANIM_LINEAR);
5360 int sync_frame = (i == Xdrip_stretch ? 7 :
5361 i == Xdrip_stretchB ? 7 :
5362 i == Ydrip_s2 ? j + 8 :
5363 i == Ydrip_s2B ? j + 8 :
5372 i == Xfake_acid_1 ? 0 :
5373 i == Xfake_acid_2 ? 10 :
5374 i == Xfake_acid_3 ? 20 :
5375 i == Xfake_acid_4 ? 30 :
5376 i == Xfake_acid_5 ? 40 :
5377 i == Xfake_acid_6 ? 50 :
5378 i == Xfake_acid_7 ? 60 :
5379 i == Xfake_acid_8 ? 70 :
5381 i == Xball_2B ? j + 8 :
5382 i == Yball_eat ? j + 1 :
5383 i == Ykey_1_eat ? j + 1 :
5384 i == Ykey_2_eat ? j + 1 :
5385 i == Ykey_3_eat ? j + 1 :
5386 i == Ykey_4_eat ? j + 1 :
5387 i == Ykey_5_eat ? j + 1 :
5388 i == Ykey_6_eat ? j + 1 :
5389 i == Ykey_7_eat ? j + 1 :
5390 i == Ykey_8_eat ? j + 1 :
5391 i == Ylenses_eat ? j + 1 :
5392 i == Ymagnify_eat ? j + 1 :
5393 i == Ygrass_eat ? j + 1 :
5394 i == Ydirt_eat ? j + 1 :
5395 i == Xamoeba_1 ? 0 :
5396 i == Xamoeba_2 ? 1 :
5397 i == Xamoeba_3 ? 2 :
5398 i == Xamoeba_4 ? 3 :
5399 i == Xamoeba_5 ? 0 :
5400 i == Xamoeba_6 ? 1 :
5401 i == Xamoeba_7 ? 2 :
5402 i == Xamoeba_8 ? 3 :
5403 i == Xexit_2 ? j + 8 :
5404 i == Xexit_3 ? j + 16 :
5405 i == Xdynamite_1 ? 0 :
5406 i == Xdynamite_2 ? 8 :
5407 i == Xdynamite_3 ? 16 :
5408 i == Xdynamite_4 ? 24 :
5409 i == Xsand_stonein_1 ? j + 1 :
5410 i == Xsand_stonein_2 ? j + 9 :
5411 i == Xsand_stonein_3 ? j + 17 :
5412 i == Xsand_stonein_4 ? j + 25 :
5413 i == Xsand_stoneout_1 && j == 0 ? 0 :
5414 i == Xsand_stoneout_1 && j == 1 ? 0 :
5415 i == Xsand_stoneout_1 && j == 2 ? 1 :
5416 i == Xsand_stoneout_1 && j == 3 ? 2 :
5417 i == Xsand_stoneout_1 && j == 4 ? 2 :
5418 i == Xsand_stoneout_1 && j == 5 ? 3 :
5419 i == Xsand_stoneout_1 && j == 6 ? 4 :
5420 i == Xsand_stoneout_1 && j == 7 ? 4 :
5421 i == Xsand_stoneout_2 && j == 0 ? 5 :
5422 i == Xsand_stoneout_2 && j == 1 ? 6 :
5423 i == Xsand_stoneout_2 && j == 2 ? 7 :
5424 i == Xsand_stoneout_2 && j == 3 ? 8 :
5425 i == Xsand_stoneout_2 && j == 4 ? 9 :
5426 i == Xsand_stoneout_2 && j == 5 ? 11 :
5427 i == Xsand_stoneout_2 && j == 6 ? 13 :
5428 i == Xsand_stoneout_2 && j == 7 ? 15 :
5429 i == Xboom_bug && j == 1 ? 2 :
5430 i == Xboom_bug && j == 2 ? 2 :
5431 i == Xboom_bug && j == 3 ? 4 :
5432 i == Xboom_bug && j == 4 ? 4 :
5433 i == Xboom_bug && j == 5 ? 2 :
5434 i == Xboom_bug && j == 6 ? 2 :
5435 i == Xboom_bug && j == 7 ? 0 :
5436 i == Xboom_bomb && j == 1 ? 2 :
5437 i == Xboom_bomb && j == 2 ? 2 :
5438 i == Xboom_bomb && j == 3 ? 4 :
5439 i == Xboom_bomb && j == 4 ? 4 :
5440 i == Xboom_bomb && j == 5 ? 2 :
5441 i == Xboom_bomb && j == 6 ? 2 :
5442 i == Xboom_bomb && j == 7 ? 0 :
5443 i == Xboom_android && j == 7 ? 6 :
5444 i == Xboom_1 && j == 1 ? 2 :
5445 i == Xboom_1 && j == 2 ? 2 :
5446 i == Xboom_1 && j == 3 ? 4 :
5447 i == Xboom_1 && j == 4 ? 4 :
5448 i == Xboom_1 && j == 5 ? 6 :
5449 i == Xboom_1 && j == 6 ? 6 :
5450 i == Xboom_1 && j == 7 ? 8 :
5451 i == Xboom_2 && j == 0 ? 8 :
5452 i == Xboom_2 && j == 1 ? 8 :
5453 i == Xboom_2 && j == 2 ? 10 :
5454 i == Xboom_2 && j == 3 ? 10 :
5455 i == Xboom_2 && j == 4 ? 10 :
5456 i == Xboom_2 && j == 5 ? 12 :
5457 i == Xboom_2 && j == 6 ? 12 :
5458 i == Xboom_2 && j == 7 ? 12 :
5459 special_animation && j == 4 ? 3 :
5460 effective_action != action ? 0 :
5464 Bitmap *debug_bitmap = g_em->bitmap;
5465 int debug_src_x = g_em->src_x;
5466 int debug_src_y = g_em->src_y;
5469 int frame = getAnimationFrame(g->anim_frames,
5472 g->anim_start_frame,
5475 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5476 g->double_movement && is_backside);
5478 g_em->bitmap = src_bitmap;
5479 g_em->src_x = src_x;
5480 g_em->src_y = src_y;
5481 g_em->src_offset_x = 0;
5482 g_em->src_offset_y = 0;
5483 g_em->dst_offset_x = 0;
5484 g_em->dst_offset_y = 0;
5485 g_em->width = TILEX;
5486 g_em->height = TILEY;
5488 g_em->crumbled_bitmap = NULL;
5489 g_em->crumbled_src_x = 0;
5490 g_em->crumbled_src_y = 0;
5491 g_em->crumbled_border_size = 0;
5493 g_em->has_crumbled_graphics = FALSE;
5494 g_em->preserve_background = FALSE;
5497 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5498 printf("::: empty crumbled: %d [%s], %d, %d\n",
5499 effective_element, element_info[effective_element].token_name,
5500 effective_action, direction);
5503 /* if element can be crumbled, but certain action graphics are just empty
5504 space (like snapping sand with the original R'n'D graphics), do not
5505 treat these empty space graphics as crumbled graphics in EMC engine */
5506 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5508 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5510 g_em->has_crumbled_graphics = TRUE;
5511 g_em->crumbled_bitmap = src_bitmap;
5512 g_em->crumbled_src_x = src_x;
5513 g_em->crumbled_src_y = src_y;
5514 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5517 if (!g->double_movement && (effective_action == ACTION_FALLING ||
5518 effective_action == ACTION_MOVING ||
5519 effective_action == ACTION_PUSHING ||
5520 effective_action == ACTION_EATING))
5523 (effective_action == ACTION_FALLING ? MV_DOWN : direction);
5524 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5525 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5526 int num_steps = (i == Ydrip_s1 ||
5529 i == Ydrip_s2B ? 16 : 8);
5530 int cx = ABS(dx) * (TILEX / num_steps);
5531 int cy = ABS(dy) * (TILEY / num_steps);
5532 int step_frame = (i == Ydrip_s2 ||
5533 i == Ydrip_s2B ? j + 8 : j) + 1;
5534 int step = (is_backside ? step_frame : num_steps - step_frame);
5536 if (is_backside) /* tile where movement starts */
5538 if (dx < 0 || dy < 0)
5540 g_em->src_offset_x = cx * step;
5541 g_em->src_offset_y = cy * step;
5545 g_em->dst_offset_x = cx * step;
5546 g_em->dst_offset_y = cy * step;
5549 else /* tile where movement ends */
5551 if (dx < 0 || dy < 0)
5553 g_em->dst_offset_x = cx * step;
5554 g_em->dst_offset_y = cy * step;
5558 g_em->src_offset_x = cx * step;
5559 g_em->src_offset_y = cy * step;
5563 g_em->width = TILEX - cx * step;
5564 g_em->height = TILEY - cy * step;
5568 /* create unique graphic identifier to decide if tile must be redrawn */
5569 /* bit 31 - 16 (16 bit): EM style graphic
5570 bit 15 - 12 ( 4 bit): EM style frame
5571 bit 11 - 6 ( 6 bit): graphic width
5572 bit 5 - 0 ( 6 bit): graphic height */
5573 g_em->unique_identifier =
5574 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5576 /* create unique graphic identifier to decide if tile must be redrawn */
5577 /* bit 31 - 16 (16 bit): EM style element
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 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5586 if (effective_element == EL_ROCK)
5587 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5588 effective_action, j, graphic, frame, g_em->unique_identifier);
5594 /* skip check for EMC elements not contained in original EMC artwork */
5595 if (element == EL_EMC_FAKE_ACID)
5599 if (g_em->bitmap != debug_bitmap ||
5600 g_em->src_x != debug_src_x ||
5601 g_em->src_y != debug_src_y ||
5602 g_em->src_offset_x != 0 ||
5603 g_em->src_offset_y != 0 ||
5604 g_em->dst_offset_x != 0 ||
5605 g_em->dst_offset_y != 0 ||
5606 g_em->width != TILEX ||
5607 g_em->height != TILEY)
5609 static int last_i = -1;
5617 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5618 i, element, element_info[element].token_name,
5619 element_action_info[effective_action].suffix, direction);
5621 if (element != effective_element)
5622 printf(" [%d ('%s')]",
5624 element_info[effective_element].token_name);
5628 if (g_em->bitmap != debug_bitmap)
5629 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5630 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5632 if (g_em->src_x != debug_src_x ||
5633 g_em->src_y != debug_src_y)
5634 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5635 j, (is_backside ? 'B' : 'F'),
5636 g_em->src_x, g_em->src_y,
5637 g_em->src_x / 32, g_em->src_y / 32,
5638 debug_src_x, debug_src_y,
5639 debug_src_x / 32, debug_src_y / 32);
5641 if (g_em->src_offset_x != 0 ||
5642 g_em->src_offset_y != 0 ||
5643 g_em->dst_offset_x != 0 ||
5644 g_em->dst_offset_y != 0)
5645 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5647 g_em->src_offset_x, g_em->src_offset_y,
5648 g_em->dst_offset_x, g_em->dst_offset_y);
5650 if (g_em->width != TILEX ||
5651 g_em->height != TILEY)
5652 printf(" %d (%d): size %d,%d should be %d,%d\n",
5654 g_em->width, g_em->height, TILEX, TILEY);
5661 for (i = 0; i < TILE_MAX; i++)
5663 for (j = 0; j < 8; j++)
5665 int element = object_mapping[i].element_rnd;
5666 int action = object_mapping[i].action;
5667 int direction = object_mapping[i].direction;
5668 boolean is_backside = object_mapping[i].is_backside;
5670 int graphic_action = el_act_dir2img(element, action, direction);
5671 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5673 int graphic_action = element_info[element].graphic[action];
5674 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5677 if ((action == ACTION_SMASHED_BY_ROCK ||
5678 action == ACTION_SMASHED_BY_SPRING ||
5679 action == ACTION_EATING) &&
5680 graphic_action == graphic_default)
5682 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5683 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5684 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5685 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5688 /* no separate animation for "smashed by rock" -- use rock instead */
5689 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5690 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5692 g_em->bitmap = g_xx->bitmap;
5693 g_em->src_x = g_xx->src_x;
5694 g_em->src_y = g_xx->src_y;
5695 g_em->src_offset_x = g_xx->src_offset_x;
5696 g_em->src_offset_y = g_xx->src_offset_y;
5697 g_em->dst_offset_x = g_xx->dst_offset_x;
5698 g_em->dst_offset_y = g_xx->dst_offset_y;
5699 g_em->width = g_xx->width;
5700 g_em->height = g_xx->height;
5702 g_em->unique_identifier = g_xx->unique_identifier;
5706 g_em->preserve_background = TRUE;
5711 for (p = 0; p < MAX_PLAYERS; p++)
5713 for (i = 0; i < SPR_MAX; i++)
5715 int element = player_mapping[p][i].element_rnd;
5716 int action = player_mapping[p][i].action;
5717 int direction = player_mapping[p][i].direction;
5719 for (j = 0; j < 8; j++)
5721 int effective_element = element;
5722 int effective_action = action;
5723 int graphic = (direction == MV_NONE ?
5724 el_act2img(effective_element, effective_action) :
5725 el_act_dir2img(effective_element, effective_action,
5727 struct GraphicInfo *g = &graphic_info[graphic];
5728 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5734 Bitmap *debug_bitmap = g_em->bitmap;
5735 int debug_src_x = g_em->src_x;
5736 int debug_src_y = g_em->src_y;
5739 int frame = getAnimationFrame(g->anim_frames,
5742 g->anim_start_frame,
5745 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5747 g_em->bitmap = src_bitmap;
5748 g_em->src_x = src_x;
5749 g_em->src_y = src_y;
5750 g_em->src_offset_x = 0;
5751 g_em->src_offset_y = 0;
5752 g_em->dst_offset_x = 0;
5753 g_em->dst_offset_y = 0;
5754 g_em->width = TILEX;
5755 g_em->height = TILEY;
5760 /* skip check for EMC elements not contained in original EMC artwork */
5761 if (element == EL_PLAYER_3 ||
5762 element == EL_PLAYER_4)
5766 if (g_em->bitmap != debug_bitmap ||
5767 g_em->src_x != debug_src_x ||
5768 g_em->src_y != debug_src_y)
5770 static int last_i = -1;
5778 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5779 p, i, element, element_info[element].token_name,
5780 element_action_info[effective_action].suffix, direction);
5782 if (element != effective_element)
5783 printf(" [%d ('%s')]",
5785 element_info[effective_element].token_name);
5789 if (g_em->bitmap != debug_bitmap)
5790 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5791 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5793 if (g_em->src_x != debug_src_x ||
5794 g_em->src_y != debug_src_y)
5795 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5797 g_em->src_x, g_em->src_y,
5798 g_em->src_x / 32, g_em->src_y / 32,
5799 debug_src_x, debug_src_y,
5800 debug_src_x / 32, debug_src_y / 32);