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 #define TILE_GFX_ELEMENT(x, y) \
907 (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ? \
908 GfxElement[x][y] : Feld[x][y])
910 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
914 int sx = SCREENX(x), sy = SCREENY(y);
916 int width, height, cx, cy, i;
917 int crumbled_border_size = graphic_info[graphic].border_size;
918 static int xy[4][2] =
926 if (!IN_LEV_FIELD(x, y))
929 element = TILE_GFX_ELEMENT(x, y);
931 /* crumble field itself */
932 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
934 if (!IN_SCR_FIELD(sx, sy))
937 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
939 for (i = 0; i < 4; i++)
941 int xx = x + xy[i][0];
942 int yy = y + xy[i][1];
944 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
947 /* check if neighbour field is of same type */
948 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
951 if (i == 1 || i == 2)
953 width = crumbled_border_size;
955 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
961 height = crumbled_border_size;
963 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
966 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
967 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
970 MarkTileDirty(sx, sy);
972 else /* crumble neighbour fields */
974 for (i = 0; i < 4; i++)
976 int xx = x + xy[i][0];
977 int yy = y + xy[i][1];
978 int sxx = sx + xy[i][0];
979 int syy = sy + xy[i][1];
982 if (!IN_LEV_FIELD(xx, yy) ||
983 !IN_SCR_FIELD(sxx, syy) ||
988 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
992 element = TILE_GFX_ELEMENT(xx, yy);
994 if (!GFX_CRUMBLED(element))
997 if (!IN_LEV_FIELD(xx, yy) ||
998 !IN_SCR_FIELD(sxx, syy) ||
999 !GFX_CRUMBLED(Feld[xx][yy]) ||
1005 graphic = el_act2crm(element, ACTION_DEFAULT);
1007 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1009 crumbled_border_size = graphic_info[graphic].border_size;
1011 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1013 if (i == 1 || i == 2)
1015 width = crumbled_border_size;
1017 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1023 height = crumbled_border_size;
1025 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1028 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1029 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1031 MarkTileDirty(sxx, syy);
1036 void DrawLevelFieldCrumbledSand(int x, int y)
1040 if (!IN_LEV_FIELD(x, y))
1044 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1045 GFX_CRUMBLED(GfxElement[x][y]))
1047 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1053 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1055 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1058 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1061 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1064 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1065 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1066 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1067 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1068 int sx = SCREENX(x), sy = SCREENY(y);
1070 DrawGraphic(sx, sy, graphic1, frame1);
1071 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1074 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1076 int sx = SCREENX(x), sy = SCREENY(y);
1077 static int xy[4][2] =
1086 for (i = 0; i < 4; i++)
1088 int xx = x + xy[i][0];
1089 int yy = y + xy[i][1];
1090 int sxx = sx + xy[i][0];
1091 int syy = sy + xy[i][1];
1093 if (!IN_LEV_FIELD(xx, yy) ||
1094 !IN_SCR_FIELD(sxx, syy) ||
1095 !GFX_CRUMBLED(Feld[xx][yy]) ||
1099 DrawLevelField(xx, yy);
1103 static int getBorderElement(int x, int y)
1107 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1108 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1109 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1110 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1111 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1112 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1113 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1115 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1116 int steel_position = (x == -1 && y == -1 ? 0 :
1117 x == lev_fieldx && y == -1 ? 1 :
1118 x == -1 && y == lev_fieldy ? 2 :
1119 x == lev_fieldx && y == lev_fieldy ? 3 :
1120 x == -1 || x == lev_fieldx ? 4 :
1121 y == -1 || y == lev_fieldy ? 5 : 6);
1123 return border[steel_position][steel_type];
1126 void DrawScreenElement(int x, int y, int element)
1128 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1129 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1132 void DrawLevelElement(int x, int y, int element)
1134 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1135 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1138 void DrawScreenField(int x, int y)
1140 int lx = LEVELX(x), ly = LEVELY(y);
1141 int element, content;
1143 if (!IN_LEV_FIELD(lx, ly))
1145 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1148 element = getBorderElement(lx, ly);
1150 DrawScreenElement(x, y, element);
1154 element = Feld[lx][ly];
1155 content = Store[lx][ly];
1157 if (IS_MOVING(lx, ly))
1159 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1160 boolean cut_mode = NO_CUTTING;
1162 if (element == EL_QUICKSAND_EMPTYING ||
1163 element == EL_MAGIC_WALL_EMPTYING ||
1164 element == EL_BD_MAGIC_WALL_EMPTYING ||
1165 element == EL_AMOEBA_DROPPING)
1166 cut_mode = CUT_ABOVE;
1167 else if (element == EL_QUICKSAND_FILLING ||
1168 element == EL_MAGIC_WALL_FILLING ||
1169 element == EL_BD_MAGIC_WALL_FILLING)
1170 cut_mode = CUT_BELOW;
1172 if (cut_mode == CUT_ABOVE)
1173 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1175 DrawScreenElement(x, y, EL_EMPTY);
1178 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1179 else if (cut_mode == NO_CUTTING)
1180 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1182 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1184 if (content == EL_ACID)
1186 int dir = MovDir[lx][ly];
1187 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1188 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1190 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1193 else if (IS_BLOCKED(lx, ly))
1198 boolean cut_mode = NO_CUTTING;
1199 int element_old, content_old;
1201 Blocked2Moving(lx, ly, &oldx, &oldy);
1204 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1205 MovDir[oldx][oldy] == MV_RIGHT);
1207 element_old = Feld[oldx][oldy];
1208 content_old = Store[oldx][oldy];
1210 if (element_old == EL_QUICKSAND_EMPTYING ||
1211 element_old == EL_MAGIC_WALL_EMPTYING ||
1212 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1213 element_old == EL_AMOEBA_DROPPING)
1214 cut_mode = CUT_ABOVE;
1216 DrawScreenElement(x, y, EL_EMPTY);
1219 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1221 else if (cut_mode == NO_CUTTING)
1222 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1225 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1228 else if (IS_DRAWABLE(element))
1229 DrawScreenElement(x, y, element);
1231 DrawScreenElement(x, y, EL_EMPTY);
1234 void DrawLevelField(int x, int y)
1236 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1237 DrawScreenField(SCREENX(x), SCREENY(y));
1238 else if (IS_MOVING(x, y))
1242 Moving2Blocked(x, y, &newx, &newy);
1243 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1244 DrawScreenField(SCREENX(newx), SCREENY(newy));
1246 else if (IS_BLOCKED(x, y))
1250 Blocked2Moving(x, y, &oldx, &oldy);
1251 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1252 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1256 void DrawMiniElement(int x, int y, int element)
1260 graphic = el2edimg(element);
1261 DrawMiniGraphic(x, y, graphic);
1264 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1266 int x = sx + scroll_x, y = sy + scroll_y;
1268 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1269 DrawMiniElement(sx, sy, EL_EMPTY);
1270 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1271 DrawMiniElement(sx, sy, Feld[x][y]);
1273 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1276 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1277 int x, int y, int xsize, int ysize, int font_nr)
1279 int font_width = getFontWidth(font_nr);
1280 int font_height = getFontHeight(font_nr);
1281 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1284 int dst_x = SX + startx + x * font_width;
1285 int dst_y = SY + starty + y * font_height;
1286 int width = graphic_info[graphic].width;
1287 int height = graphic_info[graphic].height;
1288 int inner_width = MAX(width - 2 * font_width, font_width);
1289 int inner_height = MAX(height - 2 * font_height, font_height);
1290 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1291 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1292 boolean draw_masked = graphic_info[graphic].draw_masked;
1294 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1296 if (src_bitmap == NULL || width < font_width || height < font_height)
1298 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1302 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1303 inner_sx + (x - 1) * font_width % inner_width);
1304 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1305 inner_sy + (y - 1) * font_height % inner_height);
1309 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1310 dst_x - src_x, dst_y - src_y);
1311 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1315 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1319 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1321 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1322 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1323 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1324 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1325 boolean no_delay = (tape.warp_forward);
1326 unsigned long anim_delay = 0;
1327 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1328 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1329 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1330 int font_width = getFontWidth(font_nr);
1331 int font_height = getFontHeight(font_nr);
1332 int max_xsize = level.envelope_xsize[envelope_nr];
1333 int max_ysize = level.envelope_ysize[envelope_nr];
1334 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1335 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1336 int xend = max_xsize;
1337 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1338 int xstep = (xstart < xend ? 1 : 0);
1339 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1342 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1344 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1345 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1346 int sx = (SXSIZE - xsize * font_width) / 2;
1347 int sy = (SYSIZE - ysize * font_height) / 2;
1350 SetDrawtoField(DRAW_BUFFERED);
1352 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1354 SetDrawtoField(DRAW_BACKBUFFER);
1356 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1357 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1359 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1360 level.envelope_text[envelope_nr], font_nr, max_xsize,
1361 xsize - 2, ysize - 2, mask_mode);
1363 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1366 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1370 void ShowEnvelope(int envelope_nr)
1372 int element = EL_ENVELOPE_1 + envelope_nr;
1373 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1374 int sound_opening = element_info[element].sound[ACTION_OPENING];
1375 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1376 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1377 boolean no_delay = (tape.warp_forward);
1378 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1379 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1380 int anim_mode = graphic_info[graphic].anim_mode;
1381 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1382 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1384 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1386 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1388 if (anim_mode == ANIM_DEFAULT)
1389 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1391 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1394 Delay(wait_delay_value);
1396 WaitForEventToContinue();
1398 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1400 if (anim_mode != ANIM_NONE)
1401 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1403 if (anim_mode == ANIM_DEFAULT)
1404 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1406 game.envelope_active = FALSE;
1408 SetDrawtoField(DRAW_BUFFERED);
1410 redraw_mask |= REDRAW_FIELD;
1414 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1416 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1417 int mini_startx = src_bitmap->width * 3 / 4;
1418 int mini_starty = src_bitmap->height * 2 / 3;
1419 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1420 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1422 *bitmap = src_bitmap;
1427 void DrawMicroElement(int xpos, int ypos, int element)
1431 int graphic = el2preimg(element);
1433 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1434 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1442 SetDrawBackgroundMask(REDRAW_NONE);
1445 for (x = BX1; x <= BX2; x++)
1446 for (y = BY1; y <= BY2; y++)
1447 DrawScreenField(x, y);
1449 redraw_mask |= REDRAW_FIELD;
1452 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1456 for (x = 0; x < size_x; x++)
1457 for (y = 0; y < size_y; y++)
1458 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1460 redraw_mask |= REDRAW_FIELD;
1463 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1467 DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
1469 if (lev_fieldx < STD_LEV_FIELDX)
1470 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1471 if (lev_fieldy < STD_LEV_FIELDY)
1472 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1474 xpos += MICRO_TILEX;
1475 ypos += MICRO_TILEY;
1477 for (x = -1; x <= STD_LEV_FIELDX; x++)
1479 for (y = -1; y <= STD_LEV_FIELDY; y++)
1481 int lx = from_x + x, ly = from_y + y;
1483 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1484 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1485 level.field[lx][ly]);
1486 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1487 && BorderElement != EL_EMPTY)
1488 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1489 getBorderElement(lx, ly));
1493 redraw_mask |= REDRAW_MICROLEVEL;
1496 #define MICROLABEL_EMPTY 0
1497 #define MICROLABEL_LEVEL_NAME 1
1498 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1499 #define MICROLABEL_LEVEL_AUTHOR 3
1500 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1501 #define MICROLABEL_IMPORTED_FROM 5
1502 #define MICROLABEL_IMPORTED_BY_HEAD 6
1503 #define MICROLABEL_IMPORTED_BY 7
1505 static void DrawMicroLevelLabelExt(int mode)
1507 char label_text[MAX_OUTPUT_LINESIZE + 1];
1508 int max_len_label_text;
1509 int font_nr = FONT_TEXT_2;
1512 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1513 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1514 mode == MICROLABEL_IMPORTED_BY_HEAD)
1515 font_nr = FONT_TEXT_3;
1517 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1519 for (i = 0; i < max_len_label_text; i++)
1520 label_text[i] = ' ';
1521 label_text[max_len_label_text] = '\0';
1523 if (strlen(label_text) > 0)
1525 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1526 int lypos = MICROLABEL2_YPOS;
1528 DrawText(lxpos, lypos, label_text, font_nr);
1532 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1533 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1534 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1535 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1536 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1537 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1538 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1539 max_len_label_text);
1540 label_text[max_len_label_text] = '\0';
1542 if (strlen(label_text) > 0)
1544 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1545 int lypos = MICROLABEL2_YPOS;
1547 DrawText(lxpos, lypos, label_text, font_nr);
1550 redraw_mask |= REDRAW_MICROLEVEL;
1553 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1555 static unsigned long scroll_delay = 0;
1556 static unsigned long label_delay = 0;
1557 static int from_x, from_y, scroll_direction;
1558 static int label_state, label_counter;
1559 int last_game_status = game_status; /* save current game status */
1561 /* force PREVIEW font on preview level */
1562 game_status = GAME_MODE_PSEUDO_PREVIEW;
1566 from_x = from_y = 0;
1567 scroll_direction = MV_RIGHT;
1571 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1572 DrawMicroLevelLabelExt(label_state);
1574 /* initialize delay counters */
1575 DelayReached(&scroll_delay, 0);
1576 DelayReached(&label_delay, 0);
1578 if (leveldir_current->name)
1580 char label_text[MAX_OUTPUT_LINESIZE + 1];
1581 int font_nr = FONT_TEXT_1;
1582 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1585 strncpy(label_text, leveldir_current->name, max_len_label_text);
1586 label_text[max_len_label_text] = '\0';
1588 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1589 lypos = SY + MICROLABEL1_YPOS;
1591 DrawText(lxpos, lypos, label_text, font_nr);
1594 game_status = last_game_status; /* restore current game status */
1599 /* scroll micro level, if needed */
1600 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1601 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1603 switch (scroll_direction)
1609 scroll_direction = MV_UP;
1613 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1616 scroll_direction = MV_DOWN;
1623 scroll_direction = MV_RIGHT;
1627 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1630 scroll_direction = MV_LEFT;
1637 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1640 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1641 /* redraw micro level label, if needed */
1642 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1643 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1644 strcmp(level.author, leveldir_current->name) != 0 &&
1645 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1647 int max_label_counter = 23;
1649 if (leveldir_current->imported_from != NULL &&
1650 strlen(leveldir_current->imported_from) > 0)
1651 max_label_counter += 14;
1652 if (leveldir_current->imported_by != NULL &&
1653 strlen(leveldir_current->imported_by) > 0)
1654 max_label_counter += 14;
1656 label_counter = (label_counter + 1) % max_label_counter;
1657 label_state = (label_counter >= 0 && label_counter <= 7 ?
1658 MICROLABEL_LEVEL_NAME :
1659 label_counter >= 9 && label_counter <= 12 ?
1660 MICROLABEL_LEVEL_AUTHOR_HEAD :
1661 label_counter >= 14 && label_counter <= 21 ?
1662 MICROLABEL_LEVEL_AUTHOR :
1663 label_counter >= 23 && label_counter <= 26 ?
1664 MICROLABEL_IMPORTED_FROM_HEAD :
1665 label_counter >= 28 && label_counter <= 35 ?
1666 MICROLABEL_IMPORTED_FROM :
1667 label_counter >= 37 && label_counter <= 40 ?
1668 MICROLABEL_IMPORTED_BY_HEAD :
1669 label_counter >= 42 && label_counter <= 49 ?
1670 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1672 if (leveldir_current->imported_from == NULL &&
1673 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1674 label_state == MICROLABEL_IMPORTED_FROM))
1675 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1676 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1678 DrawMicroLevelLabelExt(label_state);
1681 game_status = last_game_status; /* restore current game status */
1684 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1685 int graphic, int sync_frame, int mask_mode)
1687 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1689 if (mask_mode == USE_MASKING)
1690 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1692 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1695 inline void DrawGraphicAnimation(int x, int y, int graphic)
1697 int lx = LEVELX(x), ly = LEVELY(y);
1699 if (!IN_SCR_FIELD(x, y))
1702 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1703 graphic, GfxFrame[lx][ly], NO_MASKING);
1704 MarkTileDirty(x, y);
1707 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1709 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1712 void DrawLevelElementAnimation(int x, int y, int element)
1714 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1716 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1719 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1721 int sx = SCREENX(x), sy = SCREENY(y);
1723 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1726 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1729 DrawGraphicAnimation(sx, sy, graphic);
1732 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1733 DrawLevelFieldCrumbledSand(x, y);
1735 if (GFX_CRUMBLED(Feld[x][y]))
1736 DrawLevelFieldCrumbledSand(x, y);
1740 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1742 int sx = SCREENX(x), sy = SCREENY(y);
1745 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1748 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1750 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1753 DrawGraphicAnimation(sx, sy, graphic);
1755 if (GFX_CRUMBLED(element))
1756 DrawLevelFieldCrumbledSand(x, y);
1759 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1761 if (player->use_murphy)
1763 /* this works only because currently only one player can be "murphy" ... */
1764 static int last_horizontal_dir = MV_LEFT;
1765 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1767 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1768 last_horizontal_dir = move_dir;
1770 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1772 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1774 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1780 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1783 static boolean equalGraphics(int graphic1, int graphic2)
1785 struct GraphicInfo *g1 = &graphic_info[graphic1];
1786 struct GraphicInfo *g2 = &graphic_info[graphic2];
1788 return (g1->bitmap == g2->bitmap &&
1789 g1->src_x == g2->src_x &&
1790 g1->src_y == g2->src_y &&
1791 g1->anim_frames == g2->anim_frames &&
1792 g1->anim_delay == g2->anim_delay &&
1793 g1->anim_mode == g2->anim_mode);
1796 void DrawAllPlayers()
1800 for (i = 0; i < MAX_PLAYERS; i++)
1801 if (stored_player[i].active)
1802 DrawPlayer(&stored_player[i]);
1805 void DrawPlayerField(int x, int y)
1807 if (!IS_PLAYER(x, y))
1810 DrawPlayer(PLAYERINFO(x, y));
1813 void DrawPlayer(struct PlayerInfo *player)
1815 int jx = player->jx;
1816 int jy = player->jy;
1817 int move_dir = player->MovDir;
1818 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1819 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1820 int last_jx = (player->is_moving ? jx - dx : jx);
1821 int last_jy = (player->is_moving ? jy - dy : jy);
1822 int next_jx = jx + dx;
1823 int next_jy = jy + dy;
1824 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1825 int sx = SCREENX(jx), sy = SCREENY(jy);
1826 int sxx = 0, syy = 0;
1827 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1829 int action = ACTION_DEFAULT;
1830 int last_player_graphic = getPlayerGraphic(player, move_dir);
1831 int last_player_frame = player->Frame;
1835 /* GfxElement[][] is set to the element the player is digging or collecting;
1836 remove also for off-screen player if the player is not moving anymore */
1837 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1838 GfxElement[jx][jy] = EL_UNDEFINED;
1841 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1845 if (!IN_LEV_FIELD(jx, jy))
1847 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1848 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1849 printf("DrawPlayerField(): This should never happen!\n");
1854 if (element == EL_EXPLOSION)
1857 action = (player->is_pushing ? ACTION_PUSHING :
1858 player->is_digging ? ACTION_DIGGING :
1859 player->is_collecting ? ACTION_COLLECTING :
1860 player->is_moving ? ACTION_MOVING :
1861 player->is_snapping ? ACTION_SNAPPING :
1862 player->is_dropping ? ACTION_DROPPING :
1863 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1865 InitPlayerGfxAnimation(player, action, move_dir);
1867 /* ----------------------------------------------------------------------- */
1868 /* draw things in the field the player is leaving, if needed */
1869 /* ----------------------------------------------------------------------- */
1871 if (player->is_moving)
1873 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1875 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1877 if (last_element == EL_DYNAMITE_ACTIVE ||
1878 last_element == EL_EM_DYNAMITE_ACTIVE ||
1879 last_element == EL_SP_DISK_RED_ACTIVE)
1880 DrawDynamite(last_jx, last_jy);
1882 DrawLevelFieldThruMask(last_jx, last_jy);
1884 else if (last_element == EL_DYNAMITE_ACTIVE ||
1885 last_element == EL_EM_DYNAMITE_ACTIVE ||
1886 last_element == EL_SP_DISK_RED_ACTIVE)
1887 DrawDynamite(last_jx, last_jy);
1889 DrawLevelField(last_jx, last_jy);
1891 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
1892 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
1895 if (!IN_SCR_FIELD(sx, sy))
1898 if (setup.direct_draw)
1899 SetDrawtoField(DRAW_BUFFERED);
1901 /* ----------------------------------------------------------------------- */
1902 /* draw things behind the player, if needed */
1903 /* ----------------------------------------------------------------------- */
1906 DrawLevelElement(jx, jy, Back[jx][jy]);
1907 else if (IS_ACTIVE_BOMB(element))
1908 DrawLevelElement(jx, jy, EL_EMPTY);
1911 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
1913 if (GFX_CRUMBLED(GfxElement[jx][jy]))
1914 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
1917 int old_element = GfxElement[jx][jy];
1918 int old_graphic = el_act_dir2img(old_element, action, move_dir);
1919 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
1921 DrawGraphic(sx, sy, old_graphic, frame);
1926 GfxElement[jx][jy] = EL_UNDEFINED;
1928 /* make sure that pushed elements are drawn with correct frame rate */
1929 if (player->is_pushing && player->is_moving)
1930 GfxFrame[jx][jy] = player->StepFrame;
1932 DrawLevelField(jx, jy);
1936 /* ----------------------------------------------------------------------- */
1937 /* draw player himself */
1938 /* ----------------------------------------------------------------------- */
1940 graphic = getPlayerGraphic(player, move_dir);
1942 /* in the case of changed player action or direction, prevent the current
1943 animation frame from being restarted for identical animations */
1944 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
1945 player->Frame = last_player_frame;
1947 frame = getGraphicAnimationFrame(graphic, player->Frame);
1951 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1952 sxx = player->GfxPos;
1954 syy = player->GfxPos;
1957 if (!setup.soft_scrolling && ScreenMovPos)
1960 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1962 if (SHIELD_ON(player))
1964 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
1965 IMG_SHIELD_NORMAL_ACTIVE);
1966 int frame = getGraphicAnimationFrame(graphic, -1);
1968 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1971 /* ----------------------------------------------------------------------- */
1972 /* draw things the player is pushing, if needed */
1973 /* ----------------------------------------------------------------------- */
1976 printf("::: %d, %d [%d, %d] [%d]\n",
1977 player->is_pushing, player_is_moving, player->GfxAction,
1978 player->is_moving, player_is_moving);
1982 if (player->is_pushing && player->is_moving)
1984 int px = SCREENX(jx), py = SCREENY(jy);
1985 int pxx = (TILEX - ABS(sxx)) * dx;
1986 int pyy = (TILEY - ABS(syy)) * dy;
1991 if (!IS_MOVING(jx, jy)) /* push movement already finished */
1992 element = Feld[next_jx][next_jy];
1994 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
1995 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
1997 /* draw background element under pushed element (like the Sokoban field) */
1998 if (Back[next_jx][next_jy])
1999 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2001 /* masked drawing is needed for EMC style (double) movement graphics */
2002 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2006 /* ----------------------------------------------------------------------- */
2007 /* draw things in front of player (active dynamite or dynabombs) */
2008 /* ----------------------------------------------------------------------- */
2010 if (IS_ACTIVE_BOMB(element))
2012 graphic = el2img(element);
2013 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2015 if (game.emulation == EMU_SUPAPLEX)
2016 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2018 DrawGraphicThruMask(sx, sy, graphic, frame);
2021 if (player_is_moving && last_element == EL_EXPLOSION)
2023 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
2024 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2025 int phase = ExplodePhase[last_jx][last_jy] - 1;
2026 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2029 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2032 /* ----------------------------------------------------------------------- */
2033 /* draw elements the player is just walking/passing through/under */
2034 /* ----------------------------------------------------------------------- */
2036 if (player_is_moving)
2038 /* handle the field the player is leaving ... */
2039 if (IS_ACCESSIBLE_INSIDE(last_element))
2040 DrawLevelField(last_jx, last_jy);
2041 else if (IS_ACCESSIBLE_UNDER(last_element))
2042 DrawLevelFieldThruMask(last_jx, last_jy);
2045 /* do not redraw accessible elements if the player is just pushing them */
2046 if (!player_is_moving || !player->is_pushing)
2048 /* ... and the field the player is entering */
2049 if (IS_ACCESSIBLE_INSIDE(element))
2050 DrawLevelField(jx, jy);
2051 else if (IS_ACCESSIBLE_UNDER(element))
2052 DrawLevelFieldThruMask(jx, jy);
2055 if (setup.direct_draw)
2057 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2058 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2059 int x_size = TILEX * (1 + ABS(jx - last_jx));
2060 int y_size = TILEY * (1 + ABS(jy - last_jy));
2062 BlitBitmap(drawto_field, window,
2063 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2064 SetDrawtoField(DRAW_DIRECT);
2067 MarkTileDirty(sx, sy);
2070 /* ------------------------------------------------------------------------- */
2072 void WaitForEventToContinue()
2074 boolean still_wait = TRUE;
2076 /* simulate releasing mouse button over last gadget, if still pressed */
2078 HandleGadgets(-1, -1, 0);
2080 button_status = MB_RELEASED;
2092 case EVENT_BUTTONPRESS:
2093 case EVENT_KEYPRESS:
2097 case EVENT_KEYRELEASE:
2098 ClearPlayerAction();
2102 HandleOtherEvents(&event);
2106 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2113 /* don't eat all CPU time */
2118 #define MAX_REQUEST_LINES 13
2119 #define MAX_REQUEST_LINE_FONT1_LEN 7
2120 #define MAX_REQUEST_LINE_FONT2_LEN 10
2122 boolean Request(char *text, unsigned int req_state)
2124 int mx, my, ty, result = -1;
2125 unsigned int old_door_state;
2126 int last_game_status = game_status; /* save current game status */
2127 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2128 int font_nr = FONT_TEXT_2;
2129 int max_word_len = 0;
2132 for (text_ptr = text; *text_ptr; text_ptr++)
2134 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2136 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2138 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2139 font_nr = FONT_LEVEL_NUMBER;
2145 if (game_status == GAME_MODE_PLAYING &&
2146 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2147 BlitScreenToBitmap_EM(backbuffer);
2149 /* disable deactivated drawing when quick-loading level tape recording */
2150 if (tape.playing && tape.deactivate_display)
2151 TapeDeactivateDisplayOff(TRUE);
2153 SetMouseCursor(CURSOR_DEFAULT);
2155 #if defined(NETWORK_AVALIABLE)
2156 /* pause network game while waiting for request to answer */
2157 if (options.network &&
2158 game_status == GAME_MODE_PLAYING &&
2159 req_state & REQUEST_WAIT_FOR_INPUT)
2160 SendToServer_PausePlaying();
2163 old_door_state = GetDoorState();
2165 /* simulate releasing mouse button over last gadget, if still pressed */
2167 HandleGadgets(-1, -1, 0);
2171 if (old_door_state & DOOR_OPEN_1)
2173 CloseDoor(DOOR_CLOSE_1);
2175 /* save old door content */
2176 BlitBitmap(bitmap_db_door, bitmap_db_door,
2177 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2178 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2181 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2183 /* clear door drawing field */
2184 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2186 /* force DOOR font on preview level */
2187 game_status = GAME_MODE_PSEUDO_DOOR;
2189 /* write text for request */
2190 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2192 char text_line[max_request_line_len + 1];
2198 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2201 if (!tc || tc == ' ')
2212 strncpy(text_line, text, tl);
2215 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2216 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2217 text_line, font_nr);
2219 text += tl + (tc == ' ' ? 1 : 0);
2222 game_status = last_game_status; /* restore current game status */
2224 if (req_state & REQ_ASK)
2226 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2227 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2229 else if (req_state & REQ_CONFIRM)
2231 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2233 else if (req_state & REQ_PLAYER)
2235 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2236 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2237 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2238 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2241 /* copy request gadgets to door backbuffer */
2242 BlitBitmap(drawto, bitmap_db_door,
2243 DX, DY, DXSIZE, DYSIZE,
2244 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2246 OpenDoor(DOOR_OPEN_1);
2248 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2250 SetDrawBackgroundMask(REDRAW_FIELD);
2255 if (game_status != GAME_MODE_MAIN)
2258 button_status = MB_RELEASED;
2260 request_gadget_id = -1;
2262 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2274 case EVENT_BUTTONPRESS:
2275 case EVENT_BUTTONRELEASE:
2276 case EVENT_MOTIONNOTIFY:
2278 if (event.type == EVENT_MOTIONNOTIFY)
2280 if (!PointerInWindow(window))
2281 continue; /* window and pointer are on different screens */
2286 motion_status = TRUE;
2287 mx = ((MotionEvent *) &event)->x;
2288 my = ((MotionEvent *) &event)->y;
2292 motion_status = FALSE;
2293 mx = ((ButtonEvent *) &event)->x;
2294 my = ((ButtonEvent *) &event)->y;
2295 if (event.type == EVENT_BUTTONPRESS)
2296 button_status = ((ButtonEvent *) &event)->button;
2298 button_status = MB_RELEASED;
2301 /* this sets 'request_gadget_id' */
2302 HandleGadgets(mx, my, button_status);
2304 switch(request_gadget_id)
2306 case TOOL_CTRL_ID_YES:
2309 case TOOL_CTRL_ID_NO:
2312 case TOOL_CTRL_ID_CONFIRM:
2313 result = TRUE | FALSE;
2316 case TOOL_CTRL_ID_PLAYER_1:
2319 case TOOL_CTRL_ID_PLAYER_2:
2322 case TOOL_CTRL_ID_PLAYER_3:
2325 case TOOL_CTRL_ID_PLAYER_4:
2336 case EVENT_KEYPRESS:
2337 switch(GetEventKey((KeyEvent *)&event, TRUE))
2350 if (req_state & REQ_PLAYER)
2354 case EVENT_KEYRELEASE:
2355 ClearPlayerAction();
2359 HandleOtherEvents(&event);
2363 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2365 int joy = AnyJoystick();
2367 if (joy & JOY_BUTTON_1)
2369 else if (joy & JOY_BUTTON_2)
2375 /* don't eat all CPU time */
2379 if (game_status != GAME_MODE_MAIN)
2384 if (!(req_state & REQ_STAY_OPEN))
2386 CloseDoor(DOOR_CLOSE_1);
2388 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2389 (req_state & REQ_REOPEN))
2390 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2395 SetDrawBackgroundMask(REDRAW_FIELD);
2397 #if defined(NETWORK_AVALIABLE)
2398 /* continue network game after request */
2399 if (options.network &&
2400 game_status == GAME_MODE_PLAYING &&
2401 req_state & REQUEST_WAIT_FOR_INPUT)
2402 SendToServer_ContinuePlaying();
2405 /* restore deactivated drawing when quick-loading level tape recording */
2406 if (tape.playing && tape.deactivate_display)
2407 TapeDeactivateDisplayOn();
2412 unsigned int OpenDoor(unsigned int door_state)
2414 if (door_state & DOOR_COPY_BACK)
2416 if (door_state & DOOR_OPEN_1)
2417 BlitBitmap(bitmap_db_door, bitmap_db_door,
2418 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2419 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2421 if (door_state & DOOR_OPEN_2)
2422 BlitBitmap(bitmap_db_door, bitmap_db_door,
2423 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2424 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2426 door_state &= ~DOOR_COPY_BACK;
2429 return MoveDoor(door_state);
2432 unsigned int CloseDoor(unsigned int door_state)
2434 unsigned int old_door_state = GetDoorState();
2436 if (!(door_state & DOOR_NO_COPY_BACK))
2438 if (old_door_state & DOOR_OPEN_1)
2439 BlitBitmap(backbuffer, bitmap_db_door,
2440 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2442 if (old_door_state & DOOR_OPEN_2)
2443 BlitBitmap(backbuffer, bitmap_db_door,
2444 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2446 door_state &= ~DOOR_NO_COPY_BACK;
2449 return MoveDoor(door_state);
2452 unsigned int GetDoorState()
2454 return MoveDoor(DOOR_GET_STATE);
2457 unsigned int SetDoorState(unsigned int door_state)
2459 return MoveDoor(door_state | DOOR_SET_STATE);
2462 unsigned int MoveDoor(unsigned int door_state)
2464 static int door1 = DOOR_OPEN_1;
2465 static int door2 = DOOR_CLOSE_2;
2466 unsigned long door_delay = 0;
2467 unsigned long door_delay_value;
2470 if (door_1.width < 0 || door_1.width > DXSIZE)
2471 door_1.width = DXSIZE;
2472 if (door_1.height < 0 || door_1.height > DYSIZE)
2473 door_1.height = DYSIZE;
2474 if (door_2.width < 0 || door_2.width > VXSIZE)
2475 door_2.width = VXSIZE;
2476 if (door_2.height < 0 || door_2.height > VYSIZE)
2477 door_2.height = VYSIZE;
2479 if (door_state == DOOR_GET_STATE)
2480 return(door1 | door2);
2482 if (door_state & DOOR_SET_STATE)
2484 if (door_state & DOOR_ACTION_1)
2485 door1 = door_state & DOOR_ACTION_1;
2486 if (door_state & DOOR_ACTION_2)
2487 door2 = door_state & DOOR_ACTION_2;
2489 return(door1 | door2);
2492 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2493 door_state &= ~DOOR_OPEN_1;
2494 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2495 door_state &= ~DOOR_CLOSE_1;
2496 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2497 door_state &= ~DOOR_OPEN_2;
2498 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2499 door_state &= ~DOOR_CLOSE_2;
2501 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2504 if (setup.quick_doors)
2506 stepsize = 20; /* must be choosen to always draw last frame */
2507 door_delay_value = 0;
2510 if (global.autoplay_leveldir)
2512 door_state |= DOOR_NO_DELAY;
2513 door_state &= ~DOOR_CLOSE_ALL;
2516 if (door_state & DOOR_ACTION)
2518 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2519 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2520 boolean door_1_done = (!handle_door_1);
2521 boolean door_2_done = (!handle_door_2);
2522 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2523 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2524 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2525 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2526 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2527 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2528 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2529 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2530 int door_skip = max_door_size - door_size;
2532 int end = door_size;
2534 int end = (door_state & DOOR_ACTION_1 &&
2535 door_1.anim_mode & ANIM_VERTICAL ? DYSIZE : DXSIZE);
2538 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2540 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2544 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2546 /* opening door sound has priority over simultaneously closing door */
2547 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2548 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2549 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2550 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2553 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2556 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2557 GC gc = bitmap->stored_clip_gc;
2559 if (door_state & DOOR_ACTION_1)
2561 int a = MIN(x * door_1.step_offset, end);
2562 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2563 int i = p + door_skip;
2565 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2567 BlitBitmap(bitmap_db_door, drawto,
2568 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2569 DXSIZE, DYSIZE, DX, DY);
2573 BlitBitmap(bitmap_db_door, drawto,
2574 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2575 DXSIZE, DYSIZE - p / 2, DX, DY);
2577 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2580 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2582 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2583 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2584 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2585 int dst2_x = DX, dst2_y = DY;
2586 int width = i, height = DYSIZE;
2588 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2589 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2592 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2593 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2596 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2598 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2599 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2600 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2601 int dst2_x = DX, dst2_y = DY;
2602 int width = DXSIZE, height = i;
2604 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2605 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2608 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2609 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2612 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2614 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2616 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2617 BlitBitmapMasked(bitmap, drawto,
2618 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2619 DX + DXSIZE - i, DY + j);
2620 BlitBitmapMasked(bitmap, drawto,
2621 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2622 DX + DXSIZE - i, DY + 140 + j);
2623 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2624 DY - (DOOR_GFX_PAGEY1 + j));
2625 BlitBitmapMasked(bitmap, drawto,
2626 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2628 BlitBitmapMasked(bitmap, drawto,
2629 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2632 BlitBitmapMasked(bitmap, drawto,
2633 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2635 BlitBitmapMasked(bitmap, drawto,
2636 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2638 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2639 BlitBitmapMasked(bitmap, drawto,
2640 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2641 DX + DXSIZE - i, DY + 77 + j);
2642 BlitBitmapMasked(bitmap, drawto,
2643 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2644 DX + DXSIZE - i, DY + 203 + j);
2647 redraw_mask |= REDRAW_DOOR_1;
2648 door_1_done = (a == end);
2651 if (door_state & DOOR_ACTION_2)
2653 int a = MIN(x * door_2.step_offset, door_size_2);
2654 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2655 int i = p + door_skip;
2657 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2659 BlitBitmap(bitmap_db_door, drawto,
2660 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2661 VXSIZE, VYSIZE, VX, VY);
2663 else if (x <= VYSIZE)
2665 BlitBitmap(bitmap_db_door, drawto,
2666 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2667 VXSIZE, VYSIZE - p / 2, VX, VY);
2669 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2672 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2674 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2675 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2676 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2677 int dst2_x = VX, dst2_y = VY;
2678 int width = i, height = VYSIZE;
2680 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2681 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2684 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2685 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2688 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2690 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2691 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2692 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2693 int dst2_x = VX, dst2_y = VY;
2694 int width = VXSIZE, height = i;
2696 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2697 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2700 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2701 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2704 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2706 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2708 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2709 BlitBitmapMasked(bitmap, drawto,
2710 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2711 VX + VXSIZE - i, VY + j);
2712 SetClipOrigin(bitmap, gc,
2713 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2714 BlitBitmapMasked(bitmap, drawto,
2715 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2718 BlitBitmapMasked(bitmap, drawto,
2719 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2720 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2721 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2722 BlitBitmapMasked(bitmap, drawto,
2723 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2725 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2728 redraw_mask |= REDRAW_DOOR_2;
2729 door_2_done = (a == VXSIZE);
2734 if (game_status == GAME_MODE_MAIN)
2737 if (!(door_state & DOOR_NO_DELAY))
2738 WaitUntilDelayReached(&door_delay, door_delay_value);
2742 if (door_state & DOOR_ACTION_1)
2743 door1 = door_state & DOOR_ACTION_1;
2744 if (door_state & DOOR_ACTION_2)
2745 door2 = door_state & DOOR_ACTION_2;
2747 return (door1 | door2);
2750 void DrawSpecialEditorDoor()
2752 /* draw bigger toolbox window */
2753 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2754 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2756 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2757 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2760 redraw_mask |= REDRAW_ALL;
2763 void UndrawSpecialEditorDoor()
2765 /* draw normal tape recorder window */
2766 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2767 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2770 redraw_mask |= REDRAW_ALL;
2774 /* ---------- new tool button stuff ---------------------------------------- */
2776 /* graphic position values for tool buttons */
2777 #define TOOL_BUTTON_YES_XPOS 2
2778 #define TOOL_BUTTON_YES_YPOS 250
2779 #define TOOL_BUTTON_YES_GFX_YPOS 0
2780 #define TOOL_BUTTON_YES_XSIZE 46
2781 #define TOOL_BUTTON_YES_YSIZE 28
2782 #define TOOL_BUTTON_NO_XPOS 52
2783 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2784 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2785 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2786 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2787 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2788 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2789 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2790 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2791 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2792 #define TOOL_BUTTON_PLAYER_XSIZE 30
2793 #define TOOL_BUTTON_PLAYER_YSIZE 30
2794 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2795 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2796 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2797 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2798 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2799 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2800 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2801 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2802 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2803 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2804 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2805 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2806 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2807 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2808 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2809 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2810 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2811 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2812 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2813 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2822 } toolbutton_info[NUM_TOOL_BUTTONS] =
2825 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2826 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2827 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2832 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2833 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2834 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2839 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2840 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2841 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2842 TOOL_CTRL_ID_CONFIRM,
2846 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2847 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2848 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2849 TOOL_CTRL_ID_PLAYER_1,
2853 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2854 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2855 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2856 TOOL_CTRL_ID_PLAYER_2,
2860 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2861 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2862 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2863 TOOL_CTRL_ID_PLAYER_3,
2867 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2868 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2869 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2870 TOOL_CTRL_ID_PLAYER_4,
2875 void CreateToolButtons()
2879 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2881 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2882 Bitmap *deco_bitmap = None;
2883 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2884 struct GadgetInfo *gi;
2885 unsigned long event_mask;
2886 int gd_xoffset, gd_yoffset;
2887 int gd_x1, gd_x2, gd_y;
2890 event_mask = GD_EVENT_RELEASED;
2892 gd_xoffset = toolbutton_info[i].xpos;
2893 gd_yoffset = toolbutton_info[i].ypos;
2894 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2895 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2896 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2898 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2900 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2902 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2903 &deco_bitmap, &deco_x, &deco_y);
2904 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2905 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2908 gi = CreateGadget(GDI_CUSTOM_ID, id,
2909 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2910 GDI_X, DX + toolbutton_info[i].x,
2911 GDI_Y, DY + toolbutton_info[i].y,
2912 GDI_WIDTH, toolbutton_info[i].width,
2913 GDI_HEIGHT, toolbutton_info[i].height,
2914 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2915 GDI_STATE, GD_BUTTON_UNPRESSED,
2916 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2917 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2918 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2919 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2920 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2921 GDI_DECORATION_SHIFTING, 1, 1,
2922 GDI_EVENT_MASK, event_mask,
2923 GDI_CALLBACK_ACTION, HandleToolButtons,
2927 Error(ERR_EXIT, "cannot create gadget");
2929 tool_gadget[id] = gi;
2933 void FreeToolButtons()
2937 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2938 FreeGadget(tool_gadget[i]);
2941 static void UnmapToolButtons()
2945 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2946 UnmapGadget(tool_gadget[i]);
2949 static void HandleToolButtons(struct GadgetInfo *gi)
2951 request_gadget_id = gi->custom_id;
2954 static struct Mapping_EM_to_RND_object
2957 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
2958 boolean is_backside; /* backside of moving element */
2964 em_object_mapping_list[] =
2967 Xblank, TRUE, FALSE,
2971 Yacid_splash_eB, FALSE, FALSE,
2972 EL_ACID_SPLASH_RIGHT, -1, -1
2975 Yacid_splash_wB, FALSE, FALSE,
2976 EL_ACID_SPLASH_LEFT, -1, -1
2979 #ifdef EM_ENGINE_BAD_ROLL
2981 Xstone_force_e, FALSE, FALSE,
2982 EL_ROCK, -1, MV_BIT_RIGHT
2985 Xstone_force_w, FALSE, FALSE,
2986 EL_ROCK, -1, MV_BIT_LEFT
2989 Xnut_force_e, FALSE, FALSE,
2990 EL_NUT, -1, MV_BIT_RIGHT
2993 Xnut_force_w, FALSE, FALSE,
2994 EL_NUT, -1, MV_BIT_LEFT
2997 Xspring_force_e, FALSE, FALSE,
2998 EL_SPRING, -1, MV_BIT_RIGHT
3001 Xspring_force_w, FALSE, FALSE,
3002 EL_SPRING, -1, MV_BIT_LEFT
3005 Xemerald_force_e, FALSE, FALSE,
3006 EL_EMERALD, -1, MV_BIT_RIGHT
3009 Xemerald_force_w, FALSE, FALSE,
3010 EL_EMERALD, -1, MV_BIT_LEFT
3013 Xdiamond_force_e, FALSE, FALSE,
3014 EL_DIAMOND, -1, MV_BIT_RIGHT
3017 Xdiamond_force_w, FALSE, FALSE,
3018 EL_DIAMOND, -1, MV_BIT_LEFT
3021 Xbomb_force_e, FALSE, FALSE,
3022 EL_BOMB, -1, MV_BIT_RIGHT
3025 Xbomb_force_w, FALSE, FALSE,
3026 EL_BOMB, -1, MV_BIT_LEFT
3028 #endif /* EM_ENGINE_BAD_ROLL */
3031 Xstone, TRUE, FALSE,
3035 Xstone_pause, FALSE, FALSE,
3039 Xstone_fall, FALSE, FALSE,
3043 Ystone_s, FALSE, FALSE,
3044 EL_ROCK, ACTION_FALLING, -1
3047 Ystone_sB, FALSE, TRUE,
3048 EL_ROCK, ACTION_FALLING, -1
3051 Ystone_e, FALSE, FALSE,
3052 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3055 Ystone_eB, FALSE, TRUE,
3056 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3059 Ystone_w, FALSE, FALSE,
3060 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3063 Ystone_wB, FALSE, TRUE,
3064 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3071 Xnut_pause, FALSE, FALSE,
3075 Xnut_fall, FALSE, FALSE,
3079 Ynut_s, FALSE, FALSE,
3080 EL_NUT, ACTION_FALLING, -1
3083 Ynut_sB, FALSE, TRUE,
3084 EL_NUT, ACTION_FALLING, -1
3087 Ynut_e, FALSE, FALSE,
3088 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3091 Ynut_eB, FALSE, TRUE,
3092 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3095 Ynut_w, FALSE, FALSE,
3096 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3099 Ynut_wB, FALSE, TRUE,
3100 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3103 Xbug_n, TRUE, FALSE,
3107 Xbug_e, TRUE, FALSE,
3108 EL_BUG_RIGHT, -1, -1
3111 Xbug_s, TRUE, FALSE,
3115 Xbug_w, TRUE, FALSE,
3119 Xbug_gon, FALSE, FALSE,
3123 Xbug_goe, FALSE, FALSE,
3124 EL_BUG_RIGHT, -1, -1
3127 Xbug_gos, FALSE, FALSE,
3131 Xbug_gow, FALSE, FALSE,
3135 Ybug_n, FALSE, FALSE,
3136 EL_BUG, ACTION_MOVING, MV_BIT_UP
3139 Ybug_nB, FALSE, TRUE,
3140 EL_BUG, ACTION_MOVING, MV_BIT_UP
3143 Ybug_e, FALSE, FALSE,
3144 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3147 Ybug_eB, FALSE, TRUE,
3148 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3151 Ybug_s, FALSE, FALSE,
3152 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3155 Ybug_sB, FALSE, TRUE,
3156 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3159 Ybug_w, FALSE, FALSE,
3160 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3163 Ybug_wB, FALSE, TRUE,
3164 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3167 Ybug_w_n, FALSE, FALSE,
3168 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3171 Ybug_n_e, FALSE, FALSE,
3172 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3175 Ybug_e_s, FALSE, FALSE,
3176 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3179 Ybug_s_w, FALSE, FALSE,
3180 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3183 Ybug_e_n, FALSE, FALSE,
3184 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3187 Ybug_s_e, FALSE, FALSE,
3188 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3191 Ybug_w_s, FALSE, FALSE,
3192 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3195 Ybug_n_w, FALSE, FALSE,
3196 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3199 Ybug_stone, FALSE, FALSE,
3200 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3203 Ybug_spring, FALSE, FALSE,
3204 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3207 Xtank_n, TRUE, FALSE,
3208 EL_SPACESHIP_UP, -1, -1
3211 Xtank_e, TRUE, FALSE,
3212 EL_SPACESHIP_RIGHT, -1, -1
3215 Xtank_s, TRUE, FALSE,
3216 EL_SPACESHIP_DOWN, -1, -1
3219 Xtank_w, TRUE, FALSE,
3220 EL_SPACESHIP_LEFT, -1, -1
3223 Xtank_gon, FALSE, FALSE,
3224 EL_SPACESHIP_UP, -1, -1
3227 Xtank_goe, FALSE, FALSE,
3228 EL_SPACESHIP_RIGHT, -1, -1
3231 Xtank_gos, FALSE, FALSE,
3232 EL_SPACESHIP_DOWN, -1, -1
3235 Xtank_gow, FALSE, FALSE,
3236 EL_SPACESHIP_LEFT, -1, -1
3239 Ytank_n, FALSE, FALSE,
3240 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3243 Ytank_nB, FALSE, TRUE,
3244 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3247 Ytank_e, FALSE, FALSE,
3248 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3251 Ytank_eB, FALSE, TRUE,
3252 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3255 Ytank_s, FALSE, FALSE,
3256 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3259 Ytank_sB, FALSE, TRUE,
3260 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3263 Ytank_w, FALSE, FALSE,
3264 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3267 Ytank_wB, FALSE, TRUE,
3268 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3271 Ytank_w_n, FALSE, FALSE,
3272 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3275 Ytank_n_e, FALSE, FALSE,
3276 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3279 Ytank_e_s, FALSE, FALSE,
3280 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3283 Ytank_s_w, FALSE, FALSE,
3284 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3287 Ytank_e_n, FALSE, FALSE,
3288 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3291 Ytank_s_e, FALSE, FALSE,
3292 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3295 Ytank_w_s, FALSE, FALSE,
3296 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3299 Ytank_n_w, FALSE, FALSE,
3300 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3303 Ytank_stone, FALSE, FALSE,
3304 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3307 Ytank_spring, FALSE, FALSE,
3308 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3311 Xandroid, TRUE, FALSE,
3312 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3315 Xandroid_1_n, FALSE, FALSE,
3316 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3319 Xandroid_2_n, FALSE, FALSE,
3320 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3323 Xandroid_1_e, FALSE, FALSE,
3324 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3327 Xandroid_2_e, FALSE, FALSE,
3328 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3331 Xandroid_1_w, FALSE, FALSE,
3332 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3335 Xandroid_2_w, FALSE, FALSE,
3336 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3339 Xandroid_1_s, FALSE, FALSE,
3340 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3343 Xandroid_2_s, FALSE, FALSE,
3344 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3347 Yandroid_n, FALSE, FALSE,
3348 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3351 Yandroid_nB, FALSE, TRUE,
3352 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3355 Yandroid_ne, FALSE, FALSE,
3356 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3359 Yandroid_neB, FALSE, TRUE,
3360 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3363 Yandroid_e, FALSE, FALSE,
3364 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3367 Yandroid_eB, FALSE, TRUE,
3368 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3371 Yandroid_se, FALSE, FALSE,
3372 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3375 Yandroid_seB, FALSE, TRUE,
3376 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3379 Yandroid_s, FALSE, FALSE,
3380 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3383 Yandroid_sB, FALSE, TRUE,
3384 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3387 Yandroid_sw, FALSE, FALSE,
3388 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3391 Yandroid_swB, FALSE, TRUE,
3392 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3395 Yandroid_w, FALSE, FALSE,
3396 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3399 Yandroid_wB, FALSE, TRUE,
3400 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3403 Yandroid_nw, FALSE, FALSE,
3404 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3407 Yandroid_nwB, FALSE, TRUE,
3408 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3411 Xspring, TRUE, FALSE,
3415 Xspring_pause, FALSE, FALSE,
3419 Xspring_e, FALSE, FALSE,
3423 Xspring_w, FALSE, FALSE,
3427 Xspring_fall, FALSE, FALSE,
3431 Yspring_s, FALSE, FALSE,
3432 EL_SPRING, ACTION_FALLING, -1
3435 Yspring_sB, FALSE, TRUE,
3436 EL_SPRING, ACTION_FALLING, -1
3439 Yspring_e, FALSE, FALSE,
3440 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3443 Yspring_eB, FALSE, TRUE,
3444 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3447 Yspring_w, FALSE, FALSE,
3448 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3451 Yspring_wB, FALSE, TRUE,
3452 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3455 Yspring_kill_e, FALSE, FALSE,
3456 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3459 Yspring_kill_eB, FALSE, TRUE,
3460 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3463 Yspring_kill_w, FALSE, FALSE,
3464 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3467 Yspring_kill_wB, FALSE, TRUE,
3468 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3471 Xeater_n, TRUE, FALSE,
3475 Xeater_e, FALSE, FALSE,
3479 Xeater_w, FALSE, FALSE,
3483 Xeater_s, FALSE, FALSE,
3487 Yeater_n, FALSE, FALSE,
3488 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3491 Yeater_nB, FALSE, TRUE,
3492 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3495 Yeater_e, FALSE, FALSE,
3496 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3499 Yeater_eB, FALSE, TRUE,
3500 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3503 Yeater_s, FALSE, FALSE,
3504 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3507 Yeater_sB, FALSE, TRUE,
3508 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3511 Yeater_w, FALSE, FALSE,
3512 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3515 Yeater_wB, FALSE, TRUE,
3516 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3519 Yeater_stone, FALSE, FALSE,
3520 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3523 Yeater_spring, FALSE, FALSE,
3524 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3527 Xalien, TRUE, FALSE,
3531 Xalien_pause, FALSE, FALSE,
3535 Yalien_n, FALSE, FALSE,
3536 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3539 Yalien_nB, FALSE, TRUE,
3540 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3543 Yalien_e, FALSE, FALSE,
3544 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3547 Yalien_eB, FALSE, TRUE,
3548 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3551 Yalien_s, FALSE, FALSE,
3552 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3555 Yalien_sB, FALSE, TRUE,
3556 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3559 Yalien_w, FALSE, FALSE,
3560 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3563 Yalien_wB, FALSE, TRUE,
3564 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3567 Yalien_stone, FALSE, FALSE,
3568 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3571 Yalien_spring, FALSE, FALSE,
3572 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3575 Xemerald, TRUE, FALSE,
3579 Xemerald_pause, FALSE, FALSE,
3583 Xemerald_fall, FALSE, FALSE,
3587 Xemerald_shine, FALSE, FALSE,
3588 EL_EMERALD, ACTION_TWINKLING, -1
3591 Yemerald_s, FALSE, FALSE,
3592 EL_EMERALD, ACTION_FALLING, -1
3595 Yemerald_sB, FALSE, TRUE,
3596 EL_EMERALD, ACTION_FALLING, -1
3599 Yemerald_e, FALSE, FALSE,
3600 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3603 Yemerald_eB, FALSE, TRUE,
3604 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3607 Yemerald_w, FALSE, FALSE,
3608 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3611 Yemerald_wB, FALSE, TRUE,
3612 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3615 Yemerald_eat, FALSE, FALSE,
3616 EL_EMERALD, ACTION_COLLECTING, -1
3619 Yemerald_stone, FALSE, FALSE,
3620 EL_NUT, ACTION_BREAKING, -1
3623 Xdiamond, TRUE, FALSE,
3627 Xdiamond_pause, FALSE, FALSE,
3631 Xdiamond_fall, FALSE, FALSE,
3635 Xdiamond_shine, FALSE, FALSE,
3636 EL_DIAMOND, ACTION_TWINKLING, -1
3639 Ydiamond_s, FALSE, FALSE,
3640 EL_DIAMOND, ACTION_FALLING, -1
3643 Ydiamond_sB, FALSE, TRUE,
3644 EL_DIAMOND, ACTION_FALLING, -1
3647 Ydiamond_e, FALSE, FALSE,
3648 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3651 Ydiamond_eB, FALSE, TRUE,
3652 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3655 Ydiamond_w, FALSE, FALSE,
3656 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3659 Ydiamond_wB, FALSE, TRUE,
3660 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3663 Ydiamond_eat, FALSE, FALSE,
3664 EL_DIAMOND, ACTION_COLLECTING, -1
3667 Ydiamond_stone, FALSE, FALSE,
3668 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3671 Xdrip_fall, TRUE, FALSE,
3672 EL_AMOEBA_DROP, -1, -1
3675 Xdrip_stretch, FALSE, FALSE,
3676 EL_AMOEBA_DROP, ACTION_FALLING, -1
3679 Xdrip_stretchB, FALSE, TRUE,
3680 EL_AMOEBA_DROP, ACTION_FALLING, -1
3683 Xdrip_eat, FALSE, FALSE,
3684 EL_AMOEBA_DROP, ACTION_GROWING, -1
3687 Ydrip_s1, FALSE, FALSE,
3688 EL_AMOEBA_DROP, ACTION_FALLING, -1
3691 Ydrip_s1B, FALSE, TRUE,
3692 EL_AMOEBA_DROP, ACTION_FALLING, -1
3695 Ydrip_s2, FALSE, FALSE,
3696 EL_AMOEBA_DROP, ACTION_FALLING, -1
3699 Ydrip_s2B, FALSE, TRUE,
3700 EL_AMOEBA_DROP, ACTION_FALLING, -1
3707 Xbomb_pause, FALSE, FALSE,
3711 Xbomb_fall, FALSE, FALSE,
3715 Ybomb_s, FALSE, FALSE,
3716 EL_BOMB, ACTION_FALLING, -1
3719 Ybomb_sB, FALSE, TRUE,
3720 EL_BOMB, ACTION_FALLING, -1
3723 Ybomb_e, FALSE, FALSE,
3724 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3727 Ybomb_eB, FALSE, TRUE,
3728 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3731 Ybomb_w, FALSE, FALSE,
3732 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3735 Ybomb_wB, FALSE, TRUE,
3736 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3739 Ybomb_eat, FALSE, FALSE,
3740 EL_BOMB, ACTION_ACTIVATING, -1
3743 Xballoon, TRUE, FALSE,
3747 Yballoon_n, FALSE, FALSE,
3748 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3751 Yballoon_nB, FALSE, TRUE,
3752 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3755 Yballoon_e, FALSE, FALSE,
3756 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3759 Yballoon_eB, FALSE, TRUE,
3760 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3763 Yballoon_s, FALSE, FALSE,
3764 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3767 Yballoon_sB, FALSE, TRUE,
3768 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3771 Yballoon_w, FALSE, FALSE,
3772 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3775 Yballoon_wB, FALSE, TRUE,
3776 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3779 Xgrass, TRUE, FALSE,
3780 EL_EMC_GRASS, -1, -1
3783 Ygrass_nB, FALSE, FALSE,
3784 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3787 Ygrass_eB, FALSE, FALSE,
3788 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3791 Ygrass_sB, FALSE, FALSE,
3792 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3795 Ygrass_wB, FALSE, FALSE,
3796 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3803 Ydirt_nB, FALSE, FALSE,
3804 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3807 Ydirt_eB, FALSE, FALSE,
3808 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3811 Ydirt_sB, FALSE, FALSE,
3812 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3815 Ydirt_wB, FALSE, FALSE,
3816 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3819 Xacid_ne, TRUE, FALSE,
3820 EL_ACID_POOL_TOPRIGHT, -1, -1
3823 Xacid_se, TRUE, FALSE,
3824 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3827 Xacid_s, TRUE, FALSE,
3828 EL_ACID_POOL_BOTTOM, -1, -1
3831 Xacid_sw, TRUE, FALSE,
3832 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3835 Xacid_nw, TRUE, FALSE,
3836 EL_ACID_POOL_TOPLEFT, -1, -1
3839 Xacid_1, TRUE, FALSE,
3843 Xacid_2, FALSE, FALSE,
3847 Xacid_3, FALSE, FALSE,
3851 Xacid_4, FALSE, FALSE,
3855 Xacid_5, FALSE, FALSE,
3859 Xacid_6, FALSE, FALSE,
3863 Xacid_7, FALSE, FALSE,
3867 Xacid_8, FALSE, FALSE,
3871 Xball_1, TRUE, FALSE,
3872 EL_EMC_MAGIC_BALL, -1, -1
3875 Xball_1B, FALSE, FALSE,
3876 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3879 Xball_2, FALSE, FALSE,
3880 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3883 Xball_2B, FALSE, FALSE,
3884 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3887 Yball_eat, FALSE, FALSE,
3888 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
3891 Ykey_1_eat, FALSE, FALSE,
3892 EL_EM_KEY_1, ACTION_COLLECTING, -1
3895 Ykey_2_eat, FALSE, FALSE,
3896 EL_EM_KEY_2, ACTION_COLLECTING, -1
3899 Ykey_3_eat, FALSE, FALSE,
3900 EL_EM_KEY_3, ACTION_COLLECTING, -1
3903 Ykey_4_eat, FALSE, FALSE,
3904 EL_EM_KEY_4, ACTION_COLLECTING, -1
3907 Ykey_5_eat, FALSE, FALSE,
3908 EL_EMC_KEY_5, ACTION_COLLECTING, -1
3911 Ykey_6_eat, FALSE, FALSE,
3912 EL_EMC_KEY_6, ACTION_COLLECTING, -1
3915 Ykey_7_eat, FALSE, FALSE,
3916 EL_EMC_KEY_7, ACTION_COLLECTING, -1
3919 Ykey_8_eat, FALSE, FALSE,
3920 EL_EMC_KEY_8, ACTION_COLLECTING, -1
3923 Ylenses_eat, FALSE, FALSE,
3924 EL_EMC_LENSES, ACTION_COLLECTING, -1
3927 Ymagnify_eat, FALSE, FALSE,
3928 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
3931 Ygrass_eat, FALSE, FALSE,
3932 EL_EMC_GRASS, ACTION_SNAPPING, -1
3935 Ydirt_eat, FALSE, FALSE,
3936 EL_SAND, ACTION_SNAPPING, -1
3939 Xgrow_ns, TRUE, FALSE,
3940 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
3943 Ygrow_ns_eat, FALSE, FALSE,
3944 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
3947 Xgrow_ew, TRUE, FALSE,
3948 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
3951 Ygrow_ew_eat, FALSE, FALSE,
3952 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
3955 Xwonderwall, TRUE, FALSE,
3956 EL_MAGIC_WALL, -1, -1
3959 XwonderwallB, FALSE, FALSE,
3960 EL_MAGIC_WALL, ACTION_ACTIVE, -1
3963 Xamoeba_1, TRUE, FALSE,
3964 EL_AMOEBA_DRY, ACTION_OTHER, -1
3967 Xamoeba_2, FALSE, FALSE,
3968 EL_AMOEBA_DRY, ACTION_OTHER, -1
3971 Xamoeba_3, FALSE, FALSE,
3972 EL_AMOEBA_DRY, ACTION_OTHER, -1
3975 Xamoeba_4, FALSE, FALSE,
3976 EL_AMOEBA_DRY, ACTION_OTHER, -1
3979 Xamoeba_5, TRUE, FALSE,
3980 EL_AMOEBA_WET, ACTION_OTHER, -1
3983 Xamoeba_6, FALSE, FALSE,
3984 EL_AMOEBA_WET, ACTION_OTHER, -1
3987 Xamoeba_7, FALSE, FALSE,
3988 EL_AMOEBA_WET, ACTION_OTHER, -1
3991 Xamoeba_8, FALSE, FALSE,
3992 EL_AMOEBA_WET, ACTION_OTHER, -1
3995 Xdoor_1, TRUE, FALSE,
3996 EL_EM_GATE_1, -1, -1
3999 Xdoor_2, TRUE, FALSE,
4000 EL_EM_GATE_2, -1, -1
4003 Xdoor_3, TRUE, FALSE,
4004 EL_EM_GATE_3, -1, -1
4007 Xdoor_4, TRUE, FALSE,
4008 EL_EM_GATE_4, -1, -1
4011 Xdoor_5, TRUE, FALSE,
4012 EL_EMC_GATE_5, -1, -1
4015 Xdoor_6, TRUE, FALSE,
4016 EL_EMC_GATE_6, -1, -1
4019 Xdoor_7, TRUE, FALSE,
4020 EL_EMC_GATE_7, -1, -1
4023 Xdoor_8, TRUE, FALSE,
4024 EL_EMC_GATE_8, -1, -1
4027 Xkey_1, TRUE, FALSE,
4031 Xkey_2, TRUE, FALSE,
4035 Xkey_3, TRUE, FALSE,
4039 Xkey_4, TRUE, FALSE,
4043 Xkey_5, TRUE, FALSE,
4044 EL_EMC_KEY_5, -1, -1
4047 Xkey_6, TRUE, FALSE,
4048 EL_EMC_KEY_6, -1, -1
4051 Xkey_7, TRUE, FALSE,
4052 EL_EMC_KEY_7, -1, -1
4055 Xkey_8, TRUE, FALSE,
4056 EL_EMC_KEY_8, -1, -1
4059 Xwind_n, TRUE, FALSE,
4060 EL_BALLOON_SWITCH_UP, -1, -1
4063 Xwind_e, TRUE, FALSE,
4064 EL_BALLOON_SWITCH_RIGHT, -1, -1
4067 Xwind_s, TRUE, FALSE,
4068 EL_BALLOON_SWITCH_DOWN, -1, -1
4071 Xwind_w, TRUE, FALSE,
4072 EL_BALLOON_SWITCH_LEFT, -1, -1
4075 Xwind_nesw, TRUE, FALSE,
4076 EL_BALLOON_SWITCH_ANY, -1, -1
4079 Xwind_stop, TRUE, FALSE,
4080 EL_BALLOON_SWITCH_NONE, -1, -1
4084 EL_EXIT_CLOSED, -1, -1
4087 Xexit_1, TRUE, FALSE,
4088 EL_EXIT_OPEN, -1, -1
4091 Xexit_2, FALSE, FALSE,
4092 EL_EXIT_OPEN, -1, -1
4095 Xexit_3, FALSE, FALSE,
4096 EL_EXIT_OPEN, -1, -1
4099 Xdynamite, TRUE, FALSE,
4100 EL_EM_DYNAMITE, -1, -1
4103 Ydynamite_eat, FALSE, FALSE,
4104 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4107 Xdynamite_1, TRUE, FALSE,
4108 EL_EM_DYNAMITE_ACTIVE, -1, -1
4111 Xdynamite_2, FALSE, FALSE,
4112 EL_EM_DYNAMITE_ACTIVE, -1, -1
4115 Xdynamite_3, FALSE, FALSE,
4116 EL_EM_DYNAMITE_ACTIVE, -1, -1
4119 Xdynamite_4, FALSE, FALSE,
4120 EL_EM_DYNAMITE_ACTIVE, -1, -1
4123 Xbumper, TRUE, FALSE,
4124 EL_EMC_SPRING_BUMPER, -1, -1
4127 XbumperB, FALSE, FALSE,
4128 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4131 Xwheel, TRUE, FALSE,
4132 EL_ROBOT_WHEEL, -1, -1
4135 XwheelB, FALSE, FALSE,
4136 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4139 Xswitch, TRUE, FALSE,
4140 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4143 XswitchB, FALSE, FALSE,
4144 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4148 EL_QUICKSAND_EMPTY, -1, -1
4151 Xsand_stone, TRUE, FALSE,
4152 EL_QUICKSAND_FULL, -1, -1
4155 Xsand_stonein_1, FALSE, FALSE,
4156 EL_ROCK, ACTION_FILLING, -1
4159 Xsand_stonein_2, FALSE, FALSE,
4160 EL_ROCK, ACTION_FILLING, -1
4163 Xsand_stonein_3, FALSE, FALSE,
4164 EL_ROCK, ACTION_FILLING, -1
4167 Xsand_stonein_4, FALSE, FALSE,
4168 EL_ROCK, ACTION_FILLING, -1
4171 Xsand_stonesand_1, FALSE, FALSE,
4172 EL_QUICKSAND_FULL, -1, -1
4175 Xsand_stonesand_2, FALSE, FALSE,
4176 EL_QUICKSAND_FULL, -1, -1
4179 Xsand_stonesand_3, FALSE, FALSE,
4180 EL_QUICKSAND_FULL, -1, -1
4183 Xsand_stonesand_4, FALSE, FALSE,
4184 EL_QUICKSAND_FULL, -1, -1
4187 Xsand_stoneout_1, FALSE, FALSE,
4188 EL_ROCK, ACTION_EMPTYING, -1
4191 Xsand_stoneout_2, FALSE, FALSE,
4192 EL_ROCK, ACTION_EMPTYING, -1
4195 Xsand_sandstone_1, FALSE, FALSE,
4196 EL_QUICKSAND_FULL, -1, -1
4199 Xsand_sandstone_2, FALSE, FALSE,
4200 EL_QUICKSAND_FULL, -1, -1
4203 Xsand_sandstone_3, FALSE, FALSE,
4204 EL_QUICKSAND_FULL, -1, -1
4207 Xsand_sandstone_4, FALSE, FALSE,
4208 EL_QUICKSAND_FULL, -1, -1
4211 Xplant, TRUE, FALSE,
4212 EL_EMC_PLANT, -1, -1
4215 Yplant, FALSE, FALSE,
4216 EL_EMC_PLANT, -1, -1
4219 Xlenses, TRUE, FALSE,
4220 EL_EMC_LENSES, -1, -1
4223 Xmagnify, TRUE, FALSE,
4224 EL_EMC_MAGNIFIER, -1, -1
4227 Xdripper, TRUE, FALSE,
4228 EL_EMC_DRIPPER, -1, -1
4231 XdripperB, FALSE, FALSE,
4232 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4235 Xfake_blank, TRUE, FALSE,
4236 EL_INVISIBLE_WALL, -1, -1
4239 Xfake_blankB, FALSE, FALSE,
4240 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4243 Xfake_grass, TRUE, FALSE,
4244 EL_EMC_FAKE_GRASS, -1, -1
4247 Xfake_grassB, FALSE, FALSE,
4248 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4251 Xfake_door_1, TRUE, FALSE,
4252 EL_EM_GATE_1_GRAY, -1, -1
4255 Xfake_door_2, TRUE, FALSE,
4256 EL_EM_GATE_2_GRAY, -1, -1
4259 Xfake_door_3, TRUE, FALSE,
4260 EL_EM_GATE_3_GRAY, -1, -1
4263 Xfake_door_4, TRUE, FALSE,
4264 EL_EM_GATE_4_GRAY, -1, -1
4267 Xfake_door_5, TRUE, FALSE,
4268 EL_EMC_GATE_5_GRAY, -1, -1
4271 Xfake_door_6, TRUE, FALSE,
4272 EL_EMC_GATE_6_GRAY, -1, -1
4275 Xfake_door_7, TRUE, FALSE,
4276 EL_EMC_GATE_7_GRAY, -1, -1
4279 Xfake_door_8, TRUE, FALSE,
4280 EL_EMC_GATE_8_GRAY, -1, -1
4283 Xfake_acid_1, TRUE, FALSE,
4284 EL_EMC_FAKE_ACID, -1, -1
4287 Xfake_acid_2, FALSE, FALSE,
4288 EL_EMC_FAKE_ACID, -1, -1
4291 Xfake_acid_3, FALSE, FALSE,
4292 EL_EMC_FAKE_ACID, -1, -1
4295 Xfake_acid_4, FALSE, FALSE,
4296 EL_EMC_FAKE_ACID, -1, -1
4299 Xfake_acid_5, FALSE, FALSE,
4300 EL_EMC_FAKE_ACID, -1, -1
4303 Xfake_acid_6, FALSE, FALSE,
4304 EL_EMC_FAKE_ACID, -1, -1
4307 Xfake_acid_7, FALSE, FALSE,
4308 EL_EMC_FAKE_ACID, -1, -1
4311 Xfake_acid_8, FALSE, FALSE,
4312 EL_EMC_FAKE_ACID, -1, -1
4315 Xsteel_1, TRUE, FALSE,
4316 EL_STEELWALL, -1, -1
4319 Xsteel_2, TRUE, FALSE,
4320 EL_EMC_STEELWALL_2, -1, -1
4323 Xsteel_3, TRUE, FALSE,
4324 EL_EMC_STEELWALL_3, -1, -1
4327 Xsteel_4, TRUE, FALSE,
4328 EL_EMC_STEELWALL_4, -1, -1
4331 Xwall_1, TRUE, FALSE,
4335 Xwall_2, TRUE, FALSE,
4336 EL_EMC_WALL_14, -1, -1
4339 Xwall_3, TRUE, FALSE,
4340 EL_EMC_WALL_15, -1, -1
4343 Xwall_4, TRUE, FALSE,
4344 EL_EMC_WALL_16, -1, -1
4347 Xround_wall_1, TRUE, FALSE,
4348 EL_WALL_SLIPPERY, -1, -1
4351 Xround_wall_2, TRUE, FALSE,
4352 EL_EMC_WALL_SLIPPERY_2, -1, -1
4355 Xround_wall_3, TRUE, FALSE,
4356 EL_EMC_WALL_SLIPPERY_3, -1, -1
4359 Xround_wall_4, TRUE, FALSE,
4360 EL_EMC_WALL_SLIPPERY_4, -1, -1
4363 Xdecor_1, TRUE, FALSE,
4364 EL_EMC_WALL_8, -1, -1
4367 Xdecor_2, TRUE, FALSE,
4368 EL_EMC_WALL_6, -1, -1
4371 Xdecor_3, TRUE, FALSE,
4372 EL_EMC_WALL_4, -1, -1
4375 Xdecor_4, TRUE, FALSE,
4376 EL_EMC_WALL_7, -1, -1
4379 Xdecor_5, TRUE, FALSE,
4380 EL_EMC_WALL_5, -1, -1
4383 Xdecor_6, TRUE, FALSE,
4384 EL_EMC_WALL_9, -1, -1
4387 Xdecor_7, TRUE, FALSE,
4388 EL_EMC_WALL_10, -1, -1
4391 Xdecor_8, TRUE, FALSE,
4392 EL_EMC_WALL_1, -1, -1
4395 Xdecor_9, TRUE, FALSE,
4396 EL_EMC_WALL_2, -1, -1
4399 Xdecor_10, TRUE, FALSE,
4400 EL_EMC_WALL_3, -1, -1
4403 Xdecor_11, TRUE, FALSE,
4404 EL_EMC_WALL_11, -1, -1
4407 Xdecor_12, TRUE, FALSE,
4408 EL_EMC_WALL_12, -1, -1
4411 Xalpha_0, TRUE, FALSE,
4412 EL_CHAR('0'), -1, -1
4415 Xalpha_1, TRUE, FALSE,
4416 EL_CHAR('1'), -1, -1
4419 Xalpha_2, TRUE, FALSE,
4420 EL_CHAR('2'), -1, -1
4423 Xalpha_3, TRUE, FALSE,
4424 EL_CHAR('3'), -1, -1
4427 Xalpha_4, TRUE, FALSE,
4428 EL_CHAR('4'), -1, -1
4431 Xalpha_5, TRUE, FALSE,
4432 EL_CHAR('5'), -1, -1
4435 Xalpha_6, TRUE, FALSE,
4436 EL_CHAR('6'), -1, -1
4439 Xalpha_7, TRUE, FALSE,
4440 EL_CHAR('7'), -1, -1
4443 Xalpha_8, TRUE, FALSE,
4444 EL_CHAR('8'), -1, -1
4447 Xalpha_9, TRUE, FALSE,
4448 EL_CHAR('9'), -1, -1
4451 Xalpha_excla, TRUE, FALSE,
4452 EL_CHAR('!'), -1, -1
4455 Xalpha_quote, TRUE, FALSE,
4456 EL_CHAR('"'), -1, -1
4459 Xalpha_comma, TRUE, FALSE,
4460 EL_CHAR(','), -1, -1
4463 Xalpha_minus, TRUE, FALSE,
4464 EL_CHAR('-'), -1, -1
4467 Xalpha_perio, TRUE, FALSE,
4468 EL_CHAR('.'), -1, -1
4471 Xalpha_colon, TRUE, FALSE,
4472 EL_CHAR(':'), -1, -1
4475 Xalpha_quest, TRUE, FALSE,
4476 EL_CHAR('?'), -1, -1
4479 Xalpha_a, TRUE, FALSE,
4480 EL_CHAR('A'), -1, -1
4483 Xalpha_b, TRUE, FALSE,
4484 EL_CHAR('B'), -1, -1
4487 Xalpha_c, TRUE, FALSE,
4488 EL_CHAR('C'), -1, -1
4491 Xalpha_d, TRUE, FALSE,
4492 EL_CHAR('D'), -1, -1
4495 Xalpha_e, TRUE, FALSE,
4496 EL_CHAR('E'), -1, -1
4499 Xalpha_f, TRUE, FALSE,
4500 EL_CHAR('F'), -1, -1
4503 Xalpha_g, TRUE, FALSE,
4504 EL_CHAR('G'), -1, -1
4507 Xalpha_h, TRUE, FALSE,
4508 EL_CHAR('H'), -1, -1
4511 Xalpha_i, TRUE, FALSE,
4512 EL_CHAR('I'), -1, -1
4515 Xalpha_j, TRUE, FALSE,
4516 EL_CHAR('J'), -1, -1
4519 Xalpha_k, TRUE, FALSE,
4520 EL_CHAR('K'), -1, -1
4523 Xalpha_l, TRUE, FALSE,
4524 EL_CHAR('L'), -1, -1
4527 Xalpha_m, TRUE, FALSE,
4528 EL_CHAR('M'), -1, -1
4531 Xalpha_n, TRUE, FALSE,
4532 EL_CHAR('N'), -1, -1
4535 Xalpha_o, TRUE, FALSE,
4536 EL_CHAR('O'), -1, -1
4539 Xalpha_p, TRUE, FALSE,
4540 EL_CHAR('P'), -1, -1
4543 Xalpha_q, TRUE, FALSE,
4544 EL_CHAR('Q'), -1, -1
4547 Xalpha_r, TRUE, FALSE,
4548 EL_CHAR('R'), -1, -1
4551 Xalpha_s, TRUE, FALSE,
4552 EL_CHAR('S'), -1, -1
4555 Xalpha_t, TRUE, FALSE,
4556 EL_CHAR('T'), -1, -1
4559 Xalpha_u, TRUE, FALSE,
4560 EL_CHAR('U'), -1, -1
4563 Xalpha_v, TRUE, FALSE,
4564 EL_CHAR('V'), -1, -1
4567 Xalpha_w, TRUE, FALSE,
4568 EL_CHAR('W'), -1, -1
4571 Xalpha_x, TRUE, FALSE,
4572 EL_CHAR('X'), -1, -1
4575 Xalpha_y, TRUE, FALSE,
4576 EL_CHAR('Y'), -1, -1
4579 Xalpha_z, TRUE, FALSE,
4580 EL_CHAR('Z'), -1, -1
4583 Xalpha_arrow_e, TRUE, FALSE,
4584 EL_CHAR('>'), -1, -1
4587 Xalpha_arrow_w, TRUE, FALSE,
4588 EL_CHAR('<'), -1, -1
4591 Xalpha_copyr, TRUE, FALSE,
4592 EL_CHAR('©'), -1, -1
4595 Xalpha_copyr, TRUE, FALSE,
4596 EL_CHAR('©'), -1, -1
4600 Xboom_bug, FALSE, FALSE,
4601 EL_BUG, ACTION_EXPLODING, -1
4604 Xboom_bomb, FALSE, FALSE,
4605 EL_BOMB, ACTION_EXPLODING, -1
4608 Xboom_android, FALSE, FALSE,
4609 EL_EMC_ANDROID, ACTION_OTHER, -1
4612 Xboom_1, FALSE, FALSE,
4613 EL_DEFAULT, ACTION_EXPLODING, -1
4616 Xboom_2, FALSE, FALSE,
4617 EL_DEFAULT, ACTION_EXPLODING, -1
4620 Znormal, FALSE, FALSE,
4624 Zdynamite, FALSE, FALSE,
4628 Zplayer, FALSE, FALSE,
4632 ZBORDER, FALSE, FALSE,
4642 static struct Mapping_EM_to_RND_player
4651 em_player_mapping_list[] =
4655 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4659 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4663 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4667 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4671 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4675 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4679 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4683 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4687 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4691 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4695 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4699 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4703 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4707 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4711 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4715 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4719 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4723 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4727 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4731 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4735 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4739 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4743 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4747 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4751 EL_PLAYER_1, ACTION_DEFAULT, -1,
4755 EL_PLAYER_2, ACTION_DEFAULT, -1,
4759 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4763 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4767 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4771 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4775 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4779 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4783 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4787 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4791 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4795 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4799 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4803 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4807 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4811 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4815 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4819 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4823 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4827 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4831 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4835 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4839 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4843 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4847 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4851 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
4855 EL_PLAYER_3, ACTION_DEFAULT, -1,
4859 EL_PLAYER_4, ACTION_DEFAULT, -1,
4868 int map_element_RND_to_EM(int element_rnd)
4870 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4871 static boolean mapping_initialized = FALSE;
4873 if (!mapping_initialized)
4877 /* return "Xalpha_quest" for all undefined elements in mapping array */
4878 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4879 mapping_RND_to_EM[i] = Xalpha_quest;
4881 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4882 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
4883 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
4884 em_object_mapping_list[i].element_em;
4886 mapping_initialized = TRUE;
4889 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4890 return mapping_RND_to_EM[element_rnd];
4892 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4897 int map_element_EM_to_RND(int element_em)
4899 static unsigned short mapping_EM_to_RND[TILE_MAX];
4900 static boolean mapping_initialized = FALSE;
4902 if (!mapping_initialized)
4906 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
4907 for (i = 0; i < TILE_MAX; i++)
4908 mapping_EM_to_RND[i] = EL_UNKNOWN;
4910 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4911 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
4912 em_object_mapping_list[i].element_rnd;
4914 mapping_initialized = TRUE;
4917 if (element_em >= 0 && element_em < TILE_MAX)
4918 return mapping_EM_to_RND[element_em];
4920 Error(ERR_WARN, "invalid EM level element %d", element_em);
4925 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
4927 struct LevelInfo_EM *level_em = level->native_em_level;
4928 struct LEVEL *lev = level_em->lev;
4931 for (i = 0; i < TILE_MAX; i++)
4932 lev->android_array[i] = Xblank;
4934 for (i = 0; i < level->num_android_clone_elements; i++)
4936 int element_rnd = level->android_clone_element[i];
4937 int element_em = map_element_RND_to_EM(element_rnd);
4939 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
4940 if (em_object_mapping_list[j].element_rnd == element_rnd)
4941 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
4945 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
4947 struct LevelInfo_EM *level_em = level->native_em_level;
4948 struct LEVEL *lev = level_em->lev;
4951 level->num_android_clone_elements = 0;
4953 for (i = 0; i < TILE_MAX; i++)
4955 int element_em = lev->android_array[i];
4957 boolean element_found = FALSE;
4959 if (element_em == Xblank)
4962 element_rnd = map_element_EM_to_RND(element_em);
4964 for (j = 0; j < level->num_android_clone_elements; j++)
4965 if (level->android_clone_element[j] == element_rnd)
4966 element_found = TRUE;
4970 level->android_clone_element[level->num_android_clone_elements++] =
4973 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
4978 if (level->num_android_clone_elements == 0)
4980 level->num_android_clone_elements = 1;
4981 level->android_clone_element[0] = EL_EMPTY;
4985 int map_direction_RND_to_EM(int direction)
4987 return (direction == MV_UP ? 0 :
4988 direction == MV_RIGHT ? 1 :
4989 direction == MV_DOWN ? 2 :
4990 direction == MV_LEFT ? 3 :
4994 int map_direction_EM_to_RND(int direction)
4996 return (direction == 0 ? MV_UP :
4997 direction == 1 ? MV_RIGHT :
4998 direction == 2 ? MV_DOWN :
4999 direction == 3 ? MV_LEFT :
5003 int get_next_element(int element)
5007 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5008 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5009 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5010 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5011 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5012 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5013 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5015 default: return element;
5020 int el_act_dir2img(int element, int action, int direction)
5022 element = GFX_ELEMENT(element);
5024 if (direction == MV_NONE)
5025 return element_info[element].graphic[action];
5027 direction = MV_DIR_TO_BIT(direction);
5029 return element_info[element].direction_graphic[action][direction];
5032 int el_act_dir2img(int element, int action, int direction)
5034 element = GFX_ELEMENT(element);
5035 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5037 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5038 return element_info[element].direction_graphic[action][direction];
5043 static int el_act_dir2crm(int element, int action, int direction)
5045 element = GFX_ELEMENT(element);
5047 if (direction == MV_NONE)
5048 return element_info[element].crumbled[action];
5050 direction = MV_DIR_TO_BIT(direction);
5052 return element_info[element].direction_crumbled[action][direction];
5055 static int el_act_dir2crm(int element, int action, int direction)
5057 element = GFX_ELEMENT(element);
5058 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5060 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5061 return element_info[element].direction_crumbled[action][direction];
5065 int el_act2img(int element, int action)
5067 element = GFX_ELEMENT(element);
5069 return element_info[element].graphic[action];
5072 int el_act2crm(int element, int action)
5074 element = GFX_ELEMENT(element);
5076 return element_info[element].crumbled[action];
5079 int el_dir2img(int element, int direction)
5081 element = GFX_ELEMENT(element);
5083 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5086 int el2baseimg(int element)
5088 return element_info[element].graphic[ACTION_DEFAULT];
5091 int el2img(int element)
5093 element = GFX_ELEMENT(element);
5095 return element_info[element].graphic[ACTION_DEFAULT];
5098 int el2edimg(int element)
5100 element = GFX_ELEMENT(element);
5102 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5105 int el2preimg(int element)
5107 element = GFX_ELEMENT(element);
5109 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5112 int font2baseimg(int font_nr)
5114 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5117 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5119 int game_frame_delay_value;
5121 game_frame_delay_value =
5122 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5123 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5126 if (tape.playing && tape.warp_forward && !tape.pausing)
5127 game_frame_delay_value = 0;
5129 return game_frame_delay_value;
5132 int getCenteredPlayerNr_EM()
5134 if (game.centered_player_nr_next >= 0 &&
5135 !native_em_level.ply[game.centered_player_nr_next]->alive)
5136 game.centered_player_nr_next = game.centered_player_nr;
5138 if (game.centered_player_nr != game.centered_player_nr_next)
5139 game.centered_player_nr = game.centered_player_nr_next;
5141 return game.centered_player_nr;
5144 int getActivePlayers_EM()
5146 int num_players = 0;
5152 for (i = 0; i < MAX_PLAYERS; i++)
5153 if (tape.player_participates[i])
5159 unsigned int InitRND(long seed)
5161 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5162 return InitEngineRND_EM(seed);
5164 return InitEngineRND(seed);
5167 #define DEBUG_EM_GFX 0
5169 void InitGraphicInfo_EM(void)
5171 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5172 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5176 if (graphic_info_em_object[0][0].bitmap == NULL)
5178 /* EM graphics not yet initialized in em_open_all() */
5184 /* always start with reliable default values */
5185 for (i = 0; i < TILE_MAX; i++)
5187 object_mapping[i].element_rnd = EL_UNKNOWN;
5188 object_mapping[i].is_backside = FALSE;
5189 object_mapping[i].action = ACTION_DEFAULT;
5190 object_mapping[i].direction = MV_NONE;
5193 /* always start with reliable default values */
5194 for (p = 0; p < MAX_PLAYERS; p++)
5196 for (i = 0; i < SPR_MAX; i++)
5198 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5199 player_mapping[p][i].action = ACTION_DEFAULT;
5200 player_mapping[p][i].direction = MV_NONE;
5204 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5206 int e = em_object_mapping_list[i].element_em;
5208 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5209 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5211 if (em_object_mapping_list[i].action != -1)
5212 object_mapping[e].action = em_object_mapping_list[i].action;
5214 if (em_object_mapping_list[i].direction != -1)
5215 object_mapping[e].direction =
5216 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5219 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5221 int a = em_player_mapping_list[i].action_em;
5222 int p = em_player_mapping_list[i].player_nr;
5224 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5226 if (em_player_mapping_list[i].action != -1)
5227 player_mapping[p][a].action = em_player_mapping_list[i].action;
5229 if (em_player_mapping_list[i].direction != -1)
5230 player_mapping[p][a].direction =
5231 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5234 for (i = 0; i < TILE_MAX; i++)
5236 int element = object_mapping[i].element_rnd;
5237 int action = object_mapping[i].action;
5238 int direction = object_mapping[i].direction;
5239 boolean is_backside = object_mapping[i].is_backside;
5240 boolean action_removing = (action == ACTION_DIGGING ||
5241 action == ACTION_SNAPPING ||
5242 action == ACTION_COLLECTING);
5243 boolean action_exploding = ((action == ACTION_EXPLODING ||
5244 action == ACTION_SMASHED_BY_ROCK ||
5245 action == ACTION_SMASHED_BY_SPRING) &&
5246 element != EL_DIAMOND);
5247 boolean action_active = (action == ACTION_ACTIVE);
5248 boolean action_other = (action == ACTION_OTHER);
5250 for (j = 0; j < 8; j++)
5252 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5253 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5255 i == Xdrip_stretch ? element :
5256 i == Xdrip_stretchB ? element :
5257 i == Ydrip_s1 ? element :
5258 i == Ydrip_s1B ? element :
5259 i == Xball_1B ? element :
5260 i == Xball_2 ? element :
5261 i == Xball_2B ? element :
5262 i == Yball_eat ? element :
5263 i == Ykey_1_eat ? element :
5264 i == Ykey_2_eat ? element :
5265 i == Ykey_3_eat ? element :
5266 i == Ykey_4_eat ? element :
5267 i == Ykey_5_eat ? element :
5268 i == Ykey_6_eat ? element :
5269 i == Ykey_7_eat ? element :
5270 i == Ykey_8_eat ? element :
5271 i == Ylenses_eat ? element :
5272 i == Ymagnify_eat ? element :
5273 i == Ygrass_eat ? element :
5274 i == Ydirt_eat ? element :
5275 i == Yspring_kill_e ? EL_SPRING :
5276 i == Yspring_kill_w ? EL_SPRING :
5277 i == Yemerald_stone ? EL_EMERALD :
5278 i == Ydiamond_stone ? EL_ROCK :
5279 i == Xsand_stonein_4 ? EL_EMPTY :
5280 i == Xsand_stoneout_2 ? EL_ROCK :
5281 is_backside ? EL_EMPTY :
5282 action_removing ? EL_EMPTY :
5284 int effective_action = (j < 7 ? action :
5285 i == Xdrip_stretch ? action :
5286 i == Xdrip_stretchB ? action :
5287 i == Ydrip_s1 ? action :
5288 i == Ydrip_s1B ? action :
5289 i == Xball_1B ? action :
5290 i == Xball_2 ? action :
5291 i == Xball_2B ? action :
5292 i == Yball_eat ? action :
5293 i == Ykey_1_eat ? action :
5294 i == Ykey_2_eat ? action :
5295 i == Ykey_3_eat ? action :
5296 i == Ykey_4_eat ? action :
5297 i == Ykey_5_eat ? action :
5298 i == Ykey_6_eat ? action :
5299 i == Ykey_7_eat ? action :
5300 i == Ykey_8_eat ? action :
5301 i == Ylenses_eat ? action :
5302 i == Ymagnify_eat ? action :
5303 i == Ygrass_eat ? action :
5304 i == Ydirt_eat ? action :
5305 i == Xsand_stonein_1 ? action :
5306 i == Xsand_stonein_2 ? action :
5307 i == Xsand_stonein_3 ? action :
5308 i == Xsand_stonein_4 ? action :
5309 i == Xsand_stoneout_1 ? action :
5310 i == Xsand_stoneout_2 ? action :
5311 i == Xboom_android ? ACTION_EXPLODING :
5312 action_exploding ? ACTION_EXPLODING :
5313 action_active ? action :
5314 action_other ? action :
5316 int graphic = (el_act_dir2img(effective_element, effective_action,
5318 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5320 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5321 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5322 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5323 struct GraphicInfo *g = &graphic_info[graphic];
5324 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5327 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5328 boolean special_animation = (action != ACTION_DEFAULT &&
5329 g->anim_frames == 3 &&
5330 g->anim_delay == 2 &&
5331 g->anim_mode & ANIM_LINEAR);
5332 int sync_frame = (i == Xdrip_stretch ? 7 :
5333 i == Xdrip_stretchB ? 7 :
5334 i == Ydrip_s2 ? j + 8 :
5335 i == Ydrip_s2B ? j + 8 :
5344 i == Xfake_acid_1 ? 0 :
5345 i == Xfake_acid_2 ? 10 :
5346 i == Xfake_acid_3 ? 20 :
5347 i == Xfake_acid_4 ? 30 :
5348 i == Xfake_acid_5 ? 40 :
5349 i == Xfake_acid_6 ? 50 :
5350 i == Xfake_acid_7 ? 60 :
5351 i == Xfake_acid_8 ? 70 :
5353 i == Xball_2B ? j + 8 :
5354 i == Yball_eat ? j + 1 :
5355 i == Ykey_1_eat ? j + 1 :
5356 i == Ykey_2_eat ? j + 1 :
5357 i == Ykey_3_eat ? j + 1 :
5358 i == Ykey_4_eat ? j + 1 :
5359 i == Ykey_5_eat ? j + 1 :
5360 i == Ykey_6_eat ? j + 1 :
5361 i == Ykey_7_eat ? j + 1 :
5362 i == Ykey_8_eat ? j + 1 :
5363 i == Ylenses_eat ? j + 1 :
5364 i == Ymagnify_eat ? j + 1 :
5365 i == Ygrass_eat ? j + 1 :
5366 i == Ydirt_eat ? j + 1 :
5367 i == Xamoeba_1 ? 0 :
5368 i == Xamoeba_2 ? 1 :
5369 i == Xamoeba_3 ? 2 :
5370 i == Xamoeba_4 ? 3 :
5371 i == Xamoeba_5 ? 0 :
5372 i == Xamoeba_6 ? 1 :
5373 i == Xamoeba_7 ? 2 :
5374 i == Xamoeba_8 ? 3 :
5375 i == Xexit_2 ? j + 8 :
5376 i == Xexit_3 ? j + 16 :
5377 i == Xdynamite_1 ? 0 :
5378 i == Xdynamite_2 ? 8 :
5379 i == Xdynamite_3 ? 16 :
5380 i == Xdynamite_4 ? 24 :
5381 i == Xsand_stonein_1 ? j + 1 :
5382 i == Xsand_stonein_2 ? j + 9 :
5383 i == Xsand_stonein_3 ? j + 17 :
5384 i == Xsand_stonein_4 ? j + 25 :
5385 i == Xsand_stoneout_1 && j == 0 ? 0 :
5386 i == Xsand_stoneout_1 && j == 1 ? 0 :
5387 i == Xsand_stoneout_1 && j == 2 ? 1 :
5388 i == Xsand_stoneout_1 && j == 3 ? 2 :
5389 i == Xsand_stoneout_1 && j == 4 ? 2 :
5390 i == Xsand_stoneout_1 && j == 5 ? 3 :
5391 i == Xsand_stoneout_1 && j == 6 ? 4 :
5392 i == Xsand_stoneout_1 && j == 7 ? 4 :
5393 i == Xsand_stoneout_2 && j == 0 ? 5 :
5394 i == Xsand_stoneout_2 && j == 1 ? 6 :
5395 i == Xsand_stoneout_2 && j == 2 ? 7 :
5396 i == Xsand_stoneout_2 && j == 3 ? 8 :
5397 i == Xsand_stoneout_2 && j == 4 ? 9 :
5398 i == Xsand_stoneout_2 && j == 5 ? 11 :
5399 i == Xsand_stoneout_2 && j == 6 ? 13 :
5400 i == Xsand_stoneout_2 && j == 7 ? 15 :
5401 i == Xboom_bug && j == 1 ? 2 :
5402 i == Xboom_bug && j == 2 ? 2 :
5403 i == Xboom_bug && j == 3 ? 4 :
5404 i == Xboom_bug && j == 4 ? 4 :
5405 i == Xboom_bug && j == 5 ? 2 :
5406 i == Xboom_bug && j == 6 ? 2 :
5407 i == Xboom_bug && j == 7 ? 0 :
5408 i == Xboom_bomb && j == 1 ? 2 :
5409 i == Xboom_bomb && j == 2 ? 2 :
5410 i == Xboom_bomb && j == 3 ? 4 :
5411 i == Xboom_bomb && j == 4 ? 4 :
5412 i == Xboom_bomb && j == 5 ? 2 :
5413 i == Xboom_bomb && j == 6 ? 2 :
5414 i == Xboom_bomb && j == 7 ? 0 :
5415 i == Xboom_android && j == 7 ? 6 :
5416 i == Xboom_1 && j == 1 ? 2 :
5417 i == Xboom_1 && j == 2 ? 2 :
5418 i == Xboom_1 && j == 3 ? 4 :
5419 i == Xboom_1 && j == 4 ? 4 :
5420 i == Xboom_1 && j == 5 ? 6 :
5421 i == Xboom_1 && j == 6 ? 6 :
5422 i == Xboom_1 && j == 7 ? 8 :
5423 i == Xboom_2 && j == 0 ? 8 :
5424 i == Xboom_2 && j == 1 ? 8 :
5425 i == Xboom_2 && j == 2 ? 10 :
5426 i == Xboom_2 && j == 3 ? 10 :
5427 i == Xboom_2 && j == 4 ? 10 :
5428 i == Xboom_2 && j == 5 ? 12 :
5429 i == Xboom_2 && j == 6 ? 12 :
5430 i == Xboom_2 && j == 7 ? 12 :
5431 special_animation && j == 4 ? 3 :
5432 effective_action != action ? 0 :
5436 Bitmap *debug_bitmap = g_em->bitmap;
5437 int debug_src_x = g_em->src_x;
5438 int debug_src_y = g_em->src_y;
5441 int frame = getAnimationFrame(g->anim_frames,
5444 g->anim_start_frame,
5447 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5448 g->double_movement && is_backside);
5450 g_em->bitmap = src_bitmap;
5451 g_em->src_x = src_x;
5452 g_em->src_y = src_y;
5453 g_em->src_offset_x = 0;
5454 g_em->src_offset_y = 0;
5455 g_em->dst_offset_x = 0;
5456 g_em->dst_offset_y = 0;
5457 g_em->width = TILEX;
5458 g_em->height = TILEY;
5460 g_em->crumbled_bitmap = NULL;
5461 g_em->crumbled_src_x = 0;
5462 g_em->crumbled_src_y = 0;
5463 g_em->crumbled_border_size = 0;
5465 g_em->has_crumbled_graphics = FALSE;
5466 g_em->preserve_background = FALSE;
5469 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5470 printf("::: empty crumbled: %d [%s], %d, %d\n",
5471 effective_element, element_info[effective_element].token_name,
5472 effective_action, direction);
5475 /* if element can be crumbled, but certain action graphics are just empty
5476 space (like snapping sand with the original R'n'D graphics), do not
5477 treat these empty space graphics as crumbled graphics in EMC engine */
5478 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5480 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5482 g_em->has_crumbled_graphics = TRUE;
5483 g_em->crumbled_bitmap = src_bitmap;
5484 g_em->crumbled_src_x = src_x;
5485 g_em->crumbled_src_y = src_y;
5486 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5489 if (!g->double_movement && (effective_action == ACTION_FALLING ||
5490 effective_action == ACTION_MOVING ||
5491 effective_action == ACTION_PUSHING ||
5492 effective_action == ACTION_EATING))
5495 (effective_action == ACTION_FALLING ? MV_DOWN : direction);
5496 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5497 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5498 int num_steps = (i == Ydrip_s1 ||
5501 i == Ydrip_s2B ? 16 : 8);
5502 int cx = ABS(dx) * (TILEX / num_steps);
5503 int cy = ABS(dy) * (TILEY / num_steps);
5504 int step_frame = (i == Ydrip_s2 ||
5505 i == Ydrip_s2B ? j + 8 : j) + 1;
5506 int step = (is_backside ? step_frame : num_steps - step_frame);
5508 if (is_backside) /* tile where movement starts */
5510 if (dx < 0 || dy < 0)
5512 g_em->src_offset_x = cx * step;
5513 g_em->src_offset_y = cy * step;
5517 g_em->dst_offset_x = cx * step;
5518 g_em->dst_offset_y = cy * step;
5521 else /* tile where movement ends */
5523 if (dx < 0 || dy < 0)
5525 g_em->dst_offset_x = cx * step;
5526 g_em->dst_offset_y = cy * step;
5530 g_em->src_offset_x = cx * step;
5531 g_em->src_offset_y = cy * step;
5535 g_em->width = TILEX - cx * step;
5536 g_em->height = TILEY - cy * step;
5540 /* create unique graphic identifier to decide if tile must be redrawn */
5541 /* bit 31 - 16 (16 bit): EM style graphic
5542 bit 15 - 12 ( 4 bit): EM style frame
5543 bit 11 - 6 ( 6 bit): graphic width
5544 bit 5 - 0 ( 6 bit): graphic height */
5545 g_em->unique_identifier =
5546 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5548 /* create unique graphic identifier to decide if tile must be redrawn */
5549 /* bit 31 - 16 (16 bit): EM style element
5550 bit 15 - 12 ( 4 bit): EM style frame
5551 bit 11 - 6 ( 6 bit): graphic width
5552 bit 5 - 0 ( 6 bit): graphic height */
5553 g_em->unique_identifier =
5554 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5558 if (effective_element == EL_ROCK)
5559 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5560 effective_action, j, graphic, frame, g_em->unique_identifier);
5566 /* skip check for EMC elements not contained in original EMC artwork */
5567 if (element == EL_EMC_FAKE_ACID)
5571 if (g_em->bitmap != debug_bitmap ||
5572 g_em->src_x != debug_src_x ||
5573 g_em->src_y != debug_src_y ||
5574 g_em->src_offset_x != 0 ||
5575 g_em->src_offset_y != 0 ||
5576 g_em->dst_offset_x != 0 ||
5577 g_em->dst_offset_y != 0 ||
5578 g_em->width != TILEX ||
5579 g_em->height != TILEY)
5581 static int last_i = -1;
5589 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5590 i, element, element_info[element].token_name,
5591 element_action_info[effective_action].suffix, direction);
5593 if (element != effective_element)
5594 printf(" [%d ('%s')]",
5596 element_info[effective_element].token_name);
5600 if (g_em->bitmap != debug_bitmap)
5601 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5602 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5604 if (g_em->src_x != debug_src_x ||
5605 g_em->src_y != debug_src_y)
5606 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5607 j, (is_backside ? 'B' : 'F'),
5608 g_em->src_x, g_em->src_y,
5609 g_em->src_x / 32, g_em->src_y / 32,
5610 debug_src_x, debug_src_y,
5611 debug_src_x / 32, debug_src_y / 32);
5613 if (g_em->src_offset_x != 0 ||
5614 g_em->src_offset_y != 0 ||
5615 g_em->dst_offset_x != 0 ||
5616 g_em->dst_offset_y != 0)
5617 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5619 g_em->src_offset_x, g_em->src_offset_y,
5620 g_em->dst_offset_x, g_em->dst_offset_y);
5622 if (g_em->width != TILEX ||
5623 g_em->height != TILEY)
5624 printf(" %d (%d): size %d,%d should be %d,%d\n",
5626 g_em->width, g_em->height, TILEX, TILEY);
5633 for (i = 0; i < TILE_MAX; i++)
5635 for (j = 0; j < 8; j++)
5637 int element = object_mapping[i].element_rnd;
5638 int action = object_mapping[i].action;
5639 int direction = object_mapping[i].direction;
5640 boolean is_backside = object_mapping[i].is_backside;
5642 int graphic_action = el_act_dir2img(element, action, direction);
5643 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5645 int graphic_action = element_info[element].graphic[action];
5646 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5649 if ((action == ACTION_SMASHED_BY_ROCK ||
5650 action == ACTION_SMASHED_BY_SPRING ||
5651 action == ACTION_EATING) &&
5652 graphic_action == graphic_default)
5654 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5655 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5656 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5657 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5660 /* no separate animation for "smashed by rock" -- use rock instead */
5661 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5662 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5664 g_em->bitmap = g_xx->bitmap;
5665 g_em->src_x = g_xx->src_x;
5666 g_em->src_y = g_xx->src_y;
5667 g_em->src_offset_x = g_xx->src_offset_x;
5668 g_em->src_offset_y = g_xx->src_offset_y;
5669 g_em->dst_offset_x = g_xx->dst_offset_x;
5670 g_em->dst_offset_y = g_xx->dst_offset_y;
5671 g_em->width = g_xx->width;
5672 g_em->height = g_xx->height;
5674 g_em->unique_identifier = g_xx->unique_identifier;
5678 g_em->preserve_background = TRUE;
5683 for (p = 0; p < MAX_PLAYERS; p++)
5685 for (i = 0; i < SPR_MAX; i++)
5687 int element = player_mapping[p][i].element_rnd;
5688 int action = player_mapping[p][i].action;
5689 int direction = player_mapping[p][i].direction;
5691 for (j = 0; j < 8; j++)
5693 int effective_element = element;
5694 int effective_action = action;
5695 int graphic = (direction == MV_NONE ?
5696 el_act2img(effective_element, effective_action) :
5697 el_act_dir2img(effective_element, effective_action,
5699 struct GraphicInfo *g = &graphic_info[graphic];
5700 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5706 Bitmap *debug_bitmap = g_em->bitmap;
5707 int debug_src_x = g_em->src_x;
5708 int debug_src_y = g_em->src_y;
5711 int frame = getAnimationFrame(g->anim_frames,
5714 g->anim_start_frame,
5717 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5719 g_em->bitmap = src_bitmap;
5720 g_em->src_x = src_x;
5721 g_em->src_y = src_y;
5722 g_em->src_offset_x = 0;
5723 g_em->src_offset_y = 0;
5724 g_em->dst_offset_x = 0;
5725 g_em->dst_offset_y = 0;
5726 g_em->width = TILEX;
5727 g_em->height = TILEY;
5732 /* skip check for EMC elements not contained in original EMC artwork */
5733 if (element == EL_PLAYER_3 ||
5734 element == EL_PLAYER_4)
5738 if (g_em->bitmap != debug_bitmap ||
5739 g_em->src_x != debug_src_x ||
5740 g_em->src_y != debug_src_y)
5742 static int last_i = -1;
5750 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5751 p, i, element, element_info[element].token_name,
5752 element_action_info[effective_action].suffix, direction);
5754 if (element != effective_element)
5755 printf(" [%d ('%s')]",
5757 element_info[effective_element].token_name);
5761 if (g_em->bitmap != debug_bitmap)
5762 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5763 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5765 if (g_em->src_x != debug_src_x ||
5766 g_em->src_y != debug_src_y)
5767 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5769 g_em->src_x, g_em->src_y,
5770 g_em->src_x / 32, g_em->src_y / 32,
5771 debug_src_x, debug_src_y,
5772 debug_src_x / 32, debug_src_y / 32);