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 int sx = SCREENX(jx), sy = SCREENY(jy);
1829 int sxx = 0, syy = 0;
1830 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1832 int action = ACTION_DEFAULT;
1833 int last_player_graphic = getPlayerGraphic(player, move_dir);
1834 int last_player_frame = player->Frame;
1838 /* GfxElement[][] is set to the element the player is digging or collecting;
1839 remove also for off-screen player if the player is not moving anymore */
1840 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1841 GfxElement[jx][jy] = EL_UNDEFINED;
1844 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1848 if (!IN_LEV_FIELD(jx, jy))
1850 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1851 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1852 printf("DrawPlayerField(): This should never happen!\n");
1857 if (element == EL_EXPLOSION)
1860 action = (player->is_pushing ? ACTION_PUSHING :
1861 player->is_digging ? ACTION_DIGGING :
1862 player->is_collecting ? ACTION_COLLECTING :
1863 player->is_moving ? ACTION_MOVING :
1864 player->is_snapping ? ACTION_SNAPPING :
1865 player->is_dropping ? ACTION_DROPPING :
1866 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1868 InitPlayerGfxAnimation(player, action, move_dir);
1870 /* ----------------------------------------------------------------------- */
1871 /* draw things in the field the player is leaving, if needed */
1872 /* ----------------------------------------------------------------------- */
1874 if (player->is_moving)
1876 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1878 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1880 if (last_element == EL_DYNAMITE_ACTIVE ||
1881 last_element == EL_EM_DYNAMITE_ACTIVE ||
1882 last_element == EL_SP_DISK_RED_ACTIVE)
1883 DrawDynamite(last_jx, last_jy);
1885 DrawLevelFieldThruMask(last_jx, last_jy);
1887 else if (last_element == EL_DYNAMITE_ACTIVE ||
1888 last_element == EL_EM_DYNAMITE_ACTIVE ||
1889 last_element == EL_SP_DISK_RED_ACTIVE)
1890 DrawDynamite(last_jx, last_jy);
1892 DrawLevelField(last_jx, last_jy);
1894 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
1895 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
1898 if (!IN_SCR_FIELD(sx, sy))
1901 if (setup.direct_draw)
1902 SetDrawtoField(DRAW_BUFFERED);
1904 /* ----------------------------------------------------------------------- */
1905 /* draw things behind the player, if needed */
1906 /* ----------------------------------------------------------------------- */
1909 DrawLevelElement(jx, jy, Back[jx][jy]);
1910 else if (IS_ACTIVE_BOMB(element))
1911 DrawLevelElement(jx, jy, EL_EMPTY);
1914 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
1916 if (GFX_CRUMBLED(GfxElement[jx][jy]))
1917 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
1920 int old_element = GfxElement[jx][jy];
1921 int old_graphic = el_act_dir2img(old_element, action, move_dir);
1922 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
1924 DrawGraphic(sx, sy, old_graphic, frame);
1929 GfxElement[jx][jy] = EL_UNDEFINED;
1931 /* make sure that pushed elements are drawn with correct frame rate */
1932 if (player->is_pushing && player->is_moving)
1933 GfxFrame[jx][jy] = player->StepFrame;
1935 DrawLevelField(jx, jy);
1939 /* ----------------------------------------------------------------------- */
1940 /* draw player himself */
1941 /* ----------------------------------------------------------------------- */
1943 graphic = getPlayerGraphic(player, move_dir);
1945 /* in the case of changed player action or direction, prevent the current
1946 animation frame from being restarted for identical animations */
1947 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
1948 player->Frame = last_player_frame;
1950 frame = getGraphicAnimationFrame(graphic, player->Frame);
1954 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1955 sxx = player->GfxPos;
1957 syy = player->GfxPos;
1960 if (!setup.soft_scrolling && ScreenMovPos)
1963 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1965 if (SHIELD_ON(player))
1967 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
1968 IMG_SHIELD_NORMAL_ACTIVE);
1969 int frame = getGraphicAnimationFrame(graphic, -1);
1971 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1974 /* ----------------------------------------------------------------------- */
1975 /* draw things the player is pushing, if needed */
1976 /* ----------------------------------------------------------------------- */
1979 printf("::: %d, %d [%d, %d] [%d]\n",
1980 player->is_pushing, player_is_moving, player->GfxAction,
1981 player->is_moving, player_is_moving);
1985 if (player->is_pushing && player->is_moving)
1987 int px = SCREENX(jx), py = SCREENY(jy);
1988 int pxx = (TILEX - ABS(sxx)) * dx;
1989 int pyy = (TILEY - ABS(syy)) * dy;
1994 if (!IS_MOVING(jx, jy)) /* push movement already finished */
1995 element = Feld[next_jx][next_jy];
1997 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
1998 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2000 /* draw background element under pushed element (like the Sokoban field) */
2001 if (Back[next_jx][next_jy])
2002 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2004 /* masked drawing is needed for EMC style (double) movement graphics */
2005 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2009 /* ----------------------------------------------------------------------- */
2010 /* draw things in front of player (active dynamite or dynabombs) */
2011 /* ----------------------------------------------------------------------- */
2013 if (IS_ACTIVE_BOMB(element))
2015 graphic = el2img(element);
2016 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2018 if (game.emulation == EMU_SUPAPLEX)
2019 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2021 DrawGraphicThruMask(sx, sy, graphic, frame);
2024 if (player_is_moving && last_element == EL_EXPLOSION)
2026 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2027 GfxElement[last_jx][last_jy] : EL_EMPTY);
2028 int graphic = el_act2img(element, ACTION_EXPLODING);
2029 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2030 int phase = ExplodePhase[last_jx][last_jy] - 1;
2031 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2034 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2037 /* ----------------------------------------------------------------------- */
2038 /* draw elements the player is just walking/passing through/under */
2039 /* ----------------------------------------------------------------------- */
2041 if (player_is_moving)
2043 /* handle the field the player is leaving ... */
2044 if (IS_ACCESSIBLE_INSIDE(last_element))
2045 DrawLevelField(last_jx, last_jy);
2046 else if (IS_ACCESSIBLE_UNDER(last_element))
2047 DrawLevelFieldThruMask(last_jx, last_jy);
2050 /* do not redraw accessible elements if the player is just pushing them */
2051 if (!player_is_moving || !player->is_pushing)
2053 /* ... and the field the player is entering */
2054 if (IS_ACCESSIBLE_INSIDE(element))
2055 DrawLevelField(jx, jy);
2056 else if (IS_ACCESSIBLE_UNDER(element))
2057 DrawLevelFieldThruMask(jx, jy);
2060 if (setup.direct_draw)
2062 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2063 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2064 int x_size = TILEX * (1 + ABS(jx - last_jx));
2065 int y_size = TILEY * (1 + ABS(jy - last_jy));
2067 BlitBitmap(drawto_field, window,
2068 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2069 SetDrawtoField(DRAW_DIRECT);
2072 MarkTileDirty(sx, sy);
2075 /* ------------------------------------------------------------------------- */
2077 void WaitForEventToContinue()
2079 boolean still_wait = TRUE;
2081 /* simulate releasing mouse button over last gadget, if still pressed */
2083 HandleGadgets(-1, -1, 0);
2085 button_status = MB_RELEASED;
2097 case EVENT_BUTTONPRESS:
2098 case EVENT_KEYPRESS:
2102 case EVENT_KEYRELEASE:
2103 ClearPlayerAction();
2107 HandleOtherEvents(&event);
2111 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2118 /* don't eat all CPU time */
2123 #define MAX_REQUEST_LINES 13
2124 #define MAX_REQUEST_LINE_FONT1_LEN 7
2125 #define MAX_REQUEST_LINE_FONT2_LEN 10
2127 boolean Request(char *text, unsigned int req_state)
2129 int mx, my, ty, result = -1;
2130 unsigned int old_door_state;
2131 int last_game_status = game_status; /* save current game status */
2132 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2133 int font_nr = FONT_TEXT_2;
2134 int max_word_len = 0;
2137 for (text_ptr = text; *text_ptr; text_ptr++)
2139 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2141 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2143 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2144 font_nr = FONT_LEVEL_NUMBER;
2150 if (game_status == GAME_MODE_PLAYING &&
2151 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2152 BlitScreenToBitmap_EM(backbuffer);
2154 /* disable deactivated drawing when quick-loading level tape recording */
2155 if (tape.playing && tape.deactivate_display)
2156 TapeDeactivateDisplayOff(TRUE);
2158 SetMouseCursor(CURSOR_DEFAULT);
2160 #if defined(NETWORK_AVALIABLE)
2161 /* pause network game while waiting for request to answer */
2162 if (options.network &&
2163 game_status == GAME_MODE_PLAYING &&
2164 req_state & REQUEST_WAIT_FOR_INPUT)
2165 SendToServer_PausePlaying();
2168 old_door_state = GetDoorState();
2170 /* simulate releasing mouse button over last gadget, if still pressed */
2172 HandleGadgets(-1, -1, 0);
2176 if (old_door_state & DOOR_OPEN_1)
2178 CloseDoor(DOOR_CLOSE_1);
2180 /* save old door content */
2181 BlitBitmap(bitmap_db_door, bitmap_db_door,
2182 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2183 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2186 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2188 /* clear door drawing field */
2189 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2191 /* force DOOR font on preview level */
2192 game_status = GAME_MODE_PSEUDO_DOOR;
2194 /* write text for request */
2195 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2197 char text_line[max_request_line_len + 1];
2203 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2206 if (!tc || tc == ' ')
2217 strncpy(text_line, text, tl);
2220 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2221 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2222 text_line, font_nr);
2224 text += tl + (tc == ' ' ? 1 : 0);
2227 game_status = last_game_status; /* restore current game status */
2229 if (req_state & REQ_ASK)
2231 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2232 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2234 else if (req_state & REQ_CONFIRM)
2236 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2238 else if (req_state & REQ_PLAYER)
2240 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2241 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2242 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2243 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2246 /* copy request gadgets to door backbuffer */
2247 BlitBitmap(drawto, bitmap_db_door,
2248 DX, DY, DXSIZE, DYSIZE,
2249 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2251 OpenDoor(DOOR_OPEN_1);
2253 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2255 SetDrawBackgroundMask(REDRAW_FIELD);
2260 if (game_status != GAME_MODE_MAIN)
2263 button_status = MB_RELEASED;
2265 request_gadget_id = -1;
2267 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2279 case EVENT_BUTTONPRESS:
2280 case EVENT_BUTTONRELEASE:
2281 case EVENT_MOTIONNOTIFY:
2283 if (event.type == EVENT_MOTIONNOTIFY)
2285 if (!PointerInWindow(window))
2286 continue; /* window and pointer are on different screens */
2291 motion_status = TRUE;
2292 mx = ((MotionEvent *) &event)->x;
2293 my = ((MotionEvent *) &event)->y;
2297 motion_status = FALSE;
2298 mx = ((ButtonEvent *) &event)->x;
2299 my = ((ButtonEvent *) &event)->y;
2300 if (event.type == EVENT_BUTTONPRESS)
2301 button_status = ((ButtonEvent *) &event)->button;
2303 button_status = MB_RELEASED;
2306 /* this sets 'request_gadget_id' */
2307 HandleGadgets(mx, my, button_status);
2309 switch(request_gadget_id)
2311 case TOOL_CTRL_ID_YES:
2314 case TOOL_CTRL_ID_NO:
2317 case TOOL_CTRL_ID_CONFIRM:
2318 result = TRUE | FALSE;
2321 case TOOL_CTRL_ID_PLAYER_1:
2324 case TOOL_CTRL_ID_PLAYER_2:
2327 case TOOL_CTRL_ID_PLAYER_3:
2330 case TOOL_CTRL_ID_PLAYER_4:
2341 case EVENT_KEYPRESS:
2342 switch(GetEventKey((KeyEvent *)&event, TRUE))
2355 if (req_state & REQ_PLAYER)
2359 case EVENT_KEYRELEASE:
2360 ClearPlayerAction();
2364 HandleOtherEvents(&event);
2368 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2370 int joy = AnyJoystick();
2372 if (joy & JOY_BUTTON_1)
2374 else if (joy & JOY_BUTTON_2)
2380 /* don't eat all CPU time */
2384 if (game_status != GAME_MODE_MAIN)
2389 if (!(req_state & REQ_STAY_OPEN))
2391 CloseDoor(DOOR_CLOSE_1);
2393 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2394 (req_state & REQ_REOPEN))
2395 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2400 SetDrawBackgroundMask(REDRAW_FIELD);
2402 #if defined(NETWORK_AVALIABLE)
2403 /* continue network game after request */
2404 if (options.network &&
2405 game_status == GAME_MODE_PLAYING &&
2406 req_state & REQUEST_WAIT_FOR_INPUT)
2407 SendToServer_ContinuePlaying();
2410 /* restore deactivated drawing when quick-loading level tape recording */
2411 if (tape.playing && tape.deactivate_display)
2412 TapeDeactivateDisplayOn();
2417 unsigned int OpenDoor(unsigned int door_state)
2419 if (door_state & DOOR_COPY_BACK)
2421 if (door_state & DOOR_OPEN_1)
2422 BlitBitmap(bitmap_db_door, bitmap_db_door,
2423 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2424 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2426 if (door_state & DOOR_OPEN_2)
2427 BlitBitmap(bitmap_db_door, bitmap_db_door,
2428 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2429 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2431 door_state &= ~DOOR_COPY_BACK;
2434 return MoveDoor(door_state);
2437 unsigned int CloseDoor(unsigned int door_state)
2439 unsigned int old_door_state = GetDoorState();
2441 if (!(door_state & DOOR_NO_COPY_BACK))
2443 if (old_door_state & DOOR_OPEN_1)
2444 BlitBitmap(backbuffer, bitmap_db_door,
2445 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2447 if (old_door_state & DOOR_OPEN_2)
2448 BlitBitmap(backbuffer, bitmap_db_door,
2449 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2451 door_state &= ~DOOR_NO_COPY_BACK;
2454 return MoveDoor(door_state);
2457 unsigned int GetDoorState()
2459 return MoveDoor(DOOR_GET_STATE);
2462 unsigned int SetDoorState(unsigned int door_state)
2464 return MoveDoor(door_state | DOOR_SET_STATE);
2467 unsigned int MoveDoor(unsigned int door_state)
2469 static int door1 = DOOR_OPEN_1;
2470 static int door2 = DOOR_CLOSE_2;
2471 unsigned long door_delay = 0;
2472 unsigned long door_delay_value;
2475 if (door_1.width < 0 || door_1.width > DXSIZE)
2476 door_1.width = DXSIZE;
2477 if (door_1.height < 0 || door_1.height > DYSIZE)
2478 door_1.height = DYSIZE;
2479 if (door_2.width < 0 || door_2.width > VXSIZE)
2480 door_2.width = VXSIZE;
2481 if (door_2.height < 0 || door_2.height > VYSIZE)
2482 door_2.height = VYSIZE;
2484 if (door_state == DOOR_GET_STATE)
2485 return(door1 | door2);
2487 if (door_state & DOOR_SET_STATE)
2489 if (door_state & DOOR_ACTION_1)
2490 door1 = door_state & DOOR_ACTION_1;
2491 if (door_state & DOOR_ACTION_2)
2492 door2 = door_state & DOOR_ACTION_2;
2494 return(door1 | door2);
2497 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2498 door_state &= ~DOOR_OPEN_1;
2499 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2500 door_state &= ~DOOR_CLOSE_1;
2501 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2502 door_state &= ~DOOR_OPEN_2;
2503 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2504 door_state &= ~DOOR_CLOSE_2;
2506 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2509 if (setup.quick_doors)
2511 stepsize = 20; /* must be choosen to always draw last frame */
2512 door_delay_value = 0;
2515 if (global.autoplay_leveldir)
2517 door_state |= DOOR_NO_DELAY;
2518 door_state &= ~DOOR_CLOSE_ALL;
2521 if (door_state & DOOR_ACTION)
2523 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2524 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2525 boolean door_1_done = (!handle_door_1);
2526 boolean door_2_done = (!handle_door_2);
2527 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2528 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2529 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2530 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2531 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2532 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2533 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2534 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2535 int door_skip = max_door_size - door_size;
2537 int end = door_size;
2539 int end = (door_state & DOOR_ACTION_1 &&
2540 door_1.anim_mode & ANIM_VERTICAL ? DYSIZE : DXSIZE);
2543 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2545 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2549 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2551 /* opening door sound has priority over simultaneously closing door */
2552 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2553 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2554 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2555 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2558 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2561 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2562 GC gc = bitmap->stored_clip_gc;
2564 if (door_state & DOOR_ACTION_1)
2566 int a = MIN(x * door_1.step_offset, end);
2567 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2568 int i = p + door_skip;
2570 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2572 BlitBitmap(bitmap_db_door, drawto,
2573 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2574 DXSIZE, DYSIZE, DX, DY);
2578 BlitBitmap(bitmap_db_door, drawto,
2579 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2580 DXSIZE, DYSIZE - p / 2, DX, DY);
2582 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2585 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2587 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2588 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2589 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2590 int dst2_x = DX, dst2_y = DY;
2591 int width = i, height = DYSIZE;
2593 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2594 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2597 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2598 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2601 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2603 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2604 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2605 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2606 int dst2_x = DX, dst2_y = DY;
2607 int width = DXSIZE, height = i;
2609 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2610 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2613 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2614 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2617 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2619 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2621 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2622 BlitBitmapMasked(bitmap, drawto,
2623 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2624 DX + DXSIZE - i, DY + j);
2625 BlitBitmapMasked(bitmap, drawto,
2626 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2627 DX + DXSIZE - i, DY + 140 + j);
2628 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2629 DY - (DOOR_GFX_PAGEY1 + j));
2630 BlitBitmapMasked(bitmap, drawto,
2631 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2633 BlitBitmapMasked(bitmap, drawto,
2634 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2637 BlitBitmapMasked(bitmap, drawto,
2638 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2640 BlitBitmapMasked(bitmap, drawto,
2641 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2643 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2644 BlitBitmapMasked(bitmap, drawto,
2645 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2646 DX + DXSIZE - i, DY + 77 + j);
2647 BlitBitmapMasked(bitmap, drawto,
2648 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2649 DX + DXSIZE - i, DY + 203 + j);
2652 redraw_mask |= REDRAW_DOOR_1;
2653 door_1_done = (a == end);
2656 if (door_state & DOOR_ACTION_2)
2658 int a = MIN(x * door_2.step_offset, door_size_2);
2659 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2660 int i = p + door_skip;
2662 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2664 BlitBitmap(bitmap_db_door, drawto,
2665 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2666 VXSIZE, VYSIZE, VX, VY);
2668 else if (x <= VYSIZE)
2670 BlitBitmap(bitmap_db_door, drawto,
2671 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2672 VXSIZE, VYSIZE - p / 2, VX, VY);
2674 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2677 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2679 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2680 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2681 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2682 int dst2_x = VX, dst2_y = VY;
2683 int width = i, height = VYSIZE;
2685 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2686 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2689 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2690 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2693 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2695 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2696 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2697 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2698 int dst2_x = VX, dst2_y = VY;
2699 int width = VXSIZE, height = i;
2701 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2702 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2705 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2706 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2709 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2711 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2713 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2714 BlitBitmapMasked(bitmap, drawto,
2715 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2716 VX + VXSIZE - i, VY + j);
2717 SetClipOrigin(bitmap, gc,
2718 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2719 BlitBitmapMasked(bitmap, drawto,
2720 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2723 BlitBitmapMasked(bitmap, drawto,
2724 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2725 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2726 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2727 BlitBitmapMasked(bitmap, drawto,
2728 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2730 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2733 redraw_mask |= REDRAW_DOOR_2;
2734 door_2_done = (a == VXSIZE);
2739 if (game_status == GAME_MODE_MAIN)
2742 if (!(door_state & DOOR_NO_DELAY))
2743 WaitUntilDelayReached(&door_delay, door_delay_value);
2747 if (door_state & DOOR_ACTION_1)
2748 door1 = door_state & DOOR_ACTION_1;
2749 if (door_state & DOOR_ACTION_2)
2750 door2 = door_state & DOOR_ACTION_2;
2752 return (door1 | door2);
2755 void DrawSpecialEditorDoor()
2757 /* draw bigger toolbox window */
2758 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2759 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2761 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2762 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2765 redraw_mask |= REDRAW_ALL;
2768 void UndrawSpecialEditorDoor()
2770 /* draw normal tape recorder window */
2771 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2772 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2775 redraw_mask |= REDRAW_ALL;
2779 /* ---------- new tool button stuff ---------------------------------------- */
2781 /* graphic position values for tool buttons */
2782 #define TOOL_BUTTON_YES_XPOS 2
2783 #define TOOL_BUTTON_YES_YPOS 250
2784 #define TOOL_BUTTON_YES_GFX_YPOS 0
2785 #define TOOL_BUTTON_YES_XSIZE 46
2786 #define TOOL_BUTTON_YES_YSIZE 28
2787 #define TOOL_BUTTON_NO_XPOS 52
2788 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2789 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2790 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2791 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2792 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2793 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2794 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2795 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2796 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2797 #define TOOL_BUTTON_PLAYER_XSIZE 30
2798 #define TOOL_BUTTON_PLAYER_YSIZE 30
2799 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2800 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2801 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2802 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2803 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2804 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2805 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2806 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2807 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2808 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2809 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2810 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2811 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2812 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2813 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2814 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2815 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2816 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2817 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2818 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2827 } toolbutton_info[NUM_TOOL_BUTTONS] =
2830 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2831 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2832 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2837 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2838 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2839 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2844 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2845 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2846 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2847 TOOL_CTRL_ID_CONFIRM,
2851 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2852 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2853 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2854 TOOL_CTRL_ID_PLAYER_1,
2858 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2859 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2860 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2861 TOOL_CTRL_ID_PLAYER_2,
2865 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2866 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2867 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2868 TOOL_CTRL_ID_PLAYER_3,
2872 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2873 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2874 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2875 TOOL_CTRL_ID_PLAYER_4,
2880 void CreateToolButtons()
2884 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2886 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2887 Bitmap *deco_bitmap = None;
2888 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2889 struct GadgetInfo *gi;
2890 unsigned long event_mask;
2891 int gd_xoffset, gd_yoffset;
2892 int gd_x1, gd_x2, gd_y;
2895 event_mask = GD_EVENT_RELEASED;
2897 gd_xoffset = toolbutton_info[i].xpos;
2898 gd_yoffset = toolbutton_info[i].ypos;
2899 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2900 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2901 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2903 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2905 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2907 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2908 &deco_bitmap, &deco_x, &deco_y);
2909 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2910 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2913 gi = CreateGadget(GDI_CUSTOM_ID, id,
2914 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2915 GDI_X, DX + toolbutton_info[i].x,
2916 GDI_Y, DY + toolbutton_info[i].y,
2917 GDI_WIDTH, toolbutton_info[i].width,
2918 GDI_HEIGHT, toolbutton_info[i].height,
2919 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2920 GDI_STATE, GD_BUTTON_UNPRESSED,
2921 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2922 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2923 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2924 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2925 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2926 GDI_DECORATION_SHIFTING, 1, 1,
2927 GDI_EVENT_MASK, event_mask,
2928 GDI_CALLBACK_ACTION, HandleToolButtons,
2932 Error(ERR_EXIT, "cannot create gadget");
2934 tool_gadget[id] = gi;
2938 void FreeToolButtons()
2942 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2943 FreeGadget(tool_gadget[i]);
2946 static void UnmapToolButtons()
2950 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2951 UnmapGadget(tool_gadget[i]);
2954 static void HandleToolButtons(struct GadgetInfo *gi)
2956 request_gadget_id = gi->custom_id;
2959 static struct Mapping_EM_to_RND_object
2962 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
2963 boolean is_backside; /* backside of moving element */
2969 em_object_mapping_list[] =
2972 Xblank, TRUE, FALSE,
2976 Yacid_splash_eB, FALSE, FALSE,
2977 EL_ACID_SPLASH_RIGHT, -1, -1
2980 Yacid_splash_wB, FALSE, FALSE,
2981 EL_ACID_SPLASH_LEFT, -1, -1
2984 #ifdef EM_ENGINE_BAD_ROLL
2986 Xstone_force_e, FALSE, FALSE,
2987 EL_ROCK, -1, MV_BIT_RIGHT
2990 Xstone_force_w, FALSE, FALSE,
2991 EL_ROCK, -1, MV_BIT_LEFT
2994 Xnut_force_e, FALSE, FALSE,
2995 EL_NUT, -1, MV_BIT_RIGHT
2998 Xnut_force_w, FALSE, FALSE,
2999 EL_NUT, -1, MV_BIT_LEFT
3002 Xspring_force_e, FALSE, FALSE,
3003 EL_SPRING, -1, MV_BIT_RIGHT
3006 Xspring_force_w, FALSE, FALSE,
3007 EL_SPRING, -1, MV_BIT_LEFT
3010 Xemerald_force_e, FALSE, FALSE,
3011 EL_EMERALD, -1, MV_BIT_RIGHT
3014 Xemerald_force_w, FALSE, FALSE,
3015 EL_EMERALD, -1, MV_BIT_LEFT
3018 Xdiamond_force_e, FALSE, FALSE,
3019 EL_DIAMOND, -1, MV_BIT_RIGHT
3022 Xdiamond_force_w, FALSE, FALSE,
3023 EL_DIAMOND, -1, MV_BIT_LEFT
3026 Xbomb_force_e, FALSE, FALSE,
3027 EL_BOMB, -1, MV_BIT_RIGHT
3030 Xbomb_force_w, FALSE, FALSE,
3031 EL_BOMB, -1, MV_BIT_LEFT
3033 #endif /* EM_ENGINE_BAD_ROLL */
3036 Xstone, TRUE, FALSE,
3040 Xstone_pause, FALSE, FALSE,
3044 Xstone_fall, FALSE, FALSE,
3048 Ystone_s, FALSE, FALSE,
3049 EL_ROCK, ACTION_FALLING, -1
3052 Ystone_sB, FALSE, TRUE,
3053 EL_ROCK, ACTION_FALLING, -1
3056 Ystone_e, FALSE, FALSE,
3057 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3060 Ystone_eB, FALSE, TRUE,
3061 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3064 Ystone_w, FALSE, FALSE,
3065 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3068 Ystone_wB, FALSE, TRUE,
3069 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3076 Xnut_pause, FALSE, FALSE,
3080 Xnut_fall, FALSE, FALSE,
3084 Ynut_s, FALSE, FALSE,
3085 EL_NUT, ACTION_FALLING, -1
3088 Ynut_sB, FALSE, TRUE,
3089 EL_NUT, ACTION_FALLING, -1
3092 Ynut_e, FALSE, FALSE,
3093 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3096 Ynut_eB, FALSE, TRUE,
3097 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3100 Ynut_w, FALSE, FALSE,
3101 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3104 Ynut_wB, FALSE, TRUE,
3105 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3108 Xbug_n, TRUE, FALSE,
3112 Xbug_e, TRUE, FALSE,
3113 EL_BUG_RIGHT, -1, -1
3116 Xbug_s, TRUE, FALSE,
3120 Xbug_w, TRUE, FALSE,
3124 Xbug_gon, FALSE, FALSE,
3128 Xbug_goe, FALSE, FALSE,
3129 EL_BUG_RIGHT, -1, -1
3132 Xbug_gos, FALSE, FALSE,
3136 Xbug_gow, FALSE, FALSE,
3140 Ybug_n, FALSE, FALSE,
3141 EL_BUG, ACTION_MOVING, MV_BIT_UP
3144 Ybug_nB, FALSE, TRUE,
3145 EL_BUG, ACTION_MOVING, MV_BIT_UP
3148 Ybug_e, FALSE, FALSE,
3149 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3152 Ybug_eB, FALSE, TRUE,
3153 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3156 Ybug_s, FALSE, FALSE,
3157 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3160 Ybug_sB, FALSE, TRUE,
3161 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3164 Ybug_w, FALSE, FALSE,
3165 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3168 Ybug_wB, FALSE, TRUE,
3169 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3172 Ybug_w_n, FALSE, FALSE,
3173 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3176 Ybug_n_e, FALSE, FALSE,
3177 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3180 Ybug_e_s, FALSE, FALSE,
3181 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3184 Ybug_s_w, FALSE, FALSE,
3185 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3188 Ybug_e_n, FALSE, FALSE,
3189 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3192 Ybug_s_e, FALSE, FALSE,
3193 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3196 Ybug_w_s, FALSE, FALSE,
3197 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3200 Ybug_n_w, FALSE, FALSE,
3201 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3204 Ybug_stone, FALSE, FALSE,
3205 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3208 Ybug_spring, FALSE, FALSE,
3209 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3212 Xtank_n, TRUE, FALSE,
3213 EL_SPACESHIP_UP, -1, -1
3216 Xtank_e, TRUE, FALSE,
3217 EL_SPACESHIP_RIGHT, -1, -1
3220 Xtank_s, TRUE, FALSE,
3221 EL_SPACESHIP_DOWN, -1, -1
3224 Xtank_w, TRUE, FALSE,
3225 EL_SPACESHIP_LEFT, -1, -1
3228 Xtank_gon, FALSE, FALSE,
3229 EL_SPACESHIP_UP, -1, -1
3232 Xtank_goe, FALSE, FALSE,
3233 EL_SPACESHIP_RIGHT, -1, -1
3236 Xtank_gos, FALSE, FALSE,
3237 EL_SPACESHIP_DOWN, -1, -1
3240 Xtank_gow, FALSE, FALSE,
3241 EL_SPACESHIP_LEFT, -1, -1
3244 Ytank_n, FALSE, FALSE,
3245 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3248 Ytank_nB, FALSE, TRUE,
3249 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3252 Ytank_e, FALSE, FALSE,
3253 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3256 Ytank_eB, FALSE, TRUE,
3257 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3260 Ytank_s, FALSE, FALSE,
3261 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3264 Ytank_sB, FALSE, TRUE,
3265 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3268 Ytank_w, FALSE, FALSE,
3269 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3272 Ytank_wB, FALSE, TRUE,
3273 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3276 Ytank_w_n, FALSE, FALSE,
3277 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3280 Ytank_n_e, FALSE, FALSE,
3281 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3284 Ytank_e_s, FALSE, FALSE,
3285 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3288 Ytank_s_w, FALSE, FALSE,
3289 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3292 Ytank_e_n, FALSE, FALSE,
3293 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3296 Ytank_s_e, FALSE, FALSE,
3297 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3300 Ytank_w_s, FALSE, FALSE,
3301 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3304 Ytank_n_w, FALSE, FALSE,
3305 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3308 Ytank_stone, FALSE, FALSE,
3309 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3312 Ytank_spring, FALSE, FALSE,
3313 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3316 Xandroid, TRUE, FALSE,
3317 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3320 Xandroid_1_n, FALSE, FALSE,
3321 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3324 Xandroid_2_n, FALSE, FALSE,
3325 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3328 Xandroid_1_e, FALSE, FALSE,
3329 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3332 Xandroid_2_e, FALSE, FALSE,
3333 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3336 Xandroid_1_w, FALSE, FALSE,
3337 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3340 Xandroid_2_w, FALSE, FALSE,
3341 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3344 Xandroid_1_s, FALSE, FALSE,
3345 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3348 Xandroid_2_s, FALSE, FALSE,
3349 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3352 Yandroid_n, FALSE, FALSE,
3353 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3356 Yandroid_nB, FALSE, TRUE,
3357 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3360 Yandroid_ne, FALSE, FALSE,
3361 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3364 Yandroid_neB, FALSE, TRUE,
3365 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3368 Yandroid_e, FALSE, FALSE,
3369 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3372 Yandroid_eB, FALSE, TRUE,
3373 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3376 Yandroid_se, FALSE, FALSE,
3377 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3380 Yandroid_seB, FALSE, TRUE,
3381 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3384 Yandroid_s, FALSE, FALSE,
3385 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3388 Yandroid_sB, FALSE, TRUE,
3389 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3392 Yandroid_sw, FALSE, FALSE,
3393 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3396 Yandroid_swB, FALSE, TRUE,
3397 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3400 Yandroid_w, FALSE, FALSE,
3401 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3404 Yandroid_wB, FALSE, TRUE,
3405 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3408 Yandroid_nw, FALSE, FALSE,
3409 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3412 Yandroid_nwB, FALSE, TRUE,
3413 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3416 Xspring, TRUE, FALSE,
3420 Xspring_pause, FALSE, FALSE,
3424 Xspring_e, FALSE, FALSE,
3428 Xspring_w, FALSE, FALSE,
3432 Xspring_fall, FALSE, FALSE,
3436 Yspring_s, FALSE, FALSE,
3437 EL_SPRING, ACTION_FALLING, -1
3440 Yspring_sB, FALSE, TRUE,
3441 EL_SPRING, ACTION_FALLING, -1
3444 Yspring_e, FALSE, FALSE,
3445 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3448 Yspring_eB, FALSE, TRUE,
3449 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3452 Yspring_w, FALSE, FALSE,
3453 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3456 Yspring_wB, FALSE, TRUE,
3457 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3460 Yspring_kill_e, FALSE, FALSE,
3461 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3464 Yspring_kill_eB, FALSE, TRUE,
3465 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3468 Yspring_kill_w, FALSE, FALSE,
3469 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3472 Yspring_kill_wB, FALSE, TRUE,
3473 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3476 Xeater_n, TRUE, FALSE,
3480 Xeater_e, FALSE, FALSE,
3484 Xeater_w, FALSE, FALSE,
3488 Xeater_s, FALSE, FALSE,
3492 Yeater_n, FALSE, FALSE,
3493 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3496 Yeater_nB, FALSE, TRUE,
3497 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3500 Yeater_e, FALSE, FALSE,
3501 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3504 Yeater_eB, FALSE, TRUE,
3505 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3508 Yeater_s, FALSE, FALSE,
3509 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3512 Yeater_sB, FALSE, TRUE,
3513 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3516 Yeater_w, FALSE, FALSE,
3517 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3520 Yeater_wB, FALSE, TRUE,
3521 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3524 Yeater_stone, FALSE, FALSE,
3525 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3528 Yeater_spring, FALSE, FALSE,
3529 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3532 Xalien, TRUE, FALSE,
3536 Xalien_pause, FALSE, FALSE,
3540 Yalien_n, FALSE, FALSE,
3541 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3544 Yalien_nB, FALSE, TRUE,
3545 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3548 Yalien_e, FALSE, FALSE,
3549 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3552 Yalien_eB, FALSE, TRUE,
3553 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3556 Yalien_s, FALSE, FALSE,
3557 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3560 Yalien_sB, FALSE, TRUE,
3561 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3564 Yalien_w, FALSE, FALSE,
3565 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3568 Yalien_wB, FALSE, TRUE,
3569 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3572 Yalien_stone, FALSE, FALSE,
3573 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3576 Yalien_spring, FALSE, FALSE,
3577 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3580 Xemerald, TRUE, FALSE,
3584 Xemerald_pause, FALSE, FALSE,
3588 Xemerald_fall, FALSE, FALSE,
3592 Xemerald_shine, FALSE, FALSE,
3593 EL_EMERALD, ACTION_TWINKLING, -1
3596 Yemerald_s, FALSE, FALSE,
3597 EL_EMERALD, ACTION_FALLING, -1
3600 Yemerald_sB, FALSE, TRUE,
3601 EL_EMERALD, ACTION_FALLING, -1
3604 Yemerald_e, FALSE, FALSE,
3605 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3608 Yemerald_eB, FALSE, TRUE,
3609 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3612 Yemerald_w, FALSE, FALSE,
3613 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3616 Yemerald_wB, FALSE, TRUE,
3617 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3620 Yemerald_eat, FALSE, FALSE,
3621 EL_EMERALD, ACTION_COLLECTING, -1
3624 Yemerald_stone, FALSE, FALSE,
3625 EL_NUT, ACTION_BREAKING, -1
3628 Xdiamond, TRUE, FALSE,
3632 Xdiamond_pause, FALSE, FALSE,
3636 Xdiamond_fall, FALSE, FALSE,
3640 Xdiamond_shine, FALSE, FALSE,
3641 EL_DIAMOND, ACTION_TWINKLING, -1
3644 Ydiamond_s, FALSE, FALSE,
3645 EL_DIAMOND, ACTION_FALLING, -1
3648 Ydiamond_sB, FALSE, TRUE,
3649 EL_DIAMOND, ACTION_FALLING, -1
3652 Ydiamond_e, FALSE, FALSE,
3653 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3656 Ydiamond_eB, FALSE, TRUE,
3657 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3660 Ydiamond_w, FALSE, FALSE,
3661 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3664 Ydiamond_wB, FALSE, TRUE,
3665 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3668 Ydiamond_eat, FALSE, FALSE,
3669 EL_DIAMOND, ACTION_COLLECTING, -1
3672 Ydiamond_stone, FALSE, FALSE,
3673 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3676 Xdrip_fall, TRUE, FALSE,
3677 EL_AMOEBA_DROP, -1, -1
3680 Xdrip_stretch, FALSE, FALSE,
3681 EL_AMOEBA_DROP, ACTION_FALLING, -1
3684 Xdrip_stretchB, FALSE, TRUE,
3685 EL_AMOEBA_DROP, ACTION_FALLING, -1
3688 Xdrip_eat, FALSE, FALSE,
3689 EL_AMOEBA_DROP, ACTION_GROWING, -1
3692 Ydrip_s1, FALSE, FALSE,
3693 EL_AMOEBA_DROP, ACTION_FALLING, -1
3696 Ydrip_s1B, FALSE, TRUE,
3697 EL_AMOEBA_DROP, ACTION_FALLING, -1
3700 Ydrip_s2, FALSE, FALSE,
3701 EL_AMOEBA_DROP, ACTION_FALLING, -1
3704 Ydrip_s2B, FALSE, TRUE,
3705 EL_AMOEBA_DROP, ACTION_FALLING, -1
3712 Xbomb_pause, FALSE, FALSE,
3716 Xbomb_fall, FALSE, FALSE,
3720 Ybomb_s, FALSE, FALSE,
3721 EL_BOMB, ACTION_FALLING, -1
3724 Ybomb_sB, FALSE, TRUE,
3725 EL_BOMB, ACTION_FALLING, -1
3728 Ybomb_e, FALSE, FALSE,
3729 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3732 Ybomb_eB, FALSE, TRUE,
3733 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3736 Ybomb_w, FALSE, FALSE,
3737 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3740 Ybomb_wB, FALSE, TRUE,
3741 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3744 Ybomb_eat, FALSE, FALSE,
3745 EL_BOMB, ACTION_ACTIVATING, -1
3748 Xballoon, TRUE, FALSE,
3752 Yballoon_n, FALSE, FALSE,
3753 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3756 Yballoon_nB, FALSE, TRUE,
3757 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3760 Yballoon_e, FALSE, FALSE,
3761 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3764 Yballoon_eB, FALSE, TRUE,
3765 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3768 Yballoon_s, FALSE, FALSE,
3769 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3772 Yballoon_sB, FALSE, TRUE,
3773 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3776 Yballoon_w, FALSE, FALSE,
3777 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3780 Yballoon_wB, FALSE, TRUE,
3781 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3784 Xgrass, TRUE, FALSE,
3785 EL_EMC_GRASS, -1, -1
3788 Ygrass_nB, FALSE, FALSE,
3789 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3792 Ygrass_eB, FALSE, FALSE,
3793 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3796 Ygrass_sB, FALSE, FALSE,
3797 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3800 Ygrass_wB, FALSE, FALSE,
3801 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3808 Ydirt_nB, FALSE, FALSE,
3809 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3812 Ydirt_eB, FALSE, FALSE,
3813 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3816 Ydirt_sB, FALSE, FALSE,
3817 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3820 Ydirt_wB, FALSE, FALSE,
3821 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3824 Xacid_ne, TRUE, FALSE,
3825 EL_ACID_POOL_TOPRIGHT, -1, -1
3828 Xacid_se, TRUE, FALSE,
3829 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3832 Xacid_s, TRUE, FALSE,
3833 EL_ACID_POOL_BOTTOM, -1, -1
3836 Xacid_sw, TRUE, FALSE,
3837 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3840 Xacid_nw, TRUE, FALSE,
3841 EL_ACID_POOL_TOPLEFT, -1, -1
3844 Xacid_1, TRUE, FALSE,
3848 Xacid_2, FALSE, FALSE,
3852 Xacid_3, FALSE, FALSE,
3856 Xacid_4, FALSE, FALSE,
3860 Xacid_5, FALSE, FALSE,
3864 Xacid_6, FALSE, FALSE,
3868 Xacid_7, FALSE, FALSE,
3872 Xacid_8, FALSE, FALSE,
3876 Xball_1, TRUE, FALSE,
3877 EL_EMC_MAGIC_BALL, -1, -1
3880 Xball_1B, FALSE, FALSE,
3881 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3884 Xball_2, FALSE, FALSE,
3885 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3888 Xball_2B, FALSE, FALSE,
3889 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3892 Yball_eat, FALSE, FALSE,
3893 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
3896 Ykey_1_eat, FALSE, FALSE,
3897 EL_EM_KEY_1, ACTION_COLLECTING, -1
3900 Ykey_2_eat, FALSE, FALSE,
3901 EL_EM_KEY_2, ACTION_COLLECTING, -1
3904 Ykey_3_eat, FALSE, FALSE,
3905 EL_EM_KEY_3, ACTION_COLLECTING, -1
3908 Ykey_4_eat, FALSE, FALSE,
3909 EL_EM_KEY_4, ACTION_COLLECTING, -1
3912 Ykey_5_eat, FALSE, FALSE,
3913 EL_EMC_KEY_5, ACTION_COLLECTING, -1
3916 Ykey_6_eat, FALSE, FALSE,
3917 EL_EMC_KEY_6, ACTION_COLLECTING, -1
3920 Ykey_7_eat, FALSE, FALSE,
3921 EL_EMC_KEY_7, ACTION_COLLECTING, -1
3924 Ykey_8_eat, FALSE, FALSE,
3925 EL_EMC_KEY_8, ACTION_COLLECTING, -1
3928 Ylenses_eat, FALSE, FALSE,
3929 EL_EMC_LENSES, ACTION_COLLECTING, -1
3932 Ymagnify_eat, FALSE, FALSE,
3933 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
3936 Ygrass_eat, FALSE, FALSE,
3937 EL_EMC_GRASS, ACTION_SNAPPING, -1
3940 Ydirt_eat, FALSE, FALSE,
3941 EL_SAND, ACTION_SNAPPING, -1
3944 Xgrow_ns, TRUE, FALSE,
3945 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
3948 Ygrow_ns_eat, FALSE, FALSE,
3949 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
3952 Xgrow_ew, TRUE, FALSE,
3953 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
3956 Ygrow_ew_eat, FALSE, FALSE,
3957 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
3960 Xwonderwall, TRUE, FALSE,
3961 EL_MAGIC_WALL, -1, -1
3964 XwonderwallB, FALSE, FALSE,
3965 EL_MAGIC_WALL, ACTION_ACTIVE, -1
3968 Xamoeba_1, TRUE, FALSE,
3969 EL_AMOEBA_DRY, ACTION_OTHER, -1
3972 Xamoeba_2, FALSE, FALSE,
3973 EL_AMOEBA_DRY, ACTION_OTHER, -1
3976 Xamoeba_3, FALSE, FALSE,
3977 EL_AMOEBA_DRY, ACTION_OTHER, -1
3980 Xamoeba_4, FALSE, FALSE,
3981 EL_AMOEBA_DRY, ACTION_OTHER, -1
3984 Xamoeba_5, TRUE, FALSE,
3985 EL_AMOEBA_WET, ACTION_OTHER, -1
3988 Xamoeba_6, FALSE, FALSE,
3989 EL_AMOEBA_WET, ACTION_OTHER, -1
3992 Xamoeba_7, FALSE, FALSE,
3993 EL_AMOEBA_WET, ACTION_OTHER, -1
3996 Xamoeba_8, FALSE, FALSE,
3997 EL_AMOEBA_WET, ACTION_OTHER, -1
4000 Xdoor_1, TRUE, FALSE,
4001 EL_EM_GATE_1, -1, -1
4004 Xdoor_2, TRUE, FALSE,
4005 EL_EM_GATE_2, -1, -1
4008 Xdoor_3, TRUE, FALSE,
4009 EL_EM_GATE_3, -1, -1
4012 Xdoor_4, TRUE, FALSE,
4013 EL_EM_GATE_4, -1, -1
4016 Xdoor_5, TRUE, FALSE,
4017 EL_EMC_GATE_5, -1, -1
4020 Xdoor_6, TRUE, FALSE,
4021 EL_EMC_GATE_6, -1, -1
4024 Xdoor_7, TRUE, FALSE,
4025 EL_EMC_GATE_7, -1, -1
4028 Xdoor_8, TRUE, FALSE,
4029 EL_EMC_GATE_8, -1, -1
4032 Xkey_1, TRUE, FALSE,
4036 Xkey_2, TRUE, FALSE,
4040 Xkey_3, TRUE, FALSE,
4044 Xkey_4, TRUE, FALSE,
4048 Xkey_5, TRUE, FALSE,
4049 EL_EMC_KEY_5, -1, -1
4052 Xkey_6, TRUE, FALSE,
4053 EL_EMC_KEY_6, -1, -1
4056 Xkey_7, TRUE, FALSE,
4057 EL_EMC_KEY_7, -1, -1
4060 Xkey_8, TRUE, FALSE,
4061 EL_EMC_KEY_8, -1, -1
4064 Xwind_n, TRUE, FALSE,
4065 EL_BALLOON_SWITCH_UP, -1, -1
4068 Xwind_e, TRUE, FALSE,
4069 EL_BALLOON_SWITCH_RIGHT, -1, -1
4072 Xwind_s, TRUE, FALSE,
4073 EL_BALLOON_SWITCH_DOWN, -1, -1
4076 Xwind_w, TRUE, FALSE,
4077 EL_BALLOON_SWITCH_LEFT, -1, -1
4080 Xwind_nesw, TRUE, FALSE,
4081 EL_BALLOON_SWITCH_ANY, -1, -1
4084 Xwind_stop, TRUE, FALSE,
4085 EL_BALLOON_SWITCH_NONE, -1, -1
4089 EL_EXIT_CLOSED, -1, -1
4092 Xexit_1, TRUE, FALSE,
4093 EL_EXIT_OPEN, -1, -1
4096 Xexit_2, FALSE, FALSE,
4097 EL_EXIT_OPEN, -1, -1
4100 Xexit_3, FALSE, FALSE,
4101 EL_EXIT_OPEN, -1, -1
4104 Xdynamite, TRUE, FALSE,
4105 EL_EM_DYNAMITE, -1, -1
4108 Ydynamite_eat, FALSE, FALSE,
4109 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4112 Xdynamite_1, TRUE, FALSE,
4113 EL_EM_DYNAMITE_ACTIVE, -1, -1
4116 Xdynamite_2, FALSE, FALSE,
4117 EL_EM_DYNAMITE_ACTIVE, -1, -1
4120 Xdynamite_3, FALSE, FALSE,
4121 EL_EM_DYNAMITE_ACTIVE, -1, -1
4124 Xdynamite_4, FALSE, FALSE,
4125 EL_EM_DYNAMITE_ACTIVE, -1, -1
4128 Xbumper, TRUE, FALSE,
4129 EL_EMC_SPRING_BUMPER, -1, -1
4132 XbumperB, FALSE, FALSE,
4133 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4136 Xwheel, TRUE, FALSE,
4137 EL_ROBOT_WHEEL, -1, -1
4140 XwheelB, FALSE, FALSE,
4141 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4144 Xswitch, TRUE, FALSE,
4145 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4148 XswitchB, FALSE, FALSE,
4149 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4153 EL_QUICKSAND_EMPTY, -1, -1
4156 Xsand_stone, TRUE, FALSE,
4157 EL_QUICKSAND_FULL, -1, -1
4160 Xsand_stonein_1, FALSE, FALSE,
4161 EL_ROCK, ACTION_FILLING, -1
4164 Xsand_stonein_2, FALSE, FALSE,
4165 EL_ROCK, ACTION_FILLING, -1
4168 Xsand_stonein_3, FALSE, FALSE,
4169 EL_ROCK, ACTION_FILLING, -1
4172 Xsand_stonein_4, FALSE, FALSE,
4173 EL_ROCK, ACTION_FILLING, -1
4176 Xsand_stonesand_1, FALSE, FALSE,
4177 EL_QUICKSAND_FULL, -1, -1
4180 Xsand_stonesand_2, FALSE, FALSE,
4181 EL_QUICKSAND_FULL, -1, -1
4184 Xsand_stonesand_3, FALSE, FALSE,
4185 EL_QUICKSAND_FULL, -1, -1
4188 Xsand_stonesand_4, FALSE, FALSE,
4189 EL_QUICKSAND_FULL, -1, -1
4192 Xsand_stoneout_1, FALSE, FALSE,
4193 EL_ROCK, ACTION_EMPTYING, -1
4196 Xsand_stoneout_2, FALSE, FALSE,
4197 EL_ROCK, ACTION_EMPTYING, -1
4200 Xsand_sandstone_1, FALSE, FALSE,
4201 EL_QUICKSAND_FULL, -1, -1
4204 Xsand_sandstone_2, FALSE, FALSE,
4205 EL_QUICKSAND_FULL, -1, -1
4208 Xsand_sandstone_3, FALSE, FALSE,
4209 EL_QUICKSAND_FULL, -1, -1
4212 Xsand_sandstone_4, FALSE, FALSE,
4213 EL_QUICKSAND_FULL, -1, -1
4216 Xplant, TRUE, FALSE,
4217 EL_EMC_PLANT, -1, -1
4220 Yplant, FALSE, FALSE,
4221 EL_EMC_PLANT, -1, -1
4224 Xlenses, TRUE, FALSE,
4225 EL_EMC_LENSES, -1, -1
4228 Xmagnify, TRUE, FALSE,
4229 EL_EMC_MAGNIFIER, -1, -1
4232 Xdripper, TRUE, FALSE,
4233 EL_EMC_DRIPPER, -1, -1
4236 XdripperB, FALSE, FALSE,
4237 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4240 Xfake_blank, TRUE, FALSE,
4241 EL_INVISIBLE_WALL, -1, -1
4244 Xfake_blankB, FALSE, FALSE,
4245 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4248 Xfake_grass, TRUE, FALSE,
4249 EL_EMC_FAKE_GRASS, -1, -1
4252 Xfake_grassB, FALSE, FALSE,
4253 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4256 Xfake_door_1, TRUE, FALSE,
4257 EL_EM_GATE_1_GRAY, -1, -1
4260 Xfake_door_2, TRUE, FALSE,
4261 EL_EM_GATE_2_GRAY, -1, -1
4264 Xfake_door_3, TRUE, FALSE,
4265 EL_EM_GATE_3_GRAY, -1, -1
4268 Xfake_door_4, TRUE, FALSE,
4269 EL_EM_GATE_4_GRAY, -1, -1
4272 Xfake_door_5, TRUE, FALSE,
4273 EL_EMC_GATE_5_GRAY, -1, -1
4276 Xfake_door_6, TRUE, FALSE,
4277 EL_EMC_GATE_6_GRAY, -1, -1
4280 Xfake_door_7, TRUE, FALSE,
4281 EL_EMC_GATE_7_GRAY, -1, -1
4284 Xfake_door_8, TRUE, FALSE,
4285 EL_EMC_GATE_8_GRAY, -1, -1
4288 Xfake_acid_1, TRUE, FALSE,
4289 EL_EMC_FAKE_ACID, -1, -1
4292 Xfake_acid_2, FALSE, FALSE,
4293 EL_EMC_FAKE_ACID, -1, -1
4296 Xfake_acid_3, FALSE, FALSE,
4297 EL_EMC_FAKE_ACID, -1, -1
4300 Xfake_acid_4, FALSE, FALSE,
4301 EL_EMC_FAKE_ACID, -1, -1
4304 Xfake_acid_5, FALSE, FALSE,
4305 EL_EMC_FAKE_ACID, -1, -1
4308 Xfake_acid_6, FALSE, FALSE,
4309 EL_EMC_FAKE_ACID, -1, -1
4312 Xfake_acid_7, FALSE, FALSE,
4313 EL_EMC_FAKE_ACID, -1, -1
4316 Xfake_acid_8, FALSE, FALSE,
4317 EL_EMC_FAKE_ACID, -1, -1
4320 Xsteel_1, TRUE, FALSE,
4321 EL_STEELWALL, -1, -1
4324 Xsteel_2, TRUE, FALSE,
4325 EL_EMC_STEELWALL_2, -1, -1
4328 Xsteel_3, TRUE, FALSE,
4329 EL_EMC_STEELWALL_3, -1, -1
4332 Xsteel_4, TRUE, FALSE,
4333 EL_EMC_STEELWALL_4, -1, -1
4336 Xwall_1, TRUE, FALSE,
4340 Xwall_2, TRUE, FALSE,
4341 EL_EMC_WALL_14, -1, -1
4344 Xwall_3, TRUE, FALSE,
4345 EL_EMC_WALL_15, -1, -1
4348 Xwall_4, TRUE, FALSE,
4349 EL_EMC_WALL_16, -1, -1
4352 Xround_wall_1, TRUE, FALSE,
4353 EL_WALL_SLIPPERY, -1, -1
4356 Xround_wall_2, TRUE, FALSE,
4357 EL_EMC_WALL_SLIPPERY_2, -1, -1
4360 Xround_wall_3, TRUE, FALSE,
4361 EL_EMC_WALL_SLIPPERY_3, -1, -1
4364 Xround_wall_4, TRUE, FALSE,
4365 EL_EMC_WALL_SLIPPERY_4, -1, -1
4368 Xdecor_1, TRUE, FALSE,
4369 EL_EMC_WALL_8, -1, -1
4372 Xdecor_2, TRUE, FALSE,
4373 EL_EMC_WALL_6, -1, -1
4376 Xdecor_3, TRUE, FALSE,
4377 EL_EMC_WALL_4, -1, -1
4380 Xdecor_4, TRUE, FALSE,
4381 EL_EMC_WALL_7, -1, -1
4384 Xdecor_5, TRUE, FALSE,
4385 EL_EMC_WALL_5, -1, -1
4388 Xdecor_6, TRUE, FALSE,
4389 EL_EMC_WALL_9, -1, -1
4392 Xdecor_7, TRUE, FALSE,
4393 EL_EMC_WALL_10, -1, -1
4396 Xdecor_8, TRUE, FALSE,
4397 EL_EMC_WALL_1, -1, -1
4400 Xdecor_9, TRUE, FALSE,
4401 EL_EMC_WALL_2, -1, -1
4404 Xdecor_10, TRUE, FALSE,
4405 EL_EMC_WALL_3, -1, -1
4408 Xdecor_11, TRUE, FALSE,
4409 EL_EMC_WALL_11, -1, -1
4412 Xdecor_12, TRUE, FALSE,
4413 EL_EMC_WALL_12, -1, -1
4416 Xalpha_0, TRUE, FALSE,
4417 EL_CHAR('0'), -1, -1
4420 Xalpha_1, TRUE, FALSE,
4421 EL_CHAR('1'), -1, -1
4424 Xalpha_2, TRUE, FALSE,
4425 EL_CHAR('2'), -1, -1
4428 Xalpha_3, TRUE, FALSE,
4429 EL_CHAR('3'), -1, -1
4432 Xalpha_4, TRUE, FALSE,
4433 EL_CHAR('4'), -1, -1
4436 Xalpha_5, TRUE, FALSE,
4437 EL_CHAR('5'), -1, -1
4440 Xalpha_6, TRUE, FALSE,
4441 EL_CHAR('6'), -1, -1
4444 Xalpha_7, TRUE, FALSE,
4445 EL_CHAR('7'), -1, -1
4448 Xalpha_8, TRUE, FALSE,
4449 EL_CHAR('8'), -1, -1
4452 Xalpha_9, TRUE, FALSE,
4453 EL_CHAR('9'), -1, -1
4456 Xalpha_excla, TRUE, FALSE,
4457 EL_CHAR('!'), -1, -1
4460 Xalpha_quote, TRUE, FALSE,
4461 EL_CHAR('"'), -1, -1
4464 Xalpha_comma, TRUE, FALSE,
4465 EL_CHAR(','), -1, -1
4468 Xalpha_minus, TRUE, FALSE,
4469 EL_CHAR('-'), -1, -1
4472 Xalpha_perio, TRUE, FALSE,
4473 EL_CHAR('.'), -1, -1
4476 Xalpha_colon, TRUE, FALSE,
4477 EL_CHAR(':'), -1, -1
4480 Xalpha_quest, TRUE, FALSE,
4481 EL_CHAR('?'), -1, -1
4484 Xalpha_a, TRUE, FALSE,
4485 EL_CHAR('A'), -1, -1
4488 Xalpha_b, TRUE, FALSE,
4489 EL_CHAR('B'), -1, -1
4492 Xalpha_c, TRUE, FALSE,
4493 EL_CHAR('C'), -1, -1
4496 Xalpha_d, TRUE, FALSE,
4497 EL_CHAR('D'), -1, -1
4500 Xalpha_e, TRUE, FALSE,
4501 EL_CHAR('E'), -1, -1
4504 Xalpha_f, TRUE, FALSE,
4505 EL_CHAR('F'), -1, -1
4508 Xalpha_g, TRUE, FALSE,
4509 EL_CHAR('G'), -1, -1
4512 Xalpha_h, TRUE, FALSE,
4513 EL_CHAR('H'), -1, -1
4516 Xalpha_i, TRUE, FALSE,
4517 EL_CHAR('I'), -1, -1
4520 Xalpha_j, TRUE, FALSE,
4521 EL_CHAR('J'), -1, -1
4524 Xalpha_k, TRUE, FALSE,
4525 EL_CHAR('K'), -1, -1
4528 Xalpha_l, TRUE, FALSE,
4529 EL_CHAR('L'), -1, -1
4532 Xalpha_m, TRUE, FALSE,
4533 EL_CHAR('M'), -1, -1
4536 Xalpha_n, TRUE, FALSE,
4537 EL_CHAR('N'), -1, -1
4540 Xalpha_o, TRUE, FALSE,
4541 EL_CHAR('O'), -1, -1
4544 Xalpha_p, TRUE, FALSE,
4545 EL_CHAR('P'), -1, -1
4548 Xalpha_q, TRUE, FALSE,
4549 EL_CHAR('Q'), -1, -1
4552 Xalpha_r, TRUE, FALSE,
4553 EL_CHAR('R'), -1, -1
4556 Xalpha_s, TRUE, FALSE,
4557 EL_CHAR('S'), -1, -1
4560 Xalpha_t, TRUE, FALSE,
4561 EL_CHAR('T'), -1, -1
4564 Xalpha_u, TRUE, FALSE,
4565 EL_CHAR('U'), -1, -1
4568 Xalpha_v, TRUE, FALSE,
4569 EL_CHAR('V'), -1, -1
4572 Xalpha_w, TRUE, FALSE,
4573 EL_CHAR('W'), -1, -1
4576 Xalpha_x, TRUE, FALSE,
4577 EL_CHAR('X'), -1, -1
4580 Xalpha_y, TRUE, FALSE,
4581 EL_CHAR('Y'), -1, -1
4584 Xalpha_z, TRUE, FALSE,
4585 EL_CHAR('Z'), -1, -1
4588 Xalpha_arrow_e, TRUE, FALSE,
4589 EL_CHAR('>'), -1, -1
4592 Xalpha_arrow_w, TRUE, FALSE,
4593 EL_CHAR('<'), -1, -1
4596 Xalpha_copyr, TRUE, FALSE,
4597 EL_CHAR('©'), -1, -1
4600 Xalpha_copyr, TRUE, FALSE,
4601 EL_CHAR('©'), -1, -1
4605 Xboom_bug, FALSE, FALSE,
4606 EL_BUG, ACTION_EXPLODING, -1
4609 Xboom_bomb, FALSE, FALSE,
4610 EL_BOMB, ACTION_EXPLODING, -1
4613 Xboom_android, FALSE, FALSE,
4614 EL_EMC_ANDROID, ACTION_OTHER, -1
4617 Xboom_1, FALSE, FALSE,
4618 EL_DEFAULT, ACTION_EXPLODING, -1
4621 Xboom_2, FALSE, FALSE,
4622 EL_DEFAULT, ACTION_EXPLODING, -1
4625 Znormal, FALSE, FALSE,
4629 Zdynamite, FALSE, FALSE,
4633 Zplayer, FALSE, FALSE,
4637 ZBORDER, FALSE, FALSE,
4647 static struct Mapping_EM_to_RND_player
4656 em_player_mapping_list[] =
4660 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4664 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4668 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4672 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4676 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4680 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4684 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4688 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4692 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4696 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4700 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4704 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4708 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4712 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4716 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4720 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4724 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4728 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4732 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4736 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4740 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4744 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4748 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4752 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4756 EL_PLAYER_1, ACTION_DEFAULT, -1,
4760 EL_PLAYER_2, ACTION_DEFAULT, -1,
4764 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4768 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4772 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4776 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4780 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4784 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4788 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4792 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4796 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4800 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4804 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4808 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4812 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4816 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4820 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4824 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4828 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4832 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4836 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4840 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4844 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4848 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4852 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4856 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
4860 EL_PLAYER_3, ACTION_DEFAULT, -1,
4864 EL_PLAYER_4, ACTION_DEFAULT, -1,
4873 int map_element_RND_to_EM(int element_rnd)
4875 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4876 static boolean mapping_initialized = FALSE;
4878 if (!mapping_initialized)
4882 /* return "Xalpha_quest" for all undefined elements in mapping array */
4883 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4884 mapping_RND_to_EM[i] = Xalpha_quest;
4886 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4887 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
4888 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
4889 em_object_mapping_list[i].element_em;
4891 mapping_initialized = TRUE;
4894 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4895 return mapping_RND_to_EM[element_rnd];
4897 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4902 int map_element_EM_to_RND(int element_em)
4904 static unsigned short mapping_EM_to_RND[TILE_MAX];
4905 static boolean mapping_initialized = FALSE;
4907 if (!mapping_initialized)
4911 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
4912 for (i = 0; i < TILE_MAX; i++)
4913 mapping_EM_to_RND[i] = EL_UNKNOWN;
4915 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4916 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
4917 em_object_mapping_list[i].element_rnd;
4919 mapping_initialized = TRUE;
4922 if (element_em >= 0 && element_em < TILE_MAX)
4923 return mapping_EM_to_RND[element_em];
4925 Error(ERR_WARN, "invalid EM level element %d", element_em);
4930 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
4932 struct LevelInfo_EM *level_em = level->native_em_level;
4933 struct LEVEL *lev = level_em->lev;
4936 for (i = 0; i < TILE_MAX; i++)
4937 lev->android_array[i] = Xblank;
4939 for (i = 0; i < level->num_android_clone_elements; i++)
4941 int element_rnd = level->android_clone_element[i];
4942 int element_em = map_element_RND_to_EM(element_rnd);
4944 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
4945 if (em_object_mapping_list[j].element_rnd == element_rnd)
4946 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
4950 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
4952 struct LevelInfo_EM *level_em = level->native_em_level;
4953 struct LEVEL *lev = level_em->lev;
4956 level->num_android_clone_elements = 0;
4958 for (i = 0; i < TILE_MAX; i++)
4960 int element_em = lev->android_array[i];
4962 boolean element_found = FALSE;
4964 if (element_em == Xblank)
4967 element_rnd = map_element_EM_to_RND(element_em);
4969 for (j = 0; j < level->num_android_clone_elements; j++)
4970 if (level->android_clone_element[j] == element_rnd)
4971 element_found = TRUE;
4975 level->android_clone_element[level->num_android_clone_elements++] =
4978 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
4983 if (level->num_android_clone_elements == 0)
4985 level->num_android_clone_elements = 1;
4986 level->android_clone_element[0] = EL_EMPTY;
4990 int map_direction_RND_to_EM(int direction)
4992 return (direction == MV_UP ? 0 :
4993 direction == MV_RIGHT ? 1 :
4994 direction == MV_DOWN ? 2 :
4995 direction == MV_LEFT ? 3 :
4999 int map_direction_EM_to_RND(int direction)
5001 return (direction == 0 ? MV_UP :
5002 direction == 1 ? MV_RIGHT :
5003 direction == 2 ? MV_DOWN :
5004 direction == 3 ? MV_LEFT :
5008 int get_next_element(int element)
5012 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5013 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5014 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5015 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5016 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5017 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5018 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5020 default: return element;
5025 int el_act_dir2img(int element, int action, int direction)
5027 element = GFX_ELEMENT(element);
5029 if (direction == MV_NONE)
5030 return element_info[element].graphic[action];
5032 direction = MV_DIR_TO_BIT(direction);
5034 return element_info[element].direction_graphic[action][direction];
5037 int el_act_dir2img(int element, int action, int direction)
5039 element = GFX_ELEMENT(element);
5040 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5042 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5043 return element_info[element].direction_graphic[action][direction];
5048 static int el_act_dir2crm(int element, int action, int direction)
5050 element = GFX_ELEMENT(element);
5052 if (direction == MV_NONE)
5053 return element_info[element].crumbled[action];
5055 direction = MV_DIR_TO_BIT(direction);
5057 return element_info[element].direction_crumbled[action][direction];
5060 static int el_act_dir2crm(int element, int action, int direction)
5062 element = GFX_ELEMENT(element);
5063 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5065 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5066 return element_info[element].direction_crumbled[action][direction];
5070 int el_act2img(int element, int action)
5072 element = GFX_ELEMENT(element);
5074 return element_info[element].graphic[action];
5077 int el_act2crm(int element, int action)
5079 element = GFX_ELEMENT(element);
5081 return element_info[element].crumbled[action];
5084 int el_dir2img(int element, int direction)
5086 element = GFX_ELEMENT(element);
5088 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5091 int el2baseimg(int element)
5093 return element_info[element].graphic[ACTION_DEFAULT];
5096 int el2img(int element)
5098 element = GFX_ELEMENT(element);
5100 return element_info[element].graphic[ACTION_DEFAULT];
5103 int el2edimg(int element)
5105 element = GFX_ELEMENT(element);
5107 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5110 int el2preimg(int element)
5112 element = GFX_ELEMENT(element);
5114 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5117 int font2baseimg(int font_nr)
5119 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5122 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5124 int game_frame_delay_value;
5126 game_frame_delay_value =
5127 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5128 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5131 if (tape.playing && tape.warp_forward && !tape.pausing)
5132 game_frame_delay_value = 0;
5134 return game_frame_delay_value;
5137 int getCenteredPlayerNr_EM()
5139 if (game.centered_player_nr_next >= 0 &&
5140 !native_em_level.ply[game.centered_player_nr_next]->alive)
5141 game.centered_player_nr_next = game.centered_player_nr;
5143 if (game.centered_player_nr != game.centered_player_nr_next)
5144 game.centered_player_nr = game.centered_player_nr_next;
5146 return game.centered_player_nr;
5149 int getActivePlayers_EM()
5151 int num_players = 0;
5157 for (i = 0; i < MAX_PLAYERS; i++)
5158 if (tape.player_participates[i])
5164 unsigned int InitRND(long seed)
5166 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5167 return InitEngineRND_EM(seed);
5169 return InitEngineRND(seed);
5172 #define DEBUG_EM_GFX 0
5174 void InitGraphicInfo_EM(void)
5176 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5177 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5181 if (graphic_info_em_object[0][0].bitmap == NULL)
5183 /* EM graphics not yet initialized in em_open_all() */
5189 /* always start with reliable default values */
5190 for (i = 0; i < TILE_MAX; i++)
5192 object_mapping[i].element_rnd = EL_UNKNOWN;
5193 object_mapping[i].is_backside = FALSE;
5194 object_mapping[i].action = ACTION_DEFAULT;
5195 object_mapping[i].direction = MV_NONE;
5198 /* always start with reliable default values */
5199 for (p = 0; p < MAX_PLAYERS; p++)
5201 for (i = 0; i < SPR_MAX; i++)
5203 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5204 player_mapping[p][i].action = ACTION_DEFAULT;
5205 player_mapping[p][i].direction = MV_NONE;
5209 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5211 int e = em_object_mapping_list[i].element_em;
5213 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5214 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5216 if (em_object_mapping_list[i].action != -1)
5217 object_mapping[e].action = em_object_mapping_list[i].action;
5219 if (em_object_mapping_list[i].direction != -1)
5220 object_mapping[e].direction =
5221 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5224 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5226 int a = em_player_mapping_list[i].action_em;
5227 int p = em_player_mapping_list[i].player_nr;
5229 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5231 if (em_player_mapping_list[i].action != -1)
5232 player_mapping[p][a].action = em_player_mapping_list[i].action;
5234 if (em_player_mapping_list[i].direction != -1)
5235 player_mapping[p][a].direction =
5236 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5239 for (i = 0; i < TILE_MAX; i++)
5241 int element = object_mapping[i].element_rnd;
5242 int action = object_mapping[i].action;
5243 int direction = object_mapping[i].direction;
5244 boolean is_backside = object_mapping[i].is_backside;
5245 boolean action_removing = (action == ACTION_DIGGING ||
5246 action == ACTION_SNAPPING ||
5247 action == ACTION_COLLECTING);
5248 boolean action_exploding = ((action == ACTION_EXPLODING ||
5249 action == ACTION_SMASHED_BY_ROCK ||
5250 action == ACTION_SMASHED_BY_SPRING) &&
5251 element != EL_DIAMOND);
5252 boolean action_active = (action == ACTION_ACTIVE);
5253 boolean action_other = (action == ACTION_OTHER);
5255 for (j = 0; j < 8; j++)
5257 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5258 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5260 i == Xdrip_stretch ? element :
5261 i == Xdrip_stretchB ? element :
5262 i == Ydrip_s1 ? element :
5263 i == Ydrip_s1B ? element :
5264 i == Xball_1B ? element :
5265 i == Xball_2 ? element :
5266 i == Xball_2B ? element :
5267 i == Yball_eat ? element :
5268 i == Ykey_1_eat ? element :
5269 i == Ykey_2_eat ? element :
5270 i == Ykey_3_eat ? element :
5271 i == Ykey_4_eat ? element :
5272 i == Ykey_5_eat ? element :
5273 i == Ykey_6_eat ? element :
5274 i == Ykey_7_eat ? element :
5275 i == Ykey_8_eat ? element :
5276 i == Ylenses_eat ? element :
5277 i == Ymagnify_eat ? element :
5278 i == Ygrass_eat ? element :
5279 i == Ydirt_eat ? element :
5280 i == Yspring_kill_e ? EL_SPRING :
5281 i == Yspring_kill_w ? EL_SPRING :
5282 i == Yemerald_stone ? EL_EMERALD :
5283 i == Ydiamond_stone ? EL_ROCK :
5284 i == Xsand_stonein_4 ? EL_EMPTY :
5285 i == Xsand_stoneout_2 ? EL_ROCK :
5286 is_backside ? EL_EMPTY :
5287 action_removing ? EL_EMPTY :
5289 int effective_action = (j < 7 ? action :
5290 i == Xdrip_stretch ? action :
5291 i == Xdrip_stretchB ? action :
5292 i == Ydrip_s1 ? action :
5293 i == Ydrip_s1B ? action :
5294 i == Xball_1B ? action :
5295 i == Xball_2 ? action :
5296 i == Xball_2B ? action :
5297 i == Yball_eat ? action :
5298 i == Ykey_1_eat ? action :
5299 i == Ykey_2_eat ? action :
5300 i == Ykey_3_eat ? action :
5301 i == Ykey_4_eat ? action :
5302 i == Ykey_5_eat ? action :
5303 i == Ykey_6_eat ? action :
5304 i == Ykey_7_eat ? action :
5305 i == Ykey_8_eat ? action :
5306 i == Ylenses_eat ? action :
5307 i == Ymagnify_eat ? action :
5308 i == Ygrass_eat ? action :
5309 i == Ydirt_eat ? action :
5310 i == Xsand_stonein_1 ? action :
5311 i == Xsand_stonein_2 ? action :
5312 i == Xsand_stonein_3 ? action :
5313 i == Xsand_stonein_4 ? action :
5314 i == Xsand_stoneout_1 ? action :
5315 i == Xsand_stoneout_2 ? action :
5316 i == Xboom_android ? ACTION_EXPLODING :
5317 action_exploding ? ACTION_EXPLODING :
5318 action_active ? action :
5319 action_other ? action :
5321 int graphic = (el_act_dir2img(effective_element, effective_action,
5323 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5325 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5326 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5327 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5328 struct GraphicInfo *g = &graphic_info[graphic];
5329 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5332 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5333 boolean special_animation = (action != ACTION_DEFAULT &&
5334 g->anim_frames == 3 &&
5335 g->anim_delay == 2 &&
5336 g->anim_mode & ANIM_LINEAR);
5337 int sync_frame = (i == Xdrip_stretch ? 7 :
5338 i == Xdrip_stretchB ? 7 :
5339 i == Ydrip_s2 ? j + 8 :
5340 i == Ydrip_s2B ? j + 8 :
5349 i == Xfake_acid_1 ? 0 :
5350 i == Xfake_acid_2 ? 10 :
5351 i == Xfake_acid_3 ? 20 :
5352 i == Xfake_acid_4 ? 30 :
5353 i == Xfake_acid_5 ? 40 :
5354 i == Xfake_acid_6 ? 50 :
5355 i == Xfake_acid_7 ? 60 :
5356 i == Xfake_acid_8 ? 70 :
5358 i == Xball_2B ? j + 8 :
5359 i == Yball_eat ? j + 1 :
5360 i == Ykey_1_eat ? j + 1 :
5361 i == Ykey_2_eat ? j + 1 :
5362 i == Ykey_3_eat ? j + 1 :
5363 i == Ykey_4_eat ? j + 1 :
5364 i == Ykey_5_eat ? j + 1 :
5365 i == Ykey_6_eat ? j + 1 :
5366 i == Ykey_7_eat ? j + 1 :
5367 i == Ykey_8_eat ? j + 1 :
5368 i == Ylenses_eat ? j + 1 :
5369 i == Ymagnify_eat ? j + 1 :
5370 i == Ygrass_eat ? j + 1 :
5371 i == Ydirt_eat ? j + 1 :
5372 i == Xamoeba_1 ? 0 :
5373 i == Xamoeba_2 ? 1 :
5374 i == Xamoeba_3 ? 2 :
5375 i == Xamoeba_4 ? 3 :
5376 i == Xamoeba_5 ? 0 :
5377 i == Xamoeba_6 ? 1 :
5378 i == Xamoeba_7 ? 2 :
5379 i == Xamoeba_8 ? 3 :
5380 i == Xexit_2 ? j + 8 :
5381 i == Xexit_3 ? j + 16 :
5382 i == Xdynamite_1 ? 0 :
5383 i == Xdynamite_2 ? 8 :
5384 i == Xdynamite_3 ? 16 :
5385 i == Xdynamite_4 ? 24 :
5386 i == Xsand_stonein_1 ? j + 1 :
5387 i == Xsand_stonein_2 ? j + 9 :
5388 i == Xsand_stonein_3 ? j + 17 :
5389 i == Xsand_stonein_4 ? j + 25 :
5390 i == Xsand_stoneout_1 && j == 0 ? 0 :
5391 i == Xsand_stoneout_1 && j == 1 ? 0 :
5392 i == Xsand_stoneout_1 && j == 2 ? 1 :
5393 i == Xsand_stoneout_1 && j == 3 ? 2 :
5394 i == Xsand_stoneout_1 && j == 4 ? 2 :
5395 i == Xsand_stoneout_1 && j == 5 ? 3 :
5396 i == Xsand_stoneout_1 && j == 6 ? 4 :
5397 i == Xsand_stoneout_1 && j == 7 ? 4 :
5398 i == Xsand_stoneout_2 && j == 0 ? 5 :
5399 i == Xsand_stoneout_2 && j == 1 ? 6 :
5400 i == Xsand_stoneout_2 && j == 2 ? 7 :
5401 i == Xsand_stoneout_2 && j == 3 ? 8 :
5402 i == Xsand_stoneout_2 && j == 4 ? 9 :
5403 i == Xsand_stoneout_2 && j == 5 ? 11 :
5404 i == Xsand_stoneout_2 && j == 6 ? 13 :
5405 i == Xsand_stoneout_2 && j == 7 ? 15 :
5406 i == Xboom_bug && j == 1 ? 2 :
5407 i == Xboom_bug && j == 2 ? 2 :
5408 i == Xboom_bug && j == 3 ? 4 :
5409 i == Xboom_bug && j == 4 ? 4 :
5410 i == Xboom_bug && j == 5 ? 2 :
5411 i == Xboom_bug && j == 6 ? 2 :
5412 i == Xboom_bug && j == 7 ? 0 :
5413 i == Xboom_bomb && j == 1 ? 2 :
5414 i == Xboom_bomb && j == 2 ? 2 :
5415 i == Xboom_bomb && j == 3 ? 4 :
5416 i == Xboom_bomb && j == 4 ? 4 :
5417 i == Xboom_bomb && j == 5 ? 2 :
5418 i == Xboom_bomb && j == 6 ? 2 :
5419 i == Xboom_bomb && j == 7 ? 0 :
5420 i == Xboom_android && j == 7 ? 6 :
5421 i == Xboom_1 && j == 1 ? 2 :
5422 i == Xboom_1 && j == 2 ? 2 :
5423 i == Xboom_1 && j == 3 ? 4 :
5424 i == Xboom_1 && j == 4 ? 4 :
5425 i == Xboom_1 && j == 5 ? 6 :
5426 i == Xboom_1 && j == 6 ? 6 :
5427 i == Xboom_1 && j == 7 ? 8 :
5428 i == Xboom_2 && j == 0 ? 8 :
5429 i == Xboom_2 && j == 1 ? 8 :
5430 i == Xboom_2 && j == 2 ? 10 :
5431 i == Xboom_2 && j == 3 ? 10 :
5432 i == Xboom_2 && j == 4 ? 10 :
5433 i == Xboom_2 && j == 5 ? 12 :
5434 i == Xboom_2 && j == 6 ? 12 :
5435 i == Xboom_2 && j == 7 ? 12 :
5436 special_animation && j == 4 ? 3 :
5437 effective_action != action ? 0 :
5441 Bitmap *debug_bitmap = g_em->bitmap;
5442 int debug_src_x = g_em->src_x;
5443 int debug_src_y = g_em->src_y;
5446 int frame = getAnimationFrame(g->anim_frames,
5449 g->anim_start_frame,
5452 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5453 g->double_movement && is_backside);
5455 g_em->bitmap = src_bitmap;
5456 g_em->src_x = src_x;
5457 g_em->src_y = src_y;
5458 g_em->src_offset_x = 0;
5459 g_em->src_offset_y = 0;
5460 g_em->dst_offset_x = 0;
5461 g_em->dst_offset_y = 0;
5462 g_em->width = TILEX;
5463 g_em->height = TILEY;
5465 g_em->crumbled_bitmap = NULL;
5466 g_em->crumbled_src_x = 0;
5467 g_em->crumbled_src_y = 0;
5468 g_em->crumbled_border_size = 0;
5470 g_em->has_crumbled_graphics = FALSE;
5471 g_em->preserve_background = FALSE;
5474 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5475 printf("::: empty crumbled: %d [%s], %d, %d\n",
5476 effective_element, element_info[effective_element].token_name,
5477 effective_action, direction);
5480 /* if element can be crumbled, but certain action graphics are just empty
5481 space (like snapping sand with the original R'n'D graphics), do not
5482 treat these empty space graphics as crumbled graphics in EMC engine */
5483 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5485 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5487 g_em->has_crumbled_graphics = TRUE;
5488 g_em->crumbled_bitmap = src_bitmap;
5489 g_em->crumbled_src_x = src_x;
5490 g_em->crumbled_src_y = src_y;
5491 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5494 if (!g->double_movement && (effective_action == ACTION_FALLING ||
5495 effective_action == ACTION_MOVING ||
5496 effective_action == ACTION_PUSHING ||
5497 effective_action == ACTION_EATING))
5500 (effective_action == ACTION_FALLING ? MV_DOWN : direction);
5501 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5502 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5503 int num_steps = (i == Ydrip_s1 ||
5506 i == Ydrip_s2B ? 16 : 8);
5507 int cx = ABS(dx) * (TILEX / num_steps);
5508 int cy = ABS(dy) * (TILEY / num_steps);
5509 int step_frame = (i == Ydrip_s2 ||
5510 i == Ydrip_s2B ? j + 8 : j) + 1;
5511 int step = (is_backside ? step_frame : num_steps - step_frame);
5513 if (is_backside) /* tile where movement starts */
5515 if (dx < 0 || dy < 0)
5517 g_em->src_offset_x = cx * step;
5518 g_em->src_offset_y = cy * step;
5522 g_em->dst_offset_x = cx * step;
5523 g_em->dst_offset_y = cy * step;
5526 else /* tile where movement ends */
5528 if (dx < 0 || dy < 0)
5530 g_em->dst_offset_x = cx * step;
5531 g_em->dst_offset_y = cy * step;
5535 g_em->src_offset_x = cx * step;
5536 g_em->src_offset_y = cy * step;
5540 g_em->width = TILEX - cx * step;
5541 g_em->height = TILEY - cy * step;
5545 /* create unique graphic identifier to decide if tile must be redrawn */
5546 /* bit 31 - 16 (16 bit): EM style graphic
5547 bit 15 - 12 ( 4 bit): EM style frame
5548 bit 11 - 6 ( 6 bit): graphic width
5549 bit 5 - 0 ( 6 bit): graphic height */
5550 g_em->unique_identifier =
5551 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5553 /* create unique graphic identifier to decide if tile must be redrawn */
5554 /* bit 31 - 16 (16 bit): EM style element
5555 bit 15 - 12 ( 4 bit): EM style frame
5556 bit 11 - 6 ( 6 bit): graphic width
5557 bit 5 - 0 ( 6 bit): graphic height */
5558 g_em->unique_identifier =
5559 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5563 if (effective_element == EL_ROCK)
5564 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5565 effective_action, j, graphic, frame, g_em->unique_identifier);
5571 /* skip check for EMC elements not contained in original EMC artwork */
5572 if (element == EL_EMC_FAKE_ACID)
5576 if (g_em->bitmap != debug_bitmap ||
5577 g_em->src_x != debug_src_x ||
5578 g_em->src_y != debug_src_y ||
5579 g_em->src_offset_x != 0 ||
5580 g_em->src_offset_y != 0 ||
5581 g_em->dst_offset_x != 0 ||
5582 g_em->dst_offset_y != 0 ||
5583 g_em->width != TILEX ||
5584 g_em->height != TILEY)
5586 static int last_i = -1;
5594 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5595 i, element, element_info[element].token_name,
5596 element_action_info[effective_action].suffix, direction);
5598 if (element != effective_element)
5599 printf(" [%d ('%s')]",
5601 element_info[effective_element].token_name);
5605 if (g_em->bitmap != debug_bitmap)
5606 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5607 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5609 if (g_em->src_x != debug_src_x ||
5610 g_em->src_y != debug_src_y)
5611 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5612 j, (is_backside ? 'B' : 'F'),
5613 g_em->src_x, g_em->src_y,
5614 g_em->src_x / 32, g_em->src_y / 32,
5615 debug_src_x, debug_src_y,
5616 debug_src_x / 32, debug_src_y / 32);
5618 if (g_em->src_offset_x != 0 ||
5619 g_em->src_offset_y != 0 ||
5620 g_em->dst_offset_x != 0 ||
5621 g_em->dst_offset_y != 0)
5622 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5624 g_em->src_offset_x, g_em->src_offset_y,
5625 g_em->dst_offset_x, g_em->dst_offset_y);
5627 if (g_em->width != TILEX ||
5628 g_em->height != TILEY)
5629 printf(" %d (%d): size %d,%d should be %d,%d\n",
5631 g_em->width, g_em->height, TILEX, TILEY);
5638 for (i = 0; i < TILE_MAX; i++)
5640 for (j = 0; j < 8; j++)
5642 int element = object_mapping[i].element_rnd;
5643 int action = object_mapping[i].action;
5644 int direction = object_mapping[i].direction;
5645 boolean is_backside = object_mapping[i].is_backside;
5647 int graphic_action = el_act_dir2img(element, action, direction);
5648 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5650 int graphic_action = element_info[element].graphic[action];
5651 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5654 if ((action == ACTION_SMASHED_BY_ROCK ||
5655 action == ACTION_SMASHED_BY_SPRING ||
5656 action == ACTION_EATING) &&
5657 graphic_action == graphic_default)
5659 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5660 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5661 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5662 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5665 /* no separate animation for "smashed by rock" -- use rock instead */
5666 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5667 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5669 g_em->bitmap = g_xx->bitmap;
5670 g_em->src_x = g_xx->src_x;
5671 g_em->src_y = g_xx->src_y;
5672 g_em->src_offset_x = g_xx->src_offset_x;
5673 g_em->src_offset_y = g_xx->src_offset_y;
5674 g_em->dst_offset_x = g_xx->dst_offset_x;
5675 g_em->dst_offset_y = g_xx->dst_offset_y;
5676 g_em->width = g_xx->width;
5677 g_em->height = g_xx->height;
5679 g_em->unique_identifier = g_xx->unique_identifier;
5683 g_em->preserve_background = TRUE;
5688 for (p = 0; p < MAX_PLAYERS; p++)
5690 for (i = 0; i < SPR_MAX; i++)
5692 int element = player_mapping[p][i].element_rnd;
5693 int action = player_mapping[p][i].action;
5694 int direction = player_mapping[p][i].direction;
5696 for (j = 0; j < 8; j++)
5698 int effective_element = element;
5699 int effective_action = action;
5700 int graphic = (direction == MV_NONE ?
5701 el_act2img(effective_element, effective_action) :
5702 el_act_dir2img(effective_element, effective_action,
5704 struct GraphicInfo *g = &graphic_info[graphic];
5705 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5711 Bitmap *debug_bitmap = g_em->bitmap;
5712 int debug_src_x = g_em->src_x;
5713 int debug_src_y = g_em->src_y;
5716 int frame = getAnimationFrame(g->anim_frames,
5719 g->anim_start_frame,
5722 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5724 g_em->bitmap = src_bitmap;
5725 g_em->src_x = src_x;
5726 g_em->src_y = src_y;
5727 g_em->src_offset_x = 0;
5728 g_em->src_offset_y = 0;
5729 g_em->dst_offset_x = 0;
5730 g_em->dst_offset_y = 0;
5731 g_em->width = TILEX;
5732 g_em->height = TILEY;
5737 /* skip check for EMC elements not contained in original EMC artwork */
5738 if (element == EL_PLAYER_3 ||
5739 element == EL_PLAYER_4)
5743 if (g_em->bitmap != debug_bitmap ||
5744 g_em->src_x != debug_src_x ||
5745 g_em->src_y != debug_src_y)
5747 static int last_i = -1;
5755 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5756 p, i, element, element_info[element].token_name,
5757 element_action_info[effective_action].suffix, direction);
5759 if (element != effective_element)
5760 printf(" [%d ('%s')]",
5762 element_info[effective_element].token_name);
5766 if (g_em->bitmap != debug_bitmap)
5767 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5768 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5770 if (g_em->src_x != debug_src_x ||
5771 g_em->src_y != debug_src_y)
5772 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5774 g_em->src_x, g_em->src_y,
5775 g_em->src_x / 32, g_em->src_y / 32,
5776 debug_src_x, debug_src_y,
5777 debug_src_x / 32, debug_src_y / 32);