1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX 0
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES 0
29 #define TOOL_CTRL_ID_NO 1
30 #define TOOL_CTRL_ID_CONFIRM 2
31 #define TOOL_CTRL_ID_PLAYER_1 3
32 #define TOOL_CTRL_ID_PLAYER_2 4
33 #define TOOL_CTRL_ID_PLAYER_3 5
34 #define TOOL_CTRL_ID_PLAYER_4 6
36 #define NUM_TOOL_BUTTONS 7
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
47 static char *print_if_not_empty(int element)
49 static char *s = NULL;
50 char *token_name = element_info[element].token_name;
55 s = checked_malloc(strlen(token_name) + 10 + 1);
57 if (element != EL_EMPTY)
58 sprintf(s, "%d\t['%s']", element, token_name);
60 sprintf(s, "%d", element);
65 void DumpTile(int x, int y)
70 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
77 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80 if (!IN_LEV_FIELD(x, y))
82 printf("(not in level field)\n");
88 printf(" Feld: %d\t['%s']\n", Feld[x][y],
89 element_info[Feld[x][y]].token_name);
90 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
91 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
92 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
93 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94 printf(" MovPos: %d\n", MovPos[x][y]);
95 printf(" MovDir: %d\n", MovDir[x][y]);
96 printf(" MovDelay: %d\n", MovDelay[x][y]);
97 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
98 printf(" CustomValue: %d\n", CustomValue[x][y]);
99 printf(" GfxElement: %d\n", GfxElement[x][y]);
100 printf(" GfxAction: %d\n", GfxAction[x][y]);
101 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
105 void SetDrawtoField(int mode)
107 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
118 drawto_field = fieldbuffer;
120 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
126 BX2 = SCR_FIELDX - 1;
127 BY2 = SCR_FIELDY - 1;
131 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 if (game_status == GAME_MODE_PLAYING &&
138 level.game_engine_type == GAME_ENGINE_TYPE_EM)
140 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
150 width = gfx.sxsize + 2 * TILEX;
151 height = gfx.sysize + 2 * TILEY;
154 if (force_redraw || setup.direct_draw)
157 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
158 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
160 if (setup.direct_draw)
161 SetDrawtoField(DRAW_BACKBUFFER);
163 for (xx = BX1; xx <= BX2; xx++)
164 for (yy = BY1; yy <= BY2; yy++)
165 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
166 DrawScreenField(xx, yy);
169 if (setup.direct_draw)
170 SetDrawtoField(DRAW_DIRECT);
173 if (setup.soft_scrolling)
175 int fx = FX, fy = FY;
177 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
178 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
180 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
184 BlitBitmap(drawto, window, x, y, width, height, x, y);
190 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
192 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
193 redraw_mask &= ~REDRAW_MAIN;
195 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
196 redraw_mask |= REDRAW_FIELD;
198 if (redraw_mask & REDRAW_FIELD)
199 redraw_mask &= ~REDRAW_TILES;
201 if (redraw_mask == REDRAW_NONE)
204 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
206 static boolean last_frame_skipped = FALSE;
207 boolean skip_even_when_not_scrolling = TRUE;
208 boolean just_scrolling = (ScreenMovDir != 0);
209 boolean verbose = FALSE;
211 if (global.fps_slowdown_factor > 1 &&
212 (FrameCounter % global.fps_slowdown_factor) &&
213 (just_scrolling || skip_even_when_not_scrolling))
215 redraw_mask &= ~REDRAW_MAIN;
217 last_frame_skipped = TRUE;
220 printf("FRAME SKIPPED\n");
224 if (last_frame_skipped)
225 redraw_mask |= REDRAW_FIELD;
227 last_frame_skipped = FALSE;
230 printf("frame not skipped\n");
234 /* synchronize X11 graphics at this point; if we would synchronize the
235 display immediately after the buffer switching (after the XFlush),
236 this could mean that we have to wait for the graphics to complete,
237 although we could go on doing calculations for the next frame */
241 if (redraw_mask & REDRAW_ALL)
243 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
247 if (redraw_mask & REDRAW_FIELD)
249 if (game_status != GAME_MODE_PLAYING ||
250 redraw_mask & REDRAW_FROM_BACKBUFFER)
252 BlitBitmap(backbuffer, window,
253 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
257 int fx = FX, fy = FY;
259 if (setup.soft_scrolling)
261 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
262 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
265 if (setup.soft_scrolling ||
266 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
267 ABS(ScreenMovPos) == ScrollStepSize ||
268 redraw_tiles > REDRAWTILES_THRESHOLD)
270 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
274 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
276 (setup.soft_scrolling ?
277 "setup.soft_scrolling" :
278 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
279 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
280 ABS(ScreenGfxPos) == ScrollStepSize ?
281 "ABS(ScreenGfxPos) == ScrollStepSize" :
282 "redraw_tiles > REDRAWTILES_THRESHOLD"));
288 redraw_mask &= ~REDRAW_MAIN;
291 if (redraw_mask & REDRAW_DOORS)
293 if (redraw_mask & REDRAW_DOOR_1)
294 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
296 if (redraw_mask & REDRAW_DOOR_2)
297 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
299 if (redraw_mask & REDRAW_DOOR_3)
300 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
302 redraw_mask &= ~REDRAW_DOORS;
305 if (redraw_mask & REDRAW_MICROLEVEL)
307 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
308 SX, SY + 10 * TILEY);
310 redraw_mask &= ~REDRAW_MICROLEVEL;
313 if (redraw_mask & REDRAW_TILES)
315 for (x = 0; x < SCR_FIELDX; x++)
316 for (y = 0 ; y < SCR_FIELDY; y++)
317 if (redraw[redraw_x1 + x][redraw_y1 + y])
318 BlitBitmap(buffer, window,
319 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
320 SX + x * TILEX, SY + y * TILEY);
323 if (redraw_mask & REDRAW_FPS) /* display frames per second */
328 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
329 if (!global.fps_slowdown)
332 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
333 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
338 for (x = 0; x < MAX_BUF_XSIZE; x++)
339 for (y = 0; y < MAX_BUF_YSIZE; y++)
342 redraw_mask = REDRAW_NONE;
348 long fading_delay = 300;
350 if (setup.fading && (redraw_mask & REDRAW_FIELD))
357 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
360 for (i = 0; i < 2 * FULL_SYSIZE; i++)
362 for (y = 0; y < FULL_SYSIZE; y++)
364 BlitBitmap(backbuffer, window,
365 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
373 for (i = 1; i < FULL_SYSIZE; i+=2)
374 BlitBitmap(backbuffer, window,
375 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
381 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
382 BlitBitmapMasked(backbuffer, window,
383 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
388 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
389 BlitBitmapMasked(backbuffer, window,
390 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
395 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
396 BlitBitmapMasked(backbuffer, window,
397 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
402 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
403 BlitBitmapMasked(backbuffer, window,
404 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
409 redraw_mask &= ~REDRAW_MAIN;
416 void SetMainBackgroundImageIfDefined(int graphic)
418 if (graphic_info[graphic].bitmap)
419 SetMainBackgroundImage(graphic);
422 void SetMainBackgroundImage(int graphic)
424 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
425 graphic_info[graphic].bitmap ?
426 graphic_info[graphic].bitmap :
427 graphic_info[IMG_BACKGROUND].bitmap);
430 void SetDoorBackgroundImage(int graphic)
432 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
433 graphic_info[graphic].bitmap ?
434 graphic_info[graphic].bitmap :
435 graphic_info[IMG_BACKGROUND].bitmap);
438 void DrawBackground(int dst_x, int dst_y, int width, int height)
440 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
442 redraw_mask |= REDRAW_FIELD;
447 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
449 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
451 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
452 SetDrawtoField(DRAW_BUFFERED);
455 SetDrawtoField(DRAW_BACKBUFFER);
457 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
459 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
460 SetDrawtoField(DRAW_DIRECT);
464 void MarkTileDirty(int x, int y)
466 int xx = redraw_x1 + x;
467 int yy = redraw_y1 + y;
472 redraw[xx][yy] = TRUE;
473 redraw_mask |= REDRAW_TILES;
476 void SetBorderElement()
480 BorderElement = EL_EMPTY;
482 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
484 for (x = 0; x < lev_fieldx; x++)
486 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
487 BorderElement = EL_STEELWALL;
489 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
495 void SetRandomAnimationValue(int x, int y)
497 gfx.anim_random_frame = GfxRandom[x][y];
500 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
502 /* animation synchronized with global frame counter, not move position */
503 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
504 sync_frame = FrameCounter;
507 if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
513 printf("::: FOO!\n");
517 return getAnimationFrame(graphic_info[graphic].anim_frames,
518 graphic_info[graphic].anim_delay,
519 graphic_info[graphic].anim_mode,
520 graphic_info[graphic].anim_start_frame,
524 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
525 int *x, int *y, boolean get_backside)
527 struct GraphicInfo *g = &graphic_info[graphic];
528 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
529 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
533 if (g->offset_y == 0) /* frames are ordered horizontally */
535 int max_width = g->anim_frames_per_line * g->width;
536 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
538 *x = pos % max_width;
539 *y = src_y % g->height + pos / max_width * g->height;
541 else if (g->offset_x == 0) /* frames are ordered vertically */
543 int max_height = g->anim_frames_per_line * g->height;
544 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
546 *x = src_x % g->width + pos / max_height * g->width;
547 *y = pos % max_height;
549 else /* frames are ordered diagonally */
551 *x = src_x + frame * g->offset_x;
552 *y = src_y + frame * g->offset_y;
556 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
558 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
561 void DrawGraphic(int x, int y, int graphic, int frame)
564 if (!IN_SCR_FIELD(x, y))
566 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
567 printf("DrawGraphic(): This should never happen!\n");
572 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
576 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
582 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
583 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
586 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
589 if (!IN_SCR_FIELD(x, y))
591 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
592 printf("DrawGraphicThruMask(): This should never happen!\n");
597 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
602 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
608 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
610 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
611 dst_x - src_x, dst_y - src_y);
612 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
615 void DrawMiniGraphic(int x, int y, int graphic)
617 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
618 MarkTileDirty(x / 2, y / 2);
621 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
623 struct GraphicInfo *g = &graphic_info[graphic];
625 int mini_starty = g->bitmap->height * 2 / 3;
628 *x = mini_startx + g->src_x / 2;
629 *y = mini_starty + g->src_y / 2;
632 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
637 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
638 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
641 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
642 int graphic, int frame,
643 int cut_mode, int mask_mode)
648 int width = TILEX, height = TILEY;
651 if (dx || dy) /* shifted graphic */
653 if (x < BX1) /* object enters playfield from the left */
660 else if (x > BX2) /* object enters playfield from the right */
666 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
672 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
674 else if (dx) /* general horizontal movement */
675 MarkTileDirty(x + SIGN(dx), y);
677 if (y < BY1) /* object enters playfield from the top */
679 if (cut_mode==CUT_BELOW) /* object completely above top border */
687 else if (y > BY2) /* object enters playfield from the bottom */
693 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
699 else if (dy > 0 && cut_mode == CUT_ABOVE)
701 if (y == BY2) /* object completely above bottom border */
707 MarkTileDirty(x, y + 1);
708 } /* object leaves playfield to the bottom */
709 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
711 else if (dy) /* general vertical movement */
712 MarkTileDirty(x, y + SIGN(dy));
716 if (!IN_SCR_FIELD(x, y))
718 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
719 printf("DrawGraphicShifted(): This should never happen!\n");
724 if (width > 0 && height > 0)
726 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
731 dst_x = FX + x * TILEX + dx;
732 dst_y = FY + y * TILEY + dy;
734 if (mask_mode == USE_MASKING)
736 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
737 dst_x - src_x, dst_y - src_y);
738 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
742 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
749 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
750 int graphic, int frame,
751 int cut_mode, int mask_mode)
756 int width = TILEX, height = TILEY;
759 int x2 = x + SIGN(dx);
760 int y2 = y + SIGN(dy);
761 int anim_frames = graphic_info[graphic].anim_frames;
762 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
763 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
764 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
766 /* re-calculate animation frame for two-tile movement animation */
767 frame = getGraphicAnimationFrame(graphic, sync_frame);
769 /* check if movement start graphic inside screen area and should be drawn */
770 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
772 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
774 dst_x = FX + x1 * TILEX;
775 dst_y = FY + y1 * TILEY;
777 if (mask_mode == USE_MASKING)
779 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
780 dst_x - src_x, dst_y - src_y);
781 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
785 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
788 MarkTileDirty(x1, y1);
791 /* check if movement end graphic inside screen area and should be drawn */
792 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
794 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
796 dst_x = FX + x2 * TILEX;
797 dst_y = FY + y2 * TILEY;
799 if (mask_mode == USE_MASKING)
801 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
802 dst_x - src_x, dst_y - src_y);
803 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
807 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
810 MarkTileDirty(x2, y2);
814 static void DrawGraphicShifted(int x, int y, int dx, int dy,
815 int graphic, int frame,
816 int cut_mode, int mask_mode)
820 DrawGraphic(x, y, graphic, frame);
825 if (graphic_info[graphic].double_movement) /* EM style movement images */
826 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
828 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
831 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
832 int frame, int cut_mode)
834 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
837 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
838 int cut_mode, int mask_mode)
840 int lx = LEVELX(x), ly = LEVELY(y);
844 if (IN_LEV_FIELD(lx, ly))
846 SetRandomAnimationValue(lx, ly);
848 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
849 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
851 /* do not use double (EM style) movement graphic when not moving */
852 if (graphic_info[graphic].double_movement && !dx && !dy)
854 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
855 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
858 else /* border element */
860 graphic = el2img(element);
861 frame = getGraphicAnimationFrame(graphic, -1);
864 if (element == EL_EXPANDABLE_WALL)
866 boolean left_stopped = FALSE, right_stopped = FALSE;
868 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
870 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
871 right_stopped = TRUE;
873 if (left_stopped && right_stopped)
875 else if (left_stopped)
877 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
878 frame = graphic_info[graphic].anim_frames - 1;
880 else if (right_stopped)
882 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
883 frame = graphic_info[graphic].anim_frames - 1;
888 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
889 else if (mask_mode == USE_MASKING)
890 DrawGraphicThruMask(x, y, graphic, frame);
892 DrawGraphic(x, y, graphic, frame);
895 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
896 int cut_mode, int mask_mode)
898 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
899 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
900 cut_mode, mask_mode);
903 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
906 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
909 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
912 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
915 void DrawLevelElementThruMask(int x, int y, int element)
917 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
920 void DrawLevelFieldThruMask(int x, int y)
922 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
925 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
929 int sx = SCREENX(x), sy = SCREENY(y);
931 int width, height, cx, cy, i;
932 int crumbled_border_size = graphic_info[graphic].border_size;
933 static int xy[4][2] =
941 if (!IN_LEV_FIELD(x, y))
944 element = TILE_GFX_ELEMENT(x, y);
946 /* crumble field itself */
947 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
949 if (!IN_SCR_FIELD(sx, sy))
952 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
954 for (i = 0; i < 4; i++)
956 int xx = x + xy[i][0];
957 int yy = y + xy[i][1];
959 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
962 /* check if neighbour field is of same type */
963 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
966 if (i == 1 || i == 2)
968 width = crumbled_border_size;
970 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
976 height = crumbled_border_size;
978 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
981 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
982 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
985 MarkTileDirty(sx, sy);
987 else /* crumble neighbour fields */
989 for (i = 0; i < 4; i++)
991 int xx = x + xy[i][0];
992 int yy = y + xy[i][1];
993 int sxx = sx + xy[i][0];
994 int syy = sy + xy[i][1];
997 if (!IN_LEV_FIELD(xx, yy) ||
998 !IN_SCR_FIELD(sxx, syy) ||
1003 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1007 element = TILE_GFX_ELEMENT(xx, yy);
1009 if (!GFX_CRUMBLED(element))
1012 if (!IN_LEV_FIELD(xx, yy) ||
1013 !IN_SCR_FIELD(sxx, syy) ||
1014 !GFX_CRUMBLED(Feld[xx][yy]) ||
1020 graphic = el_act2crm(element, ACTION_DEFAULT);
1022 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1024 crumbled_border_size = graphic_info[graphic].border_size;
1026 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1028 if (i == 1 || i == 2)
1030 width = crumbled_border_size;
1032 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1038 height = crumbled_border_size;
1040 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1043 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1044 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1046 MarkTileDirty(sxx, syy);
1051 void DrawLevelFieldCrumbledSand(int x, int y)
1055 if (!IN_LEV_FIELD(x, y))
1059 /* !!! CHECK THIS !!! */
1062 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1063 GFX_CRUMBLED(GfxElement[x][y]))
1066 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1067 GfxElement[x][y] != EL_UNDEFINED &&
1068 GFX_CRUMBLED(GfxElement[x][y]))
1070 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1077 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1079 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1082 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1085 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1088 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1089 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1090 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1091 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1092 int sx = SCREENX(x), sy = SCREENY(y);
1094 DrawGraphic(sx, sy, graphic1, frame1);
1095 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1098 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1100 int sx = SCREENX(x), sy = SCREENY(y);
1101 static int xy[4][2] =
1110 for (i = 0; i < 4; i++)
1112 int xx = x + xy[i][0];
1113 int yy = y + xy[i][1];
1114 int sxx = sx + xy[i][0];
1115 int syy = sy + xy[i][1];
1117 if (!IN_LEV_FIELD(xx, yy) ||
1118 !IN_SCR_FIELD(sxx, syy) ||
1119 !GFX_CRUMBLED(Feld[xx][yy]) ||
1123 DrawLevelField(xx, yy);
1127 static int getBorderElement(int x, int y)
1131 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1132 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1133 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1134 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1135 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1136 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1137 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1139 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1140 int steel_position = (x == -1 && y == -1 ? 0 :
1141 x == lev_fieldx && y == -1 ? 1 :
1142 x == -1 && y == lev_fieldy ? 2 :
1143 x == lev_fieldx && y == lev_fieldy ? 3 :
1144 x == -1 || x == lev_fieldx ? 4 :
1145 y == -1 || y == lev_fieldy ? 5 : 6);
1147 return border[steel_position][steel_type];
1150 void DrawScreenElement(int x, int y, int element)
1152 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1153 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1156 void DrawLevelElement(int x, int y, int element)
1158 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1159 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1162 void DrawScreenField(int x, int y)
1164 int lx = LEVELX(x), ly = LEVELY(y);
1165 int element, content;
1167 if (!IN_LEV_FIELD(lx, ly))
1169 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1172 element = getBorderElement(lx, ly);
1174 DrawScreenElement(x, y, element);
1178 element = Feld[lx][ly];
1179 content = Store[lx][ly];
1181 if (IS_MOVING(lx, ly))
1183 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1184 boolean cut_mode = NO_CUTTING;
1186 if (element == EL_QUICKSAND_EMPTYING ||
1187 element == EL_MAGIC_WALL_EMPTYING ||
1188 element == EL_BD_MAGIC_WALL_EMPTYING ||
1189 element == EL_AMOEBA_DROPPING)
1190 cut_mode = CUT_ABOVE;
1191 else if (element == EL_QUICKSAND_FILLING ||
1192 element == EL_MAGIC_WALL_FILLING ||
1193 element == EL_BD_MAGIC_WALL_FILLING)
1194 cut_mode = CUT_BELOW;
1196 if (cut_mode == CUT_ABOVE)
1197 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1199 DrawScreenElement(x, y, EL_EMPTY);
1202 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1203 else if (cut_mode == NO_CUTTING)
1204 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1206 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1208 if (content == EL_ACID)
1210 int dir = MovDir[lx][ly];
1211 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1212 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1214 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1217 else if (IS_BLOCKED(lx, ly))
1222 boolean cut_mode = NO_CUTTING;
1223 int element_old, content_old;
1225 Blocked2Moving(lx, ly, &oldx, &oldy);
1228 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1229 MovDir[oldx][oldy] == MV_RIGHT);
1231 element_old = Feld[oldx][oldy];
1232 content_old = Store[oldx][oldy];
1234 if (element_old == EL_QUICKSAND_EMPTYING ||
1235 element_old == EL_MAGIC_WALL_EMPTYING ||
1236 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1237 element_old == EL_AMOEBA_DROPPING)
1238 cut_mode = CUT_ABOVE;
1240 DrawScreenElement(x, y, EL_EMPTY);
1243 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1245 else if (cut_mode == NO_CUTTING)
1246 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1249 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1252 else if (IS_DRAWABLE(element))
1253 DrawScreenElement(x, y, element);
1255 DrawScreenElement(x, y, EL_EMPTY);
1258 void DrawLevelField(int x, int y)
1260 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1261 DrawScreenField(SCREENX(x), SCREENY(y));
1262 else if (IS_MOVING(x, y))
1266 Moving2Blocked(x, y, &newx, &newy);
1267 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1268 DrawScreenField(SCREENX(newx), SCREENY(newy));
1270 else if (IS_BLOCKED(x, y))
1274 Blocked2Moving(x, y, &oldx, &oldy);
1275 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1276 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1280 void DrawMiniElement(int x, int y, int element)
1284 graphic = el2edimg(element);
1285 DrawMiniGraphic(x, y, graphic);
1288 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1290 int x = sx + scroll_x, y = sy + scroll_y;
1292 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1293 DrawMiniElement(sx, sy, EL_EMPTY);
1294 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1295 DrawMiniElement(sx, sy, Feld[x][y]);
1297 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1300 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1301 int x, int y, int xsize, int ysize, int font_nr)
1303 int font_width = getFontWidth(font_nr);
1304 int font_height = getFontHeight(font_nr);
1305 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1308 int dst_x = SX + startx + x * font_width;
1309 int dst_y = SY + starty + y * font_height;
1310 int width = graphic_info[graphic].width;
1311 int height = graphic_info[graphic].height;
1312 int inner_width = MAX(width - 2 * font_width, font_width);
1313 int inner_height = MAX(height - 2 * font_height, font_height);
1314 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1315 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1316 boolean draw_masked = graphic_info[graphic].draw_masked;
1318 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1320 if (src_bitmap == NULL || width < font_width || height < font_height)
1322 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1326 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1327 inner_sx + (x - 1) * font_width % inner_width);
1328 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1329 inner_sy + (y - 1) * font_height % inner_height);
1333 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1334 dst_x - src_x, dst_y - src_y);
1335 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1339 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1343 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1345 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1346 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1347 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1348 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1349 boolean no_delay = (tape.warp_forward);
1350 unsigned long anim_delay = 0;
1351 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1352 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1353 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1354 int font_width = getFontWidth(font_nr);
1355 int font_height = getFontHeight(font_nr);
1356 int max_xsize = level.envelope_xsize[envelope_nr];
1357 int max_ysize = level.envelope_ysize[envelope_nr];
1358 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1359 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1360 int xend = max_xsize;
1361 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1362 int xstep = (xstart < xend ? 1 : 0);
1363 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1366 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1368 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1369 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1370 int sx = (SXSIZE - xsize * font_width) / 2;
1371 int sy = (SYSIZE - ysize * font_height) / 2;
1374 SetDrawtoField(DRAW_BUFFERED);
1376 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1378 SetDrawtoField(DRAW_BACKBUFFER);
1380 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1381 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1383 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1384 level.envelope_text[envelope_nr], font_nr, max_xsize,
1385 xsize - 2, ysize - 2, mask_mode);
1387 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1390 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1394 void ShowEnvelope(int envelope_nr)
1396 int element = EL_ENVELOPE_1 + envelope_nr;
1397 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1398 int sound_opening = element_info[element].sound[ACTION_OPENING];
1399 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1400 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1401 boolean no_delay = (tape.warp_forward);
1402 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1403 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1404 int anim_mode = graphic_info[graphic].anim_mode;
1405 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1406 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1408 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1410 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1412 if (anim_mode == ANIM_DEFAULT)
1413 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1415 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1418 Delay(wait_delay_value);
1420 WaitForEventToContinue();
1422 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1424 if (anim_mode != ANIM_NONE)
1425 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1427 if (anim_mode == ANIM_DEFAULT)
1428 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1430 game.envelope_active = FALSE;
1432 SetDrawtoField(DRAW_BUFFERED);
1434 redraw_mask |= REDRAW_FIELD;
1438 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1440 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1441 int mini_startx = src_bitmap->width * 3 / 4;
1442 int mini_starty = src_bitmap->height * 2 / 3;
1443 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1444 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1446 *bitmap = src_bitmap;
1451 void DrawMicroElement(int xpos, int ypos, int element)
1455 int graphic = el2preimg(element);
1457 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1458 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1466 SetDrawBackgroundMask(REDRAW_NONE);
1469 for (x = BX1; x <= BX2; x++)
1470 for (y = BY1; y <= BY2; y++)
1471 DrawScreenField(x, y);
1473 redraw_mask |= REDRAW_FIELD;
1476 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1480 for (x = 0; x < size_x; x++)
1481 for (y = 0; y < size_y; y++)
1482 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1484 redraw_mask |= REDRAW_FIELD;
1487 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1491 DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
1493 if (lev_fieldx < STD_LEV_FIELDX)
1494 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1495 if (lev_fieldy < STD_LEV_FIELDY)
1496 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1498 xpos += MICRO_TILEX;
1499 ypos += MICRO_TILEY;
1501 for (x = -1; x <= STD_LEV_FIELDX; x++)
1503 for (y = -1; y <= STD_LEV_FIELDY; y++)
1505 int lx = from_x + x, ly = from_y + y;
1507 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1508 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1509 level.field[lx][ly]);
1510 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1511 && BorderElement != EL_EMPTY)
1512 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1513 getBorderElement(lx, ly));
1517 redraw_mask |= REDRAW_MICROLEVEL;
1520 #define MICROLABEL_EMPTY 0
1521 #define MICROLABEL_LEVEL_NAME 1
1522 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1523 #define MICROLABEL_LEVEL_AUTHOR 3
1524 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1525 #define MICROLABEL_IMPORTED_FROM 5
1526 #define MICROLABEL_IMPORTED_BY_HEAD 6
1527 #define MICROLABEL_IMPORTED_BY 7
1529 static void DrawMicroLevelLabelExt(int mode)
1531 char label_text[MAX_OUTPUT_LINESIZE + 1];
1532 int max_len_label_text;
1533 int font_nr = FONT_TEXT_2;
1536 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1537 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1538 mode == MICROLABEL_IMPORTED_BY_HEAD)
1539 font_nr = FONT_TEXT_3;
1541 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1543 for (i = 0; i < max_len_label_text; i++)
1544 label_text[i] = ' ';
1545 label_text[max_len_label_text] = '\0';
1547 if (strlen(label_text) > 0)
1549 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1550 int lypos = MICROLABEL2_YPOS;
1552 DrawText(lxpos, lypos, label_text, font_nr);
1556 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1557 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1558 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1559 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1560 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1561 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1562 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1563 max_len_label_text);
1564 label_text[max_len_label_text] = '\0';
1566 if (strlen(label_text) > 0)
1568 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1569 int lypos = MICROLABEL2_YPOS;
1571 DrawText(lxpos, lypos, label_text, font_nr);
1574 redraw_mask |= REDRAW_MICROLEVEL;
1577 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1579 static unsigned long scroll_delay = 0;
1580 static unsigned long label_delay = 0;
1581 static int from_x, from_y, scroll_direction;
1582 static int label_state, label_counter;
1583 int last_game_status = game_status; /* save current game status */
1585 /* force PREVIEW font on preview level */
1586 game_status = GAME_MODE_PSEUDO_PREVIEW;
1590 from_x = from_y = 0;
1591 scroll_direction = MV_RIGHT;
1595 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1596 DrawMicroLevelLabelExt(label_state);
1598 /* initialize delay counters */
1599 DelayReached(&scroll_delay, 0);
1600 DelayReached(&label_delay, 0);
1602 if (leveldir_current->name)
1604 char label_text[MAX_OUTPUT_LINESIZE + 1];
1605 int font_nr = FONT_TEXT_1;
1606 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1609 strncpy(label_text, leveldir_current->name, max_len_label_text);
1610 label_text[max_len_label_text] = '\0';
1612 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1613 lypos = SY + MICROLABEL1_YPOS;
1615 DrawText(lxpos, lypos, label_text, font_nr);
1618 game_status = last_game_status; /* restore current game status */
1623 /* scroll micro level, if needed */
1624 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1625 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1627 switch (scroll_direction)
1633 scroll_direction = MV_UP;
1637 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1640 scroll_direction = MV_DOWN;
1647 scroll_direction = MV_RIGHT;
1651 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1654 scroll_direction = MV_LEFT;
1661 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1664 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1665 /* redraw micro level label, if needed */
1666 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1667 !strEqual(level.author, ANONYMOUS_NAME) &&
1668 !strEqual(level.author, leveldir_current->name) &&
1669 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1671 int max_label_counter = 23;
1673 if (leveldir_current->imported_from != NULL &&
1674 strlen(leveldir_current->imported_from) > 0)
1675 max_label_counter += 14;
1676 if (leveldir_current->imported_by != NULL &&
1677 strlen(leveldir_current->imported_by) > 0)
1678 max_label_counter += 14;
1680 label_counter = (label_counter + 1) % max_label_counter;
1681 label_state = (label_counter >= 0 && label_counter <= 7 ?
1682 MICROLABEL_LEVEL_NAME :
1683 label_counter >= 9 && label_counter <= 12 ?
1684 MICROLABEL_LEVEL_AUTHOR_HEAD :
1685 label_counter >= 14 && label_counter <= 21 ?
1686 MICROLABEL_LEVEL_AUTHOR :
1687 label_counter >= 23 && label_counter <= 26 ?
1688 MICROLABEL_IMPORTED_FROM_HEAD :
1689 label_counter >= 28 && label_counter <= 35 ?
1690 MICROLABEL_IMPORTED_FROM :
1691 label_counter >= 37 && label_counter <= 40 ?
1692 MICROLABEL_IMPORTED_BY_HEAD :
1693 label_counter >= 42 && label_counter <= 49 ?
1694 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1696 if (leveldir_current->imported_from == NULL &&
1697 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1698 label_state == MICROLABEL_IMPORTED_FROM))
1699 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1700 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1702 DrawMicroLevelLabelExt(label_state);
1705 game_status = last_game_status; /* restore current game status */
1708 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1709 int graphic, int sync_frame, int mask_mode)
1711 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1713 if (mask_mode == USE_MASKING)
1714 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1716 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1719 inline void DrawGraphicAnimation(int x, int y, int graphic)
1721 int lx = LEVELX(x), ly = LEVELY(y);
1723 if (!IN_SCR_FIELD(x, y))
1726 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1727 graphic, GfxFrame[lx][ly], NO_MASKING);
1728 MarkTileDirty(x, y);
1731 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1733 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1736 void DrawLevelElementAnimation(int x, int y, int element)
1738 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1740 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1743 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1745 int sx = SCREENX(x), sy = SCREENY(y);
1747 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1750 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1753 DrawGraphicAnimation(sx, sy, graphic);
1756 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1757 DrawLevelFieldCrumbledSand(x, y);
1759 if (GFX_CRUMBLED(Feld[x][y]))
1760 DrawLevelFieldCrumbledSand(x, y);
1764 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1766 int sx = SCREENX(x), sy = SCREENY(y);
1769 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1772 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1774 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1777 DrawGraphicAnimation(sx, sy, graphic);
1779 if (GFX_CRUMBLED(element))
1780 DrawLevelFieldCrumbledSand(x, y);
1783 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1785 if (player->use_murphy)
1787 /* this works only because currently only one player can be "murphy" ... */
1788 static int last_horizontal_dir = MV_LEFT;
1789 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1791 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1792 last_horizontal_dir = move_dir;
1794 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1796 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1798 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1804 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1807 static boolean equalGraphics(int graphic1, int graphic2)
1809 struct GraphicInfo *g1 = &graphic_info[graphic1];
1810 struct GraphicInfo *g2 = &graphic_info[graphic2];
1812 return (g1->bitmap == g2->bitmap &&
1813 g1->src_x == g2->src_x &&
1814 g1->src_y == g2->src_y &&
1815 g1->anim_frames == g2->anim_frames &&
1816 g1->anim_delay == g2->anim_delay &&
1817 g1->anim_mode == g2->anim_mode);
1820 void DrawAllPlayers()
1824 for (i = 0; i < MAX_PLAYERS; i++)
1825 if (stored_player[i].active)
1826 DrawPlayer(&stored_player[i]);
1829 void DrawPlayerField(int x, int y)
1831 if (!IS_PLAYER(x, y))
1834 DrawPlayer(PLAYERINFO(x, y));
1837 void DrawPlayer(struct PlayerInfo *player)
1839 int jx = player->jx;
1840 int jy = player->jy;
1841 int move_dir = player->MovDir;
1842 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1843 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1844 int last_jx = (player->is_moving ? jx - dx : jx);
1845 int last_jy = (player->is_moving ? jy - dy : jy);
1846 int next_jx = jx + dx;
1847 int next_jy = jy + dy;
1848 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1849 boolean player_is_opaque = FALSE;
1850 int sx = SCREENX(jx), sy = SCREENY(jy);
1851 int sxx = 0, syy = 0;
1852 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1854 int action = ACTION_DEFAULT;
1855 int last_player_graphic = getPlayerGraphic(player, move_dir);
1856 int last_player_frame = player->Frame;
1860 /* GfxElement[][] is set to the element the player is digging or collecting;
1861 remove also for off-screen player if the player is not moving anymore */
1862 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1863 GfxElement[jx][jy] = EL_UNDEFINED;
1866 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1870 if (!IN_LEV_FIELD(jx, jy))
1872 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1873 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1874 printf("DrawPlayerField(): This should never happen!\n");
1879 if (element == EL_EXPLOSION)
1882 action = (player->is_pushing ? ACTION_PUSHING :
1883 player->is_digging ? ACTION_DIGGING :
1884 player->is_collecting ? ACTION_COLLECTING :
1885 player->is_moving ? ACTION_MOVING :
1886 player->is_snapping ? ACTION_SNAPPING :
1887 player->is_dropping ? ACTION_DROPPING :
1888 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1891 if (player->is_waiting)
1892 move_dir = player->dir_waiting;
1895 InitPlayerGfxAnimation(player, action, move_dir);
1897 /* ----------------------------------------------------------------------- */
1898 /* draw things in the field the player is leaving, if needed */
1899 /* ----------------------------------------------------------------------- */
1901 if (player->is_moving)
1903 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1905 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1907 if (last_element == EL_DYNAMITE_ACTIVE ||
1908 last_element == EL_EM_DYNAMITE_ACTIVE ||
1909 last_element == EL_SP_DISK_RED_ACTIVE)
1910 DrawDynamite(last_jx, last_jy);
1912 DrawLevelFieldThruMask(last_jx, last_jy);
1914 else if (last_element == EL_DYNAMITE_ACTIVE ||
1915 last_element == EL_EM_DYNAMITE_ACTIVE ||
1916 last_element == EL_SP_DISK_RED_ACTIVE)
1917 DrawDynamite(last_jx, last_jy);
1919 DrawLevelField(last_jx, last_jy);
1921 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
1922 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
1925 if (!IN_SCR_FIELD(sx, sy))
1928 if (setup.direct_draw)
1929 SetDrawtoField(DRAW_BUFFERED);
1931 /* ----------------------------------------------------------------------- */
1932 /* draw things behind the player, if needed */
1933 /* ----------------------------------------------------------------------- */
1936 DrawLevelElement(jx, jy, Back[jx][jy]);
1937 else if (IS_ACTIVE_BOMB(element))
1938 DrawLevelElement(jx, jy, EL_EMPTY);
1941 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
1943 int old_element = GfxElement[jx][jy];
1944 int old_graphic = el_act_dir2img(old_element, action, move_dir);
1945 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
1947 if (GFX_CRUMBLED(old_element))
1948 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
1950 DrawGraphic(sx, sy, old_graphic, frame);
1952 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
1953 player_is_opaque = TRUE;
1957 GfxElement[jx][jy] = EL_UNDEFINED;
1959 /* make sure that pushed elements are drawn with correct frame rate */
1960 if (player->is_pushing && player->is_moving)
1961 GfxFrame[jx][jy] = player->StepFrame;
1963 DrawLevelField(jx, jy);
1967 /* ----------------------------------------------------------------------- */
1968 /* draw player himself */
1969 /* ----------------------------------------------------------------------- */
1971 graphic = getPlayerGraphic(player, move_dir);
1973 /* in the case of changed player action or direction, prevent the current
1974 animation frame from being restarted for identical animations */
1975 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
1976 player->Frame = last_player_frame;
1978 frame = getGraphicAnimationFrame(graphic, player->Frame);
1982 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1983 sxx = player->GfxPos;
1985 syy = player->GfxPos;
1988 if (!setup.soft_scrolling && ScreenMovPos)
1991 if (player_is_opaque)
1992 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
1994 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
1996 if (SHIELD_ON(player))
1998 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
1999 IMG_SHIELD_NORMAL_ACTIVE);
2000 int frame = getGraphicAnimationFrame(graphic, -1);
2002 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2005 /* ----------------------------------------------------------------------- */
2006 /* draw things the player is pushing, if needed */
2007 /* ----------------------------------------------------------------------- */
2010 printf("::: %d, %d [%d, %d] [%d]\n",
2011 player->is_pushing, player_is_moving, player->GfxAction,
2012 player->is_moving, player_is_moving);
2016 if (player->is_pushing && player->is_moving)
2018 int px = SCREENX(jx), py = SCREENY(jy);
2019 int pxx = (TILEX - ABS(sxx)) * dx;
2020 int pyy = (TILEY - ABS(syy)) * dy;
2025 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2026 element = Feld[next_jx][next_jy];
2028 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2029 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2031 /* draw background element under pushed element (like the Sokoban field) */
2032 if (Back[next_jx][next_jy])
2033 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2035 /* masked drawing is needed for EMC style (double) movement graphics */
2036 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2040 /* ----------------------------------------------------------------------- */
2041 /* draw things in front of player (active dynamite or dynabombs) */
2042 /* ----------------------------------------------------------------------- */
2044 if (IS_ACTIVE_BOMB(element))
2046 graphic = el2img(element);
2047 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2049 if (game.emulation == EMU_SUPAPLEX)
2050 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2052 DrawGraphicThruMask(sx, sy, graphic, frame);
2055 if (player_is_moving && last_element == EL_EXPLOSION)
2057 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2058 GfxElement[last_jx][last_jy] : EL_EMPTY);
2059 int graphic = el_act2img(element, ACTION_EXPLODING);
2060 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2061 int phase = ExplodePhase[last_jx][last_jy] - 1;
2062 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2065 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2068 /* ----------------------------------------------------------------------- */
2069 /* draw elements the player is just walking/passing through/under */
2070 /* ----------------------------------------------------------------------- */
2072 if (player_is_moving)
2074 /* handle the field the player is leaving ... */
2075 if (IS_ACCESSIBLE_INSIDE(last_element))
2076 DrawLevelField(last_jx, last_jy);
2077 else if (IS_ACCESSIBLE_UNDER(last_element))
2078 DrawLevelFieldThruMask(last_jx, last_jy);
2081 /* do not redraw accessible elements if the player is just pushing them */
2082 if (!player_is_moving || !player->is_pushing)
2084 /* ... and the field the player is entering */
2085 if (IS_ACCESSIBLE_INSIDE(element))
2086 DrawLevelField(jx, jy);
2087 else if (IS_ACCESSIBLE_UNDER(element))
2088 DrawLevelFieldThruMask(jx, jy);
2091 if (setup.direct_draw)
2093 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2094 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2095 int x_size = TILEX * (1 + ABS(jx - last_jx));
2096 int y_size = TILEY * (1 + ABS(jy - last_jy));
2098 BlitBitmap(drawto_field, window,
2099 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2100 SetDrawtoField(DRAW_DIRECT);
2103 MarkTileDirty(sx, sy);
2106 /* ------------------------------------------------------------------------- */
2108 void WaitForEventToContinue()
2110 boolean still_wait = TRUE;
2112 /* simulate releasing mouse button over last gadget, if still pressed */
2114 HandleGadgets(-1, -1, 0);
2116 button_status = MB_RELEASED;
2128 case EVENT_BUTTONPRESS:
2129 case EVENT_KEYPRESS:
2133 case EVENT_KEYRELEASE:
2134 ClearPlayerAction();
2138 HandleOtherEvents(&event);
2142 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2149 /* don't eat all CPU time */
2154 #define MAX_REQUEST_LINES 13
2155 #define MAX_REQUEST_LINE_FONT1_LEN 7
2156 #define MAX_REQUEST_LINE_FONT2_LEN 10
2158 boolean Request(char *text, unsigned int req_state)
2160 int mx, my, ty, result = -1;
2161 unsigned int old_door_state;
2162 int last_game_status = game_status; /* save current game status */
2163 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2164 int font_nr = FONT_TEXT_2;
2165 int max_word_len = 0;
2168 for (text_ptr = text; *text_ptr; text_ptr++)
2170 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2172 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2174 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2175 font_nr = FONT_LEVEL_NUMBER;
2181 if (game_status == GAME_MODE_PLAYING &&
2182 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2183 BlitScreenToBitmap_EM(backbuffer);
2185 /* disable deactivated drawing when quick-loading level tape recording */
2186 if (tape.playing && tape.deactivate_display)
2187 TapeDeactivateDisplayOff(TRUE);
2189 SetMouseCursor(CURSOR_DEFAULT);
2191 #if defined(NETWORK_AVALIABLE)
2192 /* pause network game while waiting for request to answer */
2193 if (options.network &&
2194 game_status == GAME_MODE_PLAYING &&
2195 req_state & REQUEST_WAIT_FOR_INPUT)
2196 SendToServer_PausePlaying();
2199 old_door_state = GetDoorState();
2201 /* simulate releasing mouse button over last gadget, if still pressed */
2203 HandleGadgets(-1, -1, 0);
2207 if (old_door_state & DOOR_OPEN_1)
2209 CloseDoor(DOOR_CLOSE_1);
2211 /* save old door content */
2212 BlitBitmap(bitmap_db_door, bitmap_db_door,
2213 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2214 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2217 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2219 /* clear door drawing field */
2220 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2222 /* force DOOR font on preview level */
2223 game_status = GAME_MODE_PSEUDO_DOOR;
2225 /* write text for request */
2226 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2228 char text_line[max_request_line_len + 1];
2234 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2237 if (!tc || tc == ' ')
2248 strncpy(text_line, text, tl);
2251 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2252 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2253 text_line, font_nr);
2255 text += tl + (tc == ' ' ? 1 : 0);
2258 game_status = last_game_status; /* restore current game status */
2260 if (req_state & REQ_ASK)
2262 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2263 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2265 else if (req_state & REQ_CONFIRM)
2267 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2269 else if (req_state & REQ_PLAYER)
2271 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2272 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2273 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2274 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2277 /* copy request gadgets to door backbuffer */
2278 BlitBitmap(drawto, bitmap_db_door,
2279 DX, DY, DXSIZE, DYSIZE,
2280 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2282 OpenDoor(DOOR_OPEN_1);
2284 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2286 SetDrawBackgroundMask(REDRAW_FIELD);
2291 if (game_status != GAME_MODE_MAIN)
2294 button_status = MB_RELEASED;
2296 request_gadget_id = -1;
2298 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2310 case EVENT_BUTTONPRESS:
2311 case EVENT_BUTTONRELEASE:
2312 case EVENT_MOTIONNOTIFY:
2314 if (event.type == EVENT_MOTIONNOTIFY)
2316 if (!PointerInWindow(window))
2317 continue; /* window and pointer are on different screens */
2322 motion_status = TRUE;
2323 mx = ((MotionEvent *) &event)->x;
2324 my = ((MotionEvent *) &event)->y;
2328 motion_status = FALSE;
2329 mx = ((ButtonEvent *) &event)->x;
2330 my = ((ButtonEvent *) &event)->y;
2331 if (event.type == EVENT_BUTTONPRESS)
2332 button_status = ((ButtonEvent *) &event)->button;
2334 button_status = MB_RELEASED;
2337 /* this sets 'request_gadget_id' */
2338 HandleGadgets(mx, my, button_status);
2340 switch(request_gadget_id)
2342 case TOOL_CTRL_ID_YES:
2345 case TOOL_CTRL_ID_NO:
2348 case TOOL_CTRL_ID_CONFIRM:
2349 result = TRUE | FALSE;
2352 case TOOL_CTRL_ID_PLAYER_1:
2355 case TOOL_CTRL_ID_PLAYER_2:
2358 case TOOL_CTRL_ID_PLAYER_3:
2361 case TOOL_CTRL_ID_PLAYER_4:
2372 case EVENT_KEYPRESS:
2373 switch(GetEventKey((KeyEvent *)&event, TRUE))
2386 if (req_state & REQ_PLAYER)
2390 case EVENT_KEYRELEASE:
2391 ClearPlayerAction();
2395 HandleOtherEvents(&event);
2399 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2401 int joy = AnyJoystick();
2403 if (joy & JOY_BUTTON_1)
2405 else if (joy & JOY_BUTTON_2)
2411 /* don't eat all CPU time */
2415 if (game_status != GAME_MODE_MAIN)
2420 if (!(req_state & REQ_STAY_OPEN))
2422 CloseDoor(DOOR_CLOSE_1);
2424 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2425 (req_state & REQ_REOPEN))
2426 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2431 SetDrawBackgroundMask(REDRAW_FIELD);
2433 #if defined(NETWORK_AVALIABLE)
2434 /* continue network game after request */
2435 if (options.network &&
2436 game_status == GAME_MODE_PLAYING &&
2437 req_state & REQUEST_WAIT_FOR_INPUT)
2438 SendToServer_ContinuePlaying();
2441 /* restore deactivated drawing when quick-loading level tape recording */
2442 if (tape.playing && tape.deactivate_display)
2443 TapeDeactivateDisplayOn();
2448 unsigned int OpenDoor(unsigned int door_state)
2450 if (door_state & DOOR_COPY_BACK)
2452 if (door_state & DOOR_OPEN_1)
2453 BlitBitmap(bitmap_db_door, bitmap_db_door,
2454 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2455 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2457 if (door_state & DOOR_OPEN_2)
2458 BlitBitmap(bitmap_db_door, bitmap_db_door,
2459 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2460 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2462 door_state &= ~DOOR_COPY_BACK;
2465 return MoveDoor(door_state);
2468 unsigned int CloseDoor(unsigned int door_state)
2470 unsigned int old_door_state = GetDoorState();
2472 if (!(door_state & DOOR_NO_COPY_BACK))
2474 if (old_door_state & DOOR_OPEN_1)
2475 BlitBitmap(backbuffer, bitmap_db_door,
2476 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2478 if (old_door_state & DOOR_OPEN_2)
2479 BlitBitmap(backbuffer, bitmap_db_door,
2480 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2482 door_state &= ~DOOR_NO_COPY_BACK;
2485 return MoveDoor(door_state);
2488 unsigned int GetDoorState()
2490 return MoveDoor(DOOR_GET_STATE);
2493 unsigned int SetDoorState(unsigned int door_state)
2495 return MoveDoor(door_state | DOOR_SET_STATE);
2498 unsigned int MoveDoor(unsigned int door_state)
2500 static int door1 = DOOR_OPEN_1;
2501 static int door2 = DOOR_CLOSE_2;
2502 unsigned long door_delay = 0;
2503 unsigned long door_delay_value;
2506 if (door_1.width < 0 || door_1.width > DXSIZE)
2507 door_1.width = DXSIZE;
2508 if (door_1.height < 0 || door_1.height > DYSIZE)
2509 door_1.height = DYSIZE;
2510 if (door_2.width < 0 || door_2.width > VXSIZE)
2511 door_2.width = VXSIZE;
2512 if (door_2.height < 0 || door_2.height > VYSIZE)
2513 door_2.height = VYSIZE;
2515 if (door_state == DOOR_GET_STATE)
2516 return(door1 | door2);
2518 if (door_state & DOOR_SET_STATE)
2520 if (door_state & DOOR_ACTION_1)
2521 door1 = door_state & DOOR_ACTION_1;
2522 if (door_state & DOOR_ACTION_2)
2523 door2 = door_state & DOOR_ACTION_2;
2525 return(door1 | door2);
2528 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2529 door_state &= ~DOOR_OPEN_1;
2530 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2531 door_state &= ~DOOR_CLOSE_1;
2532 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2533 door_state &= ~DOOR_OPEN_2;
2534 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2535 door_state &= ~DOOR_CLOSE_2;
2537 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2540 if (setup.quick_doors)
2542 stepsize = 20; /* must be choosen to always draw last frame */
2543 door_delay_value = 0;
2546 if (global.autoplay_leveldir)
2548 door_state |= DOOR_NO_DELAY;
2549 door_state &= ~DOOR_CLOSE_ALL;
2552 if (door_state & DOOR_ACTION)
2554 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2555 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2556 boolean door_1_done = (!handle_door_1);
2557 boolean door_2_done = (!handle_door_2);
2558 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2559 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2560 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2561 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2562 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2563 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2564 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2565 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2566 int door_skip = max_door_size - door_size;
2568 int end = door_size;
2570 int end = (door_state & DOOR_ACTION_1 &&
2571 door_1.anim_mode & ANIM_VERTICAL ? DYSIZE : DXSIZE);
2574 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2576 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2580 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2582 /* opening door sound has priority over simultaneously closing door */
2583 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2584 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2585 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2586 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2589 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2592 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2593 GC gc = bitmap->stored_clip_gc;
2595 if (door_state & DOOR_ACTION_1)
2597 int a = MIN(x * door_1.step_offset, end);
2598 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2599 int i = p + door_skip;
2601 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2603 BlitBitmap(bitmap_db_door, drawto,
2604 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2605 DXSIZE, DYSIZE, DX, DY);
2609 BlitBitmap(bitmap_db_door, drawto,
2610 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2611 DXSIZE, DYSIZE - p / 2, DX, DY);
2613 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2616 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2618 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2619 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2620 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2621 int dst2_x = DX, dst2_y = DY;
2622 int width = i, height = DYSIZE;
2624 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2625 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2628 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2629 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2632 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2634 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2635 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2636 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2637 int dst2_x = DX, dst2_y = DY;
2638 int width = DXSIZE, height = i;
2640 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2641 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2644 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2645 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2648 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2650 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2652 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2653 BlitBitmapMasked(bitmap, drawto,
2654 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2655 DX + DXSIZE - i, DY + j);
2656 BlitBitmapMasked(bitmap, drawto,
2657 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2658 DX + DXSIZE - i, DY + 140 + j);
2659 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2660 DY - (DOOR_GFX_PAGEY1 + j));
2661 BlitBitmapMasked(bitmap, drawto,
2662 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2664 BlitBitmapMasked(bitmap, drawto,
2665 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2668 BlitBitmapMasked(bitmap, drawto,
2669 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2671 BlitBitmapMasked(bitmap, drawto,
2672 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2674 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2675 BlitBitmapMasked(bitmap, drawto,
2676 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2677 DX + DXSIZE - i, DY + 77 + j);
2678 BlitBitmapMasked(bitmap, drawto,
2679 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2680 DX + DXSIZE - i, DY + 203 + j);
2683 redraw_mask |= REDRAW_DOOR_1;
2684 door_1_done = (a == end);
2687 if (door_state & DOOR_ACTION_2)
2689 int a = MIN(x * door_2.step_offset, door_size_2);
2690 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2691 int i = p + door_skip;
2693 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2695 BlitBitmap(bitmap_db_door, drawto,
2696 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2697 VXSIZE, VYSIZE, VX, VY);
2699 else if (x <= VYSIZE)
2701 BlitBitmap(bitmap_db_door, drawto,
2702 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2703 VXSIZE, VYSIZE - p / 2, VX, VY);
2705 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2708 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2710 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2711 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2712 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2713 int dst2_x = VX, dst2_y = VY;
2714 int width = i, height = VYSIZE;
2716 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2717 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2720 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2721 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2724 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2726 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2727 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2728 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2729 int dst2_x = VX, dst2_y = VY;
2730 int width = VXSIZE, height = i;
2732 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2733 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2736 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2737 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2740 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2742 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2744 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2745 BlitBitmapMasked(bitmap, drawto,
2746 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2747 VX + VXSIZE - i, VY + j);
2748 SetClipOrigin(bitmap, gc,
2749 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2750 BlitBitmapMasked(bitmap, drawto,
2751 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2754 BlitBitmapMasked(bitmap, drawto,
2755 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2756 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2757 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2758 BlitBitmapMasked(bitmap, drawto,
2759 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2761 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2764 redraw_mask |= REDRAW_DOOR_2;
2765 door_2_done = (a == VXSIZE);
2770 if (game_status == GAME_MODE_MAIN)
2773 if (!(door_state & DOOR_NO_DELAY))
2774 WaitUntilDelayReached(&door_delay, door_delay_value);
2778 if (door_state & DOOR_ACTION_1)
2779 door1 = door_state & DOOR_ACTION_1;
2780 if (door_state & DOOR_ACTION_2)
2781 door2 = door_state & DOOR_ACTION_2;
2783 return (door1 | door2);
2786 void DrawSpecialEditorDoor()
2788 /* draw bigger toolbox window */
2789 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2790 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2792 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2793 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2796 redraw_mask |= REDRAW_ALL;
2799 void UndrawSpecialEditorDoor()
2801 /* draw normal tape recorder window */
2802 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2803 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2806 redraw_mask |= REDRAW_ALL;
2810 /* ---------- new tool button stuff ---------------------------------------- */
2812 /* graphic position values for tool buttons */
2813 #define TOOL_BUTTON_YES_XPOS 2
2814 #define TOOL_BUTTON_YES_YPOS 250
2815 #define TOOL_BUTTON_YES_GFX_YPOS 0
2816 #define TOOL_BUTTON_YES_XSIZE 46
2817 #define TOOL_BUTTON_YES_YSIZE 28
2818 #define TOOL_BUTTON_NO_XPOS 52
2819 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2820 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2821 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2822 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2823 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2824 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2825 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2826 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2827 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2828 #define TOOL_BUTTON_PLAYER_XSIZE 30
2829 #define TOOL_BUTTON_PLAYER_YSIZE 30
2830 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2831 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2832 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2833 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2834 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2835 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2836 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2837 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2838 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2839 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2840 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2841 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2842 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2843 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2844 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2845 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2846 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2847 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2848 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2849 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2858 } toolbutton_info[NUM_TOOL_BUTTONS] =
2861 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2862 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2863 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2868 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2869 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2870 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2875 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2876 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2877 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2878 TOOL_CTRL_ID_CONFIRM,
2882 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2883 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2884 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2885 TOOL_CTRL_ID_PLAYER_1,
2889 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2890 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2891 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2892 TOOL_CTRL_ID_PLAYER_2,
2896 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2897 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2898 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2899 TOOL_CTRL_ID_PLAYER_3,
2903 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2904 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2905 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2906 TOOL_CTRL_ID_PLAYER_4,
2911 void CreateToolButtons()
2915 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2917 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2918 Bitmap *deco_bitmap = None;
2919 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2920 struct GadgetInfo *gi;
2921 unsigned long event_mask;
2922 int gd_xoffset, gd_yoffset;
2923 int gd_x1, gd_x2, gd_y;
2926 event_mask = GD_EVENT_RELEASED;
2928 gd_xoffset = toolbutton_info[i].xpos;
2929 gd_yoffset = toolbutton_info[i].ypos;
2930 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2931 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2932 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2934 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2936 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2938 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2939 &deco_bitmap, &deco_x, &deco_y);
2940 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2941 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2944 gi = CreateGadget(GDI_CUSTOM_ID, id,
2945 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2946 GDI_X, DX + toolbutton_info[i].x,
2947 GDI_Y, DY + toolbutton_info[i].y,
2948 GDI_WIDTH, toolbutton_info[i].width,
2949 GDI_HEIGHT, toolbutton_info[i].height,
2950 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2951 GDI_STATE, GD_BUTTON_UNPRESSED,
2952 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2953 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2954 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2955 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2956 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2957 GDI_DECORATION_SHIFTING, 1, 1,
2958 GDI_EVENT_MASK, event_mask,
2959 GDI_CALLBACK_ACTION, HandleToolButtons,
2963 Error(ERR_EXIT, "cannot create gadget");
2965 tool_gadget[id] = gi;
2969 void FreeToolButtons()
2973 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2974 FreeGadget(tool_gadget[i]);
2977 static void UnmapToolButtons()
2981 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2982 UnmapGadget(tool_gadget[i]);
2985 static void HandleToolButtons(struct GadgetInfo *gi)
2987 request_gadget_id = gi->custom_id;
2990 static struct Mapping_EM_to_RND_object
2993 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
2994 boolean is_backside; /* backside of moving element */
3000 em_object_mapping_list[] =
3003 Xblank, TRUE, FALSE,
3007 Yacid_splash_eB, FALSE, FALSE,
3008 EL_ACID_SPLASH_RIGHT, -1, -1
3011 Yacid_splash_wB, FALSE, FALSE,
3012 EL_ACID_SPLASH_LEFT, -1, -1
3015 #ifdef EM_ENGINE_BAD_ROLL
3017 Xstone_force_e, FALSE, FALSE,
3018 EL_ROCK, -1, MV_BIT_RIGHT
3021 Xstone_force_w, FALSE, FALSE,
3022 EL_ROCK, -1, MV_BIT_LEFT
3025 Xnut_force_e, FALSE, FALSE,
3026 EL_NUT, -1, MV_BIT_RIGHT
3029 Xnut_force_w, FALSE, FALSE,
3030 EL_NUT, -1, MV_BIT_LEFT
3033 Xspring_force_e, FALSE, FALSE,
3034 EL_SPRING, -1, MV_BIT_RIGHT
3037 Xspring_force_w, FALSE, FALSE,
3038 EL_SPRING, -1, MV_BIT_LEFT
3041 Xemerald_force_e, FALSE, FALSE,
3042 EL_EMERALD, -1, MV_BIT_RIGHT
3045 Xemerald_force_w, FALSE, FALSE,
3046 EL_EMERALD, -1, MV_BIT_LEFT
3049 Xdiamond_force_e, FALSE, FALSE,
3050 EL_DIAMOND, -1, MV_BIT_RIGHT
3053 Xdiamond_force_w, FALSE, FALSE,
3054 EL_DIAMOND, -1, MV_BIT_LEFT
3057 Xbomb_force_e, FALSE, FALSE,
3058 EL_BOMB, -1, MV_BIT_RIGHT
3061 Xbomb_force_w, FALSE, FALSE,
3062 EL_BOMB, -1, MV_BIT_LEFT
3064 #endif /* EM_ENGINE_BAD_ROLL */
3067 Xstone, TRUE, FALSE,
3071 Xstone_pause, FALSE, FALSE,
3075 Xstone_fall, FALSE, FALSE,
3079 Ystone_s, FALSE, FALSE,
3080 EL_ROCK, ACTION_FALLING, -1
3083 Ystone_sB, FALSE, TRUE,
3084 EL_ROCK, ACTION_FALLING, -1
3087 Ystone_e, FALSE, FALSE,
3088 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3091 Ystone_eB, FALSE, TRUE,
3092 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3095 Ystone_w, FALSE, FALSE,
3096 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3099 Ystone_wB, FALSE, TRUE,
3100 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3107 Xnut_pause, FALSE, FALSE,
3111 Xnut_fall, FALSE, FALSE,
3115 Ynut_s, FALSE, FALSE,
3116 EL_NUT, ACTION_FALLING, -1
3119 Ynut_sB, FALSE, TRUE,
3120 EL_NUT, ACTION_FALLING, -1
3123 Ynut_e, FALSE, FALSE,
3124 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3127 Ynut_eB, FALSE, TRUE,
3128 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3131 Ynut_w, FALSE, FALSE,
3132 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3135 Ynut_wB, FALSE, TRUE,
3136 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3139 Xbug_n, TRUE, FALSE,
3143 Xbug_e, TRUE, FALSE,
3144 EL_BUG_RIGHT, -1, -1
3147 Xbug_s, TRUE, FALSE,
3151 Xbug_w, TRUE, FALSE,
3155 Xbug_gon, FALSE, FALSE,
3159 Xbug_goe, FALSE, FALSE,
3160 EL_BUG_RIGHT, -1, -1
3163 Xbug_gos, FALSE, FALSE,
3167 Xbug_gow, FALSE, FALSE,
3171 Ybug_n, FALSE, FALSE,
3172 EL_BUG, ACTION_MOVING, MV_BIT_UP
3175 Ybug_nB, FALSE, TRUE,
3176 EL_BUG, ACTION_MOVING, MV_BIT_UP
3179 Ybug_e, FALSE, FALSE,
3180 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3183 Ybug_eB, FALSE, TRUE,
3184 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3187 Ybug_s, FALSE, FALSE,
3188 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3191 Ybug_sB, FALSE, TRUE,
3192 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3195 Ybug_w, FALSE, FALSE,
3196 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3199 Ybug_wB, FALSE, TRUE,
3200 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3203 Ybug_w_n, FALSE, FALSE,
3204 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3207 Ybug_n_e, FALSE, FALSE,
3208 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3211 Ybug_e_s, FALSE, FALSE,
3212 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3215 Ybug_s_w, FALSE, FALSE,
3216 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3219 Ybug_e_n, FALSE, FALSE,
3220 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3223 Ybug_s_e, FALSE, FALSE,
3224 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3227 Ybug_w_s, FALSE, FALSE,
3228 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3231 Ybug_n_w, FALSE, FALSE,
3232 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3235 Ybug_stone, FALSE, FALSE,
3236 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3239 Ybug_spring, FALSE, FALSE,
3240 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3243 Xtank_n, TRUE, FALSE,
3244 EL_SPACESHIP_UP, -1, -1
3247 Xtank_e, TRUE, FALSE,
3248 EL_SPACESHIP_RIGHT, -1, -1
3251 Xtank_s, TRUE, FALSE,
3252 EL_SPACESHIP_DOWN, -1, -1
3255 Xtank_w, TRUE, FALSE,
3256 EL_SPACESHIP_LEFT, -1, -1
3259 Xtank_gon, FALSE, FALSE,
3260 EL_SPACESHIP_UP, -1, -1
3263 Xtank_goe, FALSE, FALSE,
3264 EL_SPACESHIP_RIGHT, -1, -1
3267 Xtank_gos, FALSE, FALSE,
3268 EL_SPACESHIP_DOWN, -1, -1
3271 Xtank_gow, FALSE, FALSE,
3272 EL_SPACESHIP_LEFT, -1, -1
3275 Ytank_n, FALSE, FALSE,
3276 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3279 Ytank_nB, FALSE, TRUE,
3280 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3283 Ytank_e, FALSE, FALSE,
3284 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3287 Ytank_eB, FALSE, TRUE,
3288 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3291 Ytank_s, FALSE, FALSE,
3292 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3295 Ytank_sB, FALSE, TRUE,
3296 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3299 Ytank_w, FALSE, FALSE,
3300 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3303 Ytank_wB, FALSE, TRUE,
3304 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3307 Ytank_w_n, FALSE, FALSE,
3308 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3311 Ytank_n_e, FALSE, FALSE,
3312 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3315 Ytank_e_s, FALSE, FALSE,
3316 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3319 Ytank_s_w, FALSE, FALSE,
3320 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3323 Ytank_e_n, FALSE, FALSE,
3324 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3327 Ytank_s_e, FALSE, FALSE,
3328 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3331 Ytank_w_s, FALSE, FALSE,
3332 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3335 Ytank_n_w, FALSE, FALSE,
3336 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3339 Ytank_stone, FALSE, FALSE,
3340 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3343 Ytank_spring, FALSE, FALSE,
3344 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3347 Xandroid, TRUE, FALSE,
3348 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3351 Xandroid_1_n, FALSE, FALSE,
3352 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3355 Xandroid_2_n, FALSE, FALSE,
3356 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3359 Xandroid_1_e, FALSE, FALSE,
3360 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3363 Xandroid_2_e, FALSE, FALSE,
3364 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3367 Xandroid_1_w, FALSE, FALSE,
3368 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3371 Xandroid_2_w, FALSE, FALSE,
3372 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3375 Xandroid_1_s, FALSE, FALSE,
3376 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3379 Xandroid_2_s, FALSE, FALSE,
3380 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3383 Yandroid_n, FALSE, FALSE,
3384 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3387 Yandroid_nB, FALSE, TRUE,
3388 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3391 Yandroid_ne, FALSE, FALSE,
3392 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3395 Yandroid_neB, FALSE, TRUE,
3396 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3399 Yandroid_e, FALSE, FALSE,
3400 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3403 Yandroid_eB, FALSE, TRUE,
3404 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3407 Yandroid_se, FALSE, FALSE,
3408 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3411 Yandroid_seB, FALSE, TRUE,
3412 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3415 Yandroid_s, FALSE, FALSE,
3416 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3419 Yandroid_sB, FALSE, TRUE,
3420 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3423 Yandroid_sw, FALSE, FALSE,
3424 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3427 Yandroid_swB, FALSE, TRUE,
3428 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3431 Yandroid_w, FALSE, FALSE,
3432 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3435 Yandroid_wB, FALSE, TRUE,
3436 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3439 Yandroid_nw, FALSE, FALSE,
3440 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3443 Yandroid_nwB, FALSE, TRUE,
3444 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3447 Xspring, TRUE, FALSE,
3451 Xspring_pause, FALSE, FALSE,
3455 Xspring_e, FALSE, FALSE,
3459 Xspring_w, FALSE, FALSE,
3463 Xspring_fall, FALSE, FALSE,
3467 Yspring_s, FALSE, FALSE,
3468 EL_SPRING, ACTION_FALLING, -1
3471 Yspring_sB, FALSE, TRUE,
3472 EL_SPRING, ACTION_FALLING, -1
3475 Yspring_e, FALSE, FALSE,
3476 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3479 Yspring_eB, FALSE, TRUE,
3480 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3483 Yspring_w, FALSE, FALSE,
3484 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3487 Yspring_wB, FALSE, TRUE,
3488 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3491 Yspring_kill_e, FALSE, FALSE,
3492 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3495 Yspring_kill_eB, FALSE, TRUE,
3496 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3499 Yspring_kill_w, FALSE, FALSE,
3500 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3503 Yspring_kill_wB, FALSE, TRUE,
3504 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3507 Xeater_n, TRUE, FALSE,
3508 EL_YAMYAM_UP, -1, -1
3511 Xeater_e, TRUE, FALSE,
3512 EL_YAMYAM_RIGHT, -1, -1
3515 Xeater_w, TRUE, FALSE,
3516 EL_YAMYAM_LEFT, -1, -1
3519 Xeater_s, TRUE, FALSE,
3520 EL_YAMYAM_DOWN, -1, -1
3523 Yeater_n, FALSE, FALSE,
3524 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3527 Yeater_nB, FALSE, TRUE,
3528 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3531 Yeater_e, FALSE, FALSE,
3532 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3535 Yeater_eB, FALSE, TRUE,
3536 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3539 Yeater_s, FALSE, FALSE,
3540 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3543 Yeater_sB, FALSE, TRUE,
3544 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3547 Yeater_w, FALSE, FALSE,
3548 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3551 Yeater_wB, FALSE, TRUE,
3552 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3555 Yeater_stone, FALSE, FALSE,
3556 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3559 Yeater_spring, FALSE, FALSE,
3560 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3563 Xalien, TRUE, FALSE,
3567 Xalien_pause, FALSE, FALSE,
3571 Yalien_n, FALSE, FALSE,
3572 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3575 Yalien_nB, FALSE, TRUE,
3576 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3579 Yalien_e, FALSE, FALSE,
3580 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3583 Yalien_eB, FALSE, TRUE,
3584 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3587 Yalien_s, FALSE, FALSE,
3588 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3591 Yalien_sB, FALSE, TRUE,
3592 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3595 Yalien_w, FALSE, FALSE,
3596 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3599 Yalien_wB, FALSE, TRUE,
3600 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3603 Yalien_stone, FALSE, FALSE,
3604 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3607 Yalien_spring, FALSE, FALSE,
3608 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3611 Xemerald, TRUE, FALSE,
3615 Xemerald_pause, FALSE, FALSE,
3619 Xemerald_fall, FALSE, FALSE,
3623 Xemerald_shine, FALSE, FALSE,
3624 EL_EMERALD, ACTION_TWINKLING, -1
3627 Yemerald_s, FALSE, FALSE,
3628 EL_EMERALD, ACTION_FALLING, -1
3631 Yemerald_sB, FALSE, TRUE,
3632 EL_EMERALD, ACTION_FALLING, -1
3635 Yemerald_e, FALSE, FALSE,
3636 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3639 Yemerald_eB, FALSE, TRUE,
3640 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3643 Yemerald_w, FALSE, FALSE,
3644 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3647 Yemerald_wB, FALSE, TRUE,
3648 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3651 Yemerald_eat, FALSE, FALSE,
3652 EL_EMERALD, ACTION_COLLECTING, -1
3655 Yemerald_stone, FALSE, FALSE,
3656 EL_NUT, ACTION_BREAKING, -1
3659 Xdiamond, TRUE, FALSE,
3663 Xdiamond_pause, FALSE, FALSE,
3667 Xdiamond_fall, FALSE, FALSE,
3671 Xdiamond_shine, FALSE, FALSE,
3672 EL_DIAMOND, ACTION_TWINKLING, -1
3675 Ydiamond_s, FALSE, FALSE,
3676 EL_DIAMOND, ACTION_FALLING, -1
3679 Ydiamond_sB, FALSE, TRUE,
3680 EL_DIAMOND, ACTION_FALLING, -1
3683 Ydiamond_e, FALSE, FALSE,
3684 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3687 Ydiamond_eB, FALSE, TRUE,
3688 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3691 Ydiamond_w, FALSE, FALSE,
3692 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3695 Ydiamond_wB, FALSE, TRUE,
3696 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3699 Ydiamond_eat, FALSE, FALSE,
3700 EL_DIAMOND, ACTION_COLLECTING, -1
3703 Ydiamond_stone, FALSE, FALSE,
3704 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3707 Xdrip_fall, TRUE, FALSE,
3708 EL_AMOEBA_DROP, -1, -1
3711 Xdrip_stretch, FALSE, FALSE,
3712 EL_AMOEBA_DROP, ACTION_FALLING, -1
3715 Xdrip_stretchB, FALSE, TRUE,
3716 EL_AMOEBA_DROP, ACTION_FALLING, -1
3719 Xdrip_eat, FALSE, FALSE,
3720 EL_AMOEBA_DROP, ACTION_GROWING, -1
3723 Ydrip_s1, FALSE, FALSE,
3724 EL_AMOEBA_DROP, ACTION_FALLING, -1
3727 Ydrip_s1B, FALSE, TRUE,
3728 EL_AMOEBA_DROP, ACTION_FALLING, -1
3731 Ydrip_s2, FALSE, FALSE,
3732 EL_AMOEBA_DROP, ACTION_FALLING, -1
3735 Ydrip_s2B, FALSE, TRUE,
3736 EL_AMOEBA_DROP, ACTION_FALLING, -1
3743 Xbomb_pause, FALSE, FALSE,
3747 Xbomb_fall, FALSE, FALSE,
3751 Ybomb_s, FALSE, FALSE,
3752 EL_BOMB, ACTION_FALLING, -1
3755 Ybomb_sB, FALSE, TRUE,
3756 EL_BOMB, ACTION_FALLING, -1
3759 Ybomb_e, FALSE, FALSE,
3760 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3763 Ybomb_eB, FALSE, TRUE,
3764 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3767 Ybomb_w, FALSE, FALSE,
3768 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3771 Ybomb_wB, FALSE, TRUE,
3772 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3775 Ybomb_eat, FALSE, FALSE,
3776 EL_BOMB, ACTION_ACTIVATING, -1
3779 Xballoon, TRUE, FALSE,
3783 Yballoon_n, FALSE, FALSE,
3784 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3787 Yballoon_nB, FALSE, TRUE,
3788 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3791 Yballoon_e, FALSE, FALSE,
3792 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3795 Yballoon_eB, FALSE, TRUE,
3796 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3799 Yballoon_s, FALSE, FALSE,
3800 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3803 Yballoon_sB, FALSE, TRUE,
3804 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3807 Yballoon_w, FALSE, FALSE,
3808 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3811 Yballoon_wB, FALSE, TRUE,
3812 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3815 Xgrass, TRUE, FALSE,
3816 EL_EMC_GRASS, -1, -1
3819 Ygrass_nB, FALSE, FALSE,
3820 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3823 Ygrass_eB, FALSE, FALSE,
3824 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3827 Ygrass_sB, FALSE, FALSE,
3828 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3831 Ygrass_wB, FALSE, FALSE,
3832 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3839 Ydirt_nB, FALSE, FALSE,
3840 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3843 Ydirt_eB, FALSE, FALSE,
3844 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3847 Ydirt_sB, FALSE, FALSE,
3848 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3851 Ydirt_wB, FALSE, FALSE,
3852 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3855 Xacid_ne, TRUE, FALSE,
3856 EL_ACID_POOL_TOPRIGHT, -1, -1
3859 Xacid_se, TRUE, FALSE,
3860 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3863 Xacid_s, TRUE, FALSE,
3864 EL_ACID_POOL_BOTTOM, -1, -1
3867 Xacid_sw, TRUE, FALSE,
3868 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3871 Xacid_nw, TRUE, FALSE,
3872 EL_ACID_POOL_TOPLEFT, -1, -1
3875 Xacid_1, TRUE, FALSE,
3879 Xacid_2, FALSE, FALSE,
3883 Xacid_3, FALSE, FALSE,
3887 Xacid_4, FALSE, FALSE,
3891 Xacid_5, FALSE, FALSE,
3895 Xacid_6, FALSE, FALSE,
3899 Xacid_7, FALSE, FALSE,
3903 Xacid_8, FALSE, FALSE,
3907 Xball_1, TRUE, FALSE,
3908 EL_EMC_MAGIC_BALL, -1, -1
3911 Xball_1B, FALSE, FALSE,
3912 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3915 Xball_2, FALSE, FALSE,
3916 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3919 Xball_2B, FALSE, FALSE,
3920 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
3923 Yball_eat, FALSE, FALSE,
3924 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
3927 Ykey_1_eat, FALSE, FALSE,
3928 EL_EM_KEY_1, ACTION_COLLECTING, -1
3931 Ykey_2_eat, FALSE, FALSE,
3932 EL_EM_KEY_2, ACTION_COLLECTING, -1
3935 Ykey_3_eat, FALSE, FALSE,
3936 EL_EM_KEY_3, ACTION_COLLECTING, -1
3939 Ykey_4_eat, FALSE, FALSE,
3940 EL_EM_KEY_4, ACTION_COLLECTING, -1
3943 Ykey_5_eat, FALSE, FALSE,
3944 EL_EMC_KEY_5, ACTION_COLLECTING, -1
3947 Ykey_6_eat, FALSE, FALSE,
3948 EL_EMC_KEY_6, ACTION_COLLECTING, -1
3951 Ykey_7_eat, FALSE, FALSE,
3952 EL_EMC_KEY_7, ACTION_COLLECTING, -1
3955 Ykey_8_eat, FALSE, FALSE,
3956 EL_EMC_KEY_8, ACTION_COLLECTING, -1
3959 Ylenses_eat, FALSE, FALSE,
3960 EL_EMC_LENSES, ACTION_COLLECTING, -1
3963 Ymagnify_eat, FALSE, FALSE,
3964 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
3967 Ygrass_eat, FALSE, FALSE,
3968 EL_EMC_GRASS, ACTION_SNAPPING, -1
3971 Ydirt_eat, FALSE, FALSE,
3972 EL_SAND, ACTION_SNAPPING, -1
3975 Xgrow_ns, TRUE, FALSE,
3976 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
3979 Ygrow_ns_eat, FALSE, FALSE,
3980 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
3983 Xgrow_ew, TRUE, FALSE,
3984 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
3987 Ygrow_ew_eat, FALSE, FALSE,
3988 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
3991 Xwonderwall, TRUE, FALSE,
3992 EL_MAGIC_WALL, -1, -1
3995 XwonderwallB, FALSE, FALSE,
3996 EL_MAGIC_WALL, ACTION_ACTIVE, -1
3999 Xamoeba_1, TRUE, FALSE,
4000 EL_AMOEBA_DRY, ACTION_OTHER, -1
4003 Xamoeba_2, FALSE, FALSE,
4004 EL_AMOEBA_DRY, ACTION_OTHER, -1
4007 Xamoeba_3, FALSE, FALSE,
4008 EL_AMOEBA_DRY, ACTION_OTHER, -1
4011 Xamoeba_4, FALSE, FALSE,
4012 EL_AMOEBA_DRY, ACTION_OTHER, -1
4015 Xamoeba_5, TRUE, FALSE,
4016 EL_AMOEBA_WET, ACTION_OTHER, -1
4019 Xamoeba_6, FALSE, FALSE,
4020 EL_AMOEBA_WET, ACTION_OTHER, -1
4023 Xamoeba_7, FALSE, FALSE,
4024 EL_AMOEBA_WET, ACTION_OTHER, -1
4027 Xamoeba_8, FALSE, FALSE,
4028 EL_AMOEBA_WET, ACTION_OTHER, -1
4031 Xdoor_1, TRUE, FALSE,
4032 EL_EM_GATE_1, -1, -1
4035 Xdoor_2, TRUE, FALSE,
4036 EL_EM_GATE_2, -1, -1
4039 Xdoor_3, TRUE, FALSE,
4040 EL_EM_GATE_3, -1, -1
4043 Xdoor_4, TRUE, FALSE,
4044 EL_EM_GATE_4, -1, -1
4047 Xdoor_5, TRUE, FALSE,
4048 EL_EMC_GATE_5, -1, -1
4051 Xdoor_6, TRUE, FALSE,
4052 EL_EMC_GATE_6, -1, -1
4055 Xdoor_7, TRUE, FALSE,
4056 EL_EMC_GATE_7, -1, -1
4059 Xdoor_8, TRUE, FALSE,
4060 EL_EMC_GATE_8, -1, -1
4063 Xkey_1, TRUE, FALSE,
4067 Xkey_2, TRUE, FALSE,
4071 Xkey_3, TRUE, FALSE,
4075 Xkey_4, TRUE, FALSE,
4079 Xkey_5, TRUE, FALSE,
4080 EL_EMC_KEY_5, -1, -1
4083 Xkey_6, TRUE, FALSE,
4084 EL_EMC_KEY_6, -1, -1
4087 Xkey_7, TRUE, FALSE,
4088 EL_EMC_KEY_7, -1, -1
4091 Xkey_8, TRUE, FALSE,
4092 EL_EMC_KEY_8, -1, -1
4095 Xwind_n, TRUE, FALSE,
4096 EL_BALLOON_SWITCH_UP, -1, -1
4099 Xwind_e, TRUE, FALSE,
4100 EL_BALLOON_SWITCH_RIGHT, -1, -1
4103 Xwind_s, TRUE, FALSE,
4104 EL_BALLOON_SWITCH_DOWN, -1, -1
4107 Xwind_w, TRUE, FALSE,
4108 EL_BALLOON_SWITCH_LEFT, -1, -1
4111 Xwind_nesw, TRUE, FALSE,
4112 EL_BALLOON_SWITCH_ANY, -1, -1
4115 Xwind_stop, TRUE, FALSE,
4116 EL_BALLOON_SWITCH_NONE, -1, -1
4120 EL_EXIT_CLOSED, -1, -1
4123 Xexit_1, TRUE, FALSE,
4124 EL_EXIT_OPEN, -1, -1
4127 Xexit_2, FALSE, FALSE,
4128 EL_EXIT_OPEN, -1, -1
4131 Xexit_3, FALSE, FALSE,
4132 EL_EXIT_OPEN, -1, -1
4135 Xdynamite, TRUE, FALSE,
4136 EL_EM_DYNAMITE, -1, -1
4139 Ydynamite_eat, FALSE, FALSE,
4140 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4143 Xdynamite_1, TRUE, FALSE,
4144 EL_EM_DYNAMITE_ACTIVE, -1, -1
4147 Xdynamite_2, FALSE, FALSE,
4148 EL_EM_DYNAMITE_ACTIVE, -1, -1
4151 Xdynamite_3, FALSE, FALSE,
4152 EL_EM_DYNAMITE_ACTIVE, -1, -1
4155 Xdynamite_4, FALSE, FALSE,
4156 EL_EM_DYNAMITE_ACTIVE, -1, -1
4159 Xbumper, TRUE, FALSE,
4160 EL_EMC_SPRING_BUMPER, -1, -1
4163 XbumperB, FALSE, FALSE,
4164 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4167 Xwheel, TRUE, FALSE,
4168 EL_ROBOT_WHEEL, -1, -1
4171 XwheelB, FALSE, FALSE,
4172 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4175 Xswitch, TRUE, FALSE,
4176 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4179 XswitchB, FALSE, FALSE,
4180 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4184 EL_QUICKSAND_EMPTY, -1, -1
4187 Xsand_stone, TRUE, FALSE,
4188 EL_QUICKSAND_FULL, -1, -1
4191 Xsand_stonein_1, FALSE, TRUE,
4192 EL_ROCK, ACTION_FILLING, -1
4195 Xsand_stonein_2, FALSE, TRUE,
4196 EL_ROCK, ACTION_FILLING, -1
4199 Xsand_stonein_3, FALSE, TRUE,
4200 EL_ROCK, ACTION_FILLING, -1
4203 Xsand_stonein_4, FALSE, TRUE,
4204 EL_ROCK, ACTION_FILLING, -1
4207 Xsand_stonesand_1, FALSE, FALSE,
4208 EL_QUICKSAND_FULL, -1, -1
4211 Xsand_stonesand_2, FALSE, FALSE,
4212 EL_QUICKSAND_FULL, -1, -1
4215 Xsand_stonesand_3, FALSE, FALSE,
4216 EL_QUICKSAND_FULL, -1, -1
4219 Xsand_stonesand_4, FALSE, FALSE,
4220 EL_QUICKSAND_FULL, -1, -1
4223 Xsand_stoneout_1, FALSE, FALSE,
4224 EL_ROCK, ACTION_EMPTYING, -1
4227 Xsand_stoneout_2, FALSE, FALSE,
4228 EL_ROCK, ACTION_EMPTYING, -1
4231 Xsand_sandstone_1, FALSE, FALSE,
4232 EL_QUICKSAND_FULL, -1, -1
4235 Xsand_sandstone_2, FALSE, FALSE,
4236 EL_QUICKSAND_FULL, -1, -1
4239 Xsand_sandstone_3, FALSE, FALSE,
4240 EL_QUICKSAND_FULL, -1, -1
4243 Xsand_sandstone_4, FALSE, FALSE,
4244 EL_QUICKSAND_FULL, -1, -1
4247 Xplant, TRUE, FALSE,
4248 EL_EMC_PLANT, -1, -1
4251 Yplant, FALSE, FALSE,
4252 EL_EMC_PLANT, -1, -1
4255 Xlenses, TRUE, FALSE,
4256 EL_EMC_LENSES, -1, -1
4259 Xmagnify, TRUE, FALSE,
4260 EL_EMC_MAGNIFIER, -1, -1
4263 Xdripper, TRUE, FALSE,
4264 EL_EMC_DRIPPER, -1, -1
4267 XdripperB, FALSE, FALSE,
4268 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4271 Xfake_blank, TRUE, FALSE,
4272 EL_INVISIBLE_WALL, -1, -1
4275 Xfake_blankB, FALSE, FALSE,
4276 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4279 Xfake_grass, TRUE, FALSE,
4280 EL_EMC_FAKE_GRASS, -1, -1
4283 Xfake_grassB, FALSE, FALSE,
4284 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4287 Xfake_door_1, TRUE, FALSE,
4288 EL_EM_GATE_1_GRAY, -1, -1
4291 Xfake_door_2, TRUE, FALSE,
4292 EL_EM_GATE_2_GRAY, -1, -1
4295 Xfake_door_3, TRUE, FALSE,
4296 EL_EM_GATE_3_GRAY, -1, -1
4299 Xfake_door_4, TRUE, FALSE,
4300 EL_EM_GATE_4_GRAY, -1, -1
4303 Xfake_door_5, TRUE, FALSE,
4304 EL_EMC_GATE_5_GRAY, -1, -1
4307 Xfake_door_6, TRUE, FALSE,
4308 EL_EMC_GATE_6_GRAY, -1, -1
4311 Xfake_door_7, TRUE, FALSE,
4312 EL_EMC_GATE_7_GRAY, -1, -1
4315 Xfake_door_8, TRUE, FALSE,
4316 EL_EMC_GATE_8_GRAY, -1, -1
4319 Xfake_acid_1, TRUE, FALSE,
4320 EL_EMC_FAKE_ACID, -1, -1
4323 Xfake_acid_2, FALSE, FALSE,
4324 EL_EMC_FAKE_ACID, -1, -1
4327 Xfake_acid_3, FALSE, FALSE,
4328 EL_EMC_FAKE_ACID, -1, -1
4331 Xfake_acid_4, FALSE, FALSE,
4332 EL_EMC_FAKE_ACID, -1, -1
4335 Xfake_acid_5, FALSE, FALSE,
4336 EL_EMC_FAKE_ACID, -1, -1
4339 Xfake_acid_6, FALSE, FALSE,
4340 EL_EMC_FAKE_ACID, -1, -1
4343 Xfake_acid_7, FALSE, FALSE,
4344 EL_EMC_FAKE_ACID, -1, -1
4347 Xfake_acid_8, FALSE, FALSE,
4348 EL_EMC_FAKE_ACID, -1, -1
4351 Xsteel_1, TRUE, FALSE,
4352 EL_STEELWALL, -1, -1
4355 Xsteel_2, TRUE, FALSE,
4356 EL_EMC_STEELWALL_2, -1, -1
4359 Xsteel_3, TRUE, FALSE,
4360 EL_EMC_STEELWALL_3, -1, -1
4363 Xsteel_4, TRUE, FALSE,
4364 EL_EMC_STEELWALL_4, -1, -1
4367 Xwall_1, TRUE, FALSE,
4371 Xwall_2, TRUE, FALSE,
4372 EL_EMC_WALL_14, -1, -1
4375 Xwall_3, TRUE, FALSE,
4376 EL_EMC_WALL_15, -1, -1
4379 Xwall_4, TRUE, FALSE,
4380 EL_EMC_WALL_16, -1, -1
4383 Xround_wall_1, TRUE, FALSE,
4384 EL_WALL_SLIPPERY, -1, -1
4387 Xround_wall_2, TRUE, FALSE,
4388 EL_EMC_WALL_SLIPPERY_2, -1, -1
4391 Xround_wall_3, TRUE, FALSE,
4392 EL_EMC_WALL_SLIPPERY_3, -1, -1
4395 Xround_wall_4, TRUE, FALSE,
4396 EL_EMC_WALL_SLIPPERY_4, -1, -1
4399 Xdecor_1, TRUE, FALSE,
4400 EL_EMC_WALL_8, -1, -1
4403 Xdecor_2, TRUE, FALSE,
4404 EL_EMC_WALL_6, -1, -1
4407 Xdecor_3, TRUE, FALSE,
4408 EL_EMC_WALL_4, -1, -1
4411 Xdecor_4, TRUE, FALSE,
4412 EL_EMC_WALL_7, -1, -1
4415 Xdecor_5, TRUE, FALSE,
4416 EL_EMC_WALL_5, -1, -1
4419 Xdecor_6, TRUE, FALSE,
4420 EL_EMC_WALL_9, -1, -1
4423 Xdecor_7, TRUE, FALSE,
4424 EL_EMC_WALL_10, -1, -1
4427 Xdecor_8, TRUE, FALSE,
4428 EL_EMC_WALL_1, -1, -1
4431 Xdecor_9, TRUE, FALSE,
4432 EL_EMC_WALL_2, -1, -1
4435 Xdecor_10, TRUE, FALSE,
4436 EL_EMC_WALL_3, -1, -1
4439 Xdecor_11, TRUE, FALSE,
4440 EL_EMC_WALL_11, -1, -1
4443 Xdecor_12, TRUE, FALSE,
4444 EL_EMC_WALL_12, -1, -1
4447 Xalpha_0, TRUE, FALSE,
4448 EL_CHAR('0'), -1, -1
4451 Xalpha_1, TRUE, FALSE,
4452 EL_CHAR('1'), -1, -1
4455 Xalpha_2, TRUE, FALSE,
4456 EL_CHAR('2'), -1, -1
4459 Xalpha_3, TRUE, FALSE,
4460 EL_CHAR('3'), -1, -1
4463 Xalpha_4, TRUE, FALSE,
4464 EL_CHAR('4'), -1, -1
4467 Xalpha_5, TRUE, FALSE,
4468 EL_CHAR('5'), -1, -1
4471 Xalpha_6, TRUE, FALSE,
4472 EL_CHAR('6'), -1, -1
4475 Xalpha_7, TRUE, FALSE,
4476 EL_CHAR('7'), -1, -1
4479 Xalpha_8, TRUE, FALSE,
4480 EL_CHAR('8'), -1, -1
4483 Xalpha_9, TRUE, FALSE,
4484 EL_CHAR('9'), -1, -1
4487 Xalpha_excla, TRUE, FALSE,
4488 EL_CHAR('!'), -1, -1
4491 Xalpha_quote, TRUE, FALSE,
4492 EL_CHAR('"'), -1, -1
4495 Xalpha_comma, TRUE, FALSE,
4496 EL_CHAR(','), -1, -1
4499 Xalpha_minus, TRUE, FALSE,
4500 EL_CHAR('-'), -1, -1
4503 Xalpha_perio, TRUE, FALSE,
4504 EL_CHAR('.'), -1, -1
4507 Xalpha_colon, TRUE, FALSE,
4508 EL_CHAR(':'), -1, -1
4511 Xalpha_quest, TRUE, FALSE,
4512 EL_CHAR('?'), -1, -1
4515 Xalpha_a, TRUE, FALSE,
4516 EL_CHAR('A'), -1, -1
4519 Xalpha_b, TRUE, FALSE,
4520 EL_CHAR('B'), -1, -1
4523 Xalpha_c, TRUE, FALSE,
4524 EL_CHAR('C'), -1, -1
4527 Xalpha_d, TRUE, FALSE,
4528 EL_CHAR('D'), -1, -1
4531 Xalpha_e, TRUE, FALSE,
4532 EL_CHAR('E'), -1, -1
4535 Xalpha_f, TRUE, FALSE,
4536 EL_CHAR('F'), -1, -1
4539 Xalpha_g, TRUE, FALSE,
4540 EL_CHAR('G'), -1, -1
4543 Xalpha_h, TRUE, FALSE,
4544 EL_CHAR('H'), -1, -1
4547 Xalpha_i, TRUE, FALSE,
4548 EL_CHAR('I'), -1, -1
4551 Xalpha_j, TRUE, FALSE,
4552 EL_CHAR('J'), -1, -1
4555 Xalpha_k, TRUE, FALSE,
4556 EL_CHAR('K'), -1, -1
4559 Xalpha_l, TRUE, FALSE,
4560 EL_CHAR('L'), -1, -1
4563 Xalpha_m, TRUE, FALSE,
4564 EL_CHAR('M'), -1, -1
4567 Xalpha_n, TRUE, FALSE,
4568 EL_CHAR('N'), -1, -1
4571 Xalpha_o, TRUE, FALSE,
4572 EL_CHAR('O'), -1, -1
4575 Xalpha_p, TRUE, FALSE,
4576 EL_CHAR('P'), -1, -1
4579 Xalpha_q, TRUE, FALSE,
4580 EL_CHAR('Q'), -1, -1
4583 Xalpha_r, TRUE, FALSE,
4584 EL_CHAR('R'), -1, -1
4587 Xalpha_s, TRUE, FALSE,
4588 EL_CHAR('S'), -1, -1
4591 Xalpha_t, TRUE, FALSE,
4592 EL_CHAR('T'), -1, -1
4595 Xalpha_u, TRUE, FALSE,
4596 EL_CHAR('U'), -1, -1
4599 Xalpha_v, TRUE, FALSE,
4600 EL_CHAR('V'), -1, -1
4603 Xalpha_w, TRUE, FALSE,
4604 EL_CHAR('W'), -1, -1
4607 Xalpha_x, TRUE, FALSE,
4608 EL_CHAR('X'), -1, -1
4611 Xalpha_y, TRUE, FALSE,
4612 EL_CHAR('Y'), -1, -1
4615 Xalpha_z, TRUE, FALSE,
4616 EL_CHAR('Z'), -1, -1
4619 Xalpha_arrow_e, TRUE, FALSE,
4620 EL_CHAR('>'), -1, -1
4623 Xalpha_arrow_w, TRUE, FALSE,
4624 EL_CHAR('<'), -1, -1
4627 Xalpha_copyr, TRUE, FALSE,
4628 EL_CHAR('©'), -1, -1
4632 Xboom_bug, FALSE, FALSE,
4633 EL_BUG, ACTION_EXPLODING, -1
4636 Xboom_bomb, FALSE, FALSE,
4637 EL_BOMB, ACTION_EXPLODING, -1
4640 Xboom_android, FALSE, FALSE,
4641 EL_EMC_ANDROID, ACTION_OTHER, -1
4644 Xboom_1, FALSE, FALSE,
4645 EL_DEFAULT, ACTION_EXPLODING, -1
4648 Xboom_2, FALSE, FALSE,
4649 EL_DEFAULT, ACTION_EXPLODING, -1
4652 Znormal, FALSE, FALSE,
4656 Zdynamite, FALSE, FALSE,
4660 Zplayer, FALSE, FALSE,
4664 ZBORDER, FALSE, FALSE,
4674 static struct Mapping_EM_to_RND_player
4683 em_player_mapping_list[] =
4687 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4691 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4695 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4699 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4703 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4707 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4711 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4715 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4719 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4723 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4727 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4731 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4735 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4739 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4743 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4747 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4751 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4755 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4759 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4763 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4767 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4771 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4775 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4779 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4783 EL_PLAYER_1, ACTION_DEFAULT, -1,
4787 EL_PLAYER_2, ACTION_DEFAULT, -1,
4791 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4795 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4799 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4803 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4807 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4811 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4815 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4819 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4823 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4827 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4831 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4835 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4839 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4843 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4847 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4851 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4855 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4859 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4863 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4867 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4871 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4875 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4879 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4883 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
4887 EL_PLAYER_3, ACTION_DEFAULT, -1,
4891 EL_PLAYER_4, ACTION_DEFAULT, -1,
4900 int map_element_RND_to_EM(int element_rnd)
4902 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4903 static boolean mapping_initialized = FALSE;
4905 if (!mapping_initialized)
4909 /* return "Xalpha_quest" for all undefined elements in mapping array */
4910 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4911 mapping_RND_to_EM[i] = Xalpha_quest;
4913 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4914 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
4915 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
4916 em_object_mapping_list[i].element_em;
4918 mapping_initialized = TRUE;
4921 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4922 return mapping_RND_to_EM[element_rnd];
4924 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4929 int map_element_EM_to_RND(int element_em)
4931 static unsigned short mapping_EM_to_RND[TILE_MAX];
4932 static boolean mapping_initialized = FALSE;
4934 if (!mapping_initialized)
4938 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
4939 for (i = 0; i < TILE_MAX; i++)
4940 mapping_EM_to_RND[i] = EL_UNKNOWN;
4942 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
4943 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
4944 em_object_mapping_list[i].element_rnd;
4946 mapping_initialized = TRUE;
4949 if (element_em >= 0 && element_em < TILE_MAX)
4950 return mapping_EM_to_RND[element_em];
4952 Error(ERR_WARN, "invalid EM level element %d", element_em);
4957 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
4959 struct LevelInfo_EM *level_em = level->native_em_level;
4960 struct LEVEL *lev = level_em->lev;
4963 for (i = 0; i < TILE_MAX; i++)
4964 lev->android_array[i] = Xblank;
4966 for (i = 0; i < level->num_android_clone_elements; i++)
4968 int element_rnd = level->android_clone_element[i];
4969 int element_em = map_element_RND_to_EM(element_rnd);
4971 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
4972 if (em_object_mapping_list[j].element_rnd == element_rnd)
4973 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
4977 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
4979 struct LevelInfo_EM *level_em = level->native_em_level;
4980 struct LEVEL *lev = level_em->lev;
4983 level->num_android_clone_elements = 0;
4985 for (i = 0; i < TILE_MAX; i++)
4987 int element_em = lev->android_array[i];
4989 boolean element_found = FALSE;
4991 if (element_em == Xblank)
4994 element_rnd = map_element_EM_to_RND(element_em);
4996 for (j = 0; j < level->num_android_clone_elements; j++)
4997 if (level->android_clone_element[j] == element_rnd)
4998 element_found = TRUE;
5002 level->android_clone_element[level->num_android_clone_elements++] =
5005 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5010 if (level->num_android_clone_elements == 0)
5012 level->num_android_clone_elements = 1;
5013 level->android_clone_element[0] = EL_EMPTY;
5017 int map_direction_RND_to_EM(int direction)
5019 return (direction == MV_UP ? 0 :
5020 direction == MV_RIGHT ? 1 :
5021 direction == MV_DOWN ? 2 :
5022 direction == MV_LEFT ? 3 :
5026 int map_direction_EM_to_RND(int direction)
5028 return (direction == 0 ? MV_UP :
5029 direction == 1 ? MV_RIGHT :
5030 direction == 2 ? MV_DOWN :
5031 direction == 3 ? MV_LEFT :
5035 int get_next_element(int element)
5039 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5040 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5041 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5042 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5043 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5044 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5045 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5047 default: return element;
5052 int el_act_dir2img(int element, int action, int direction)
5054 element = GFX_ELEMENT(element);
5056 if (direction == MV_NONE)
5057 return element_info[element].graphic[action];
5059 direction = MV_DIR_TO_BIT(direction);
5061 return element_info[element].direction_graphic[action][direction];
5064 int el_act_dir2img(int element, int action, int direction)
5066 element = GFX_ELEMENT(element);
5067 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5069 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5070 return element_info[element].direction_graphic[action][direction];
5075 static int el_act_dir2crm(int element, int action, int direction)
5077 element = GFX_ELEMENT(element);
5079 if (direction == MV_NONE)
5080 return element_info[element].crumbled[action];
5082 direction = MV_DIR_TO_BIT(direction);
5084 return element_info[element].direction_crumbled[action][direction];
5087 static int el_act_dir2crm(int element, int action, int direction)
5089 element = GFX_ELEMENT(element);
5090 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5092 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5093 return element_info[element].direction_crumbled[action][direction];
5097 int el_act2img(int element, int action)
5099 element = GFX_ELEMENT(element);
5101 return element_info[element].graphic[action];
5104 int el_act2crm(int element, int action)
5106 element = GFX_ELEMENT(element);
5108 return element_info[element].crumbled[action];
5111 int el_dir2img(int element, int direction)
5113 element = GFX_ELEMENT(element);
5115 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5118 int el2baseimg(int element)
5120 return element_info[element].graphic[ACTION_DEFAULT];
5123 int el2img(int element)
5125 element = GFX_ELEMENT(element);
5127 return element_info[element].graphic[ACTION_DEFAULT];
5130 int el2edimg(int element)
5132 element = GFX_ELEMENT(element);
5134 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5137 int el2preimg(int element)
5139 element = GFX_ELEMENT(element);
5141 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5144 int font2baseimg(int font_nr)
5146 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5150 void setCenteredPlayerNr_EM(int centered_player_nr)
5152 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5155 int getCenteredPlayerNr_EM()
5158 if (game.centered_player_nr_next >= 0 &&
5159 !native_em_level.ply[game.centered_player_nr_next]->alive)
5160 game.centered_player_nr_next = game.centered_player_nr;
5163 if (game.centered_player_nr != game.centered_player_nr_next)
5164 game.centered_player_nr = game.centered_player_nr_next;
5166 return game.centered_player_nr;
5169 void setSetCenteredPlayer_EM(boolean set_centered_player)
5171 game.set_centered_player = set_centered_player;
5174 boolean getSetCenteredPlayer_EM()
5176 return game.set_centered_player;
5180 int getNumActivePlayers_EM()
5182 int num_players = 0;
5188 for (i = 0; i < MAX_PLAYERS; i++)
5189 if (tape.player_participates[i])
5196 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5198 int game_frame_delay_value;
5200 game_frame_delay_value =
5201 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5202 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5205 if (tape.playing && tape.warp_forward && !tape.pausing)
5206 game_frame_delay_value = 0;
5208 return game_frame_delay_value;
5212 unsigned int InitRND(long seed)
5214 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5215 return InitEngineRND_EM(seed);
5217 return InitEngineRND(seed);
5220 void InitGraphicInfo_EM(void)
5222 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5223 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5227 int num_em_gfx_errors = 0;
5229 if (graphic_info_em_object[0][0].bitmap == NULL)
5231 /* EM graphics not yet initialized in em_open_all() */
5236 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5239 /* always start with reliable default values */
5240 for (i = 0; i < TILE_MAX; i++)
5242 object_mapping[i].element_rnd = EL_UNKNOWN;
5243 object_mapping[i].is_backside = FALSE;
5244 object_mapping[i].action = ACTION_DEFAULT;
5245 object_mapping[i].direction = MV_NONE;
5248 /* always start with reliable default values */
5249 for (p = 0; p < MAX_PLAYERS; p++)
5251 for (i = 0; i < SPR_MAX; i++)
5253 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5254 player_mapping[p][i].action = ACTION_DEFAULT;
5255 player_mapping[p][i].direction = MV_NONE;
5259 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5261 int e = em_object_mapping_list[i].element_em;
5263 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5264 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5266 if (em_object_mapping_list[i].action != -1)
5267 object_mapping[e].action = em_object_mapping_list[i].action;
5269 if (em_object_mapping_list[i].direction != -1)
5270 object_mapping[e].direction =
5271 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5274 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5276 int a = em_player_mapping_list[i].action_em;
5277 int p = em_player_mapping_list[i].player_nr;
5279 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5281 if (em_player_mapping_list[i].action != -1)
5282 player_mapping[p][a].action = em_player_mapping_list[i].action;
5284 if (em_player_mapping_list[i].direction != -1)
5285 player_mapping[p][a].direction =
5286 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5289 for (i = 0; i < TILE_MAX; i++)
5291 int element = object_mapping[i].element_rnd;
5292 int action = object_mapping[i].action;
5293 int direction = object_mapping[i].direction;
5294 boolean is_backside = object_mapping[i].is_backside;
5295 boolean action_removing = (action == ACTION_DIGGING ||
5296 action == ACTION_SNAPPING ||
5297 action == ACTION_COLLECTING);
5298 boolean action_exploding = ((action == ACTION_EXPLODING ||
5299 action == ACTION_SMASHED_BY_ROCK ||
5300 action == ACTION_SMASHED_BY_SPRING) &&
5301 element != EL_DIAMOND);
5302 boolean action_active = (action == ACTION_ACTIVE);
5303 boolean action_other = (action == ACTION_OTHER);
5305 for (j = 0; j < 8; j++)
5307 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5308 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5310 i == Xdrip_stretch ? element :
5311 i == Xdrip_stretchB ? element :
5312 i == Ydrip_s1 ? element :
5313 i == Ydrip_s1B ? element :
5314 i == Xball_1B ? element :
5315 i == Xball_2 ? element :
5316 i == Xball_2B ? element :
5317 i == Yball_eat ? element :
5318 i == Ykey_1_eat ? element :
5319 i == Ykey_2_eat ? element :
5320 i == Ykey_3_eat ? element :
5321 i == Ykey_4_eat ? element :
5322 i == Ykey_5_eat ? element :
5323 i == Ykey_6_eat ? element :
5324 i == Ykey_7_eat ? element :
5325 i == Ykey_8_eat ? element :
5326 i == Ylenses_eat ? element :
5327 i == Ymagnify_eat ? element :
5328 i == Ygrass_eat ? element :
5329 i == Ydirt_eat ? element :
5330 i == Yemerald_stone ? EL_EMERALD :
5331 i == Ydiamond_stone ? EL_ROCK :
5332 i == Xsand_stonein_1 ? element :
5333 i == Xsand_stonein_2 ? element :
5334 i == Xsand_stonein_3 ? element :
5335 i == Xsand_stonein_4 ? element :
5336 is_backside ? EL_EMPTY :
5337 action_removing ? EL_EMPTY :
5339 int effective_action = (j < 7 ? action :
5340 i == Xdrip_stretch ? action :
5341 i == Xdrip_stretchB ? action :
5342 i == Ydrip_s1 ? action :
5343 i == Ydrip_s1B ? action :
5344 i == Xball_1B ? action :
5345 i == Xball_2 ? action :
5346 i == Xball_2B ? action :
5347 i == Yball_eat ? action :
5348 i == Ykey_1_eat ? action :
5349 i == Ykey_2_eat ? action :
5350 i == Ykey_3_eat ? action :
5351 i == Ykey_4_eat ? action :
5352 i == Ykey_5_eat ? action :
5353 i == Ykey_6_eat ? action :
5354 i == Ykey_7_eat ? action :
5355 i == Ykey_8_eat ? action :
5356 i == Ylenses_eat ? action :
5357 i == Ymagnify_eat ? action :
5358 i == Ygrass_eat ? action :
5359 i == Ydirt_eat ? action :
5360 i == Xsand_stonein_1 ? action :
5361 i == Xsand_stonein_2 ? action :
5362 i == Xsand_stonein_3 ? action :
5363 i == Xsand_stonein_4 ? action :
5364 i == Xsand_stoneout_1 ? action :
5365 i == Xsand_stoneout_2 ? action :
5366 i == Xboom_android ? ACTION_EXPLODING :
5367 action_exploding ? ACTION_EXPLODING :
5368 action_active ? action :
5369 action_other ? action :
5371 int graphic = (el_act_dir2img(effective_element, effective_action,
5373 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5375 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5376 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5377 boolean has_action_graphics = (graphic != base_graphic);
5378 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5379 struct GraphicInfo *g = &graphic_info[graphic];
5380 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5383 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5384 boolean special_animation = (action != ACTION_DEFAULT &&
5385 g->anim_frames == 3 &&
5386 g->anim_delay == 2 &&
5387 g->anim_mode & ANIM_LINEAR);
5388 int sync_frame = (i == Xdrip_stretch ? 7 :
5389 i == Xdrip_stretchB ? 7 :
5390 i == Ydrip_s2 ? j + 8 :
5391 i == Ydrip_s2B ? j + 8 :
5400 i == Xfake_acid_1 ? 0 :
5401 i == Xfake_acid_2 ? 10 :
5402 i == Xfake_acid_3 ? 20 :
5403 i == Xfake_acid_4 ? 30 :
5404 i == Xfake_acid_5 ? 40 :
5405 i == Xfake_acid_6 ? 50 :
5406 i == Xfake_acid_7 ? 60 :
5407 i == Xfake_acid_8 ? 70 :
5409 i == Xball_2B ? j + 8 :
5410 i == Yball_eat ? j + 1 :
5411 i == Ykey_1_eat ? j + 1 :
5412 i == Ykey_2_eat ? j + 1 :
5413 i == Ykey_3_eat ? j + 1 :
5414 i == Ykey_4_eat ? j + 1 :
5415 i == Ykey_5_eat ? j + 1 :
5416 i == Ykey_6_eat ? j + 1 :
5417 i == Ykey_7_eat ? j + 1 :
5418 i == Ykey_8_eat ? j + 1 :
5419 i == Ylenses_eat ? j + 1 :
5420 i == Ymagnify_eat ? j + 1 :
5421 i == Ygrass_eat ? j + 1 :
5422 i == Ydirt_eat ? j + 1 :
5423 i == Xamoeba_1 ? 0 :
5424 i == Xamoeba_2 ? 1 :
5425 i == Xamoeba_3 ? 2 :
5426 i == Xamoeba_4 ? 3 :
5427 i == Xamoeba_5 ? 0 :
5428 i == Xamoeba_6 ? 1 :
5429 i == Xamoeba_7 ? 2 :
5430 i == Xamoeba_8 ? 3 :
5431 i == Xexit_2 ? j + 8 :
5432 i == Xexit_3 ? j + 16 :
5433 i == Xdynamite_1 ? 0 :
5434 i == Xdynamite_2 ? 8 :
5435 i == Xdynamite_3 ? 16 :
5436 i == Xdynamite_4 ? 24 :
5437 i == Xsand_stonein_1 ? j + 1 :
5438 i == Xsand_stonein_2 ? j + 9 :
5439 i == Xsand_stonein_3 ? j + 17 :
5440 i == Xsand_stonein_4 ? j + 25 :
5441 i == Xsand_stoneout_1 && j == 0 ? 0 :
5442 i == Xsand_stoneout_1 && j == 1 ? 0 :
5443 i == Xsand_stoneout_1 && j == 2 ? 1 :
5444 i == Xsand_stoneout_1 && j == 3 ? 2 :
5445 i == Xsand_stoneout_1 && j == 4 ? 2 :
5446 i == Xsand_stoneout_1 && j == 5 ? 3 :
5447 i == Xsand_stoneout_1 && j == 6 ? 4 :
5448 i == Xsand_stoneout_1 && j == 7 ? 4 :
5449 i == Xsand_stoneout_2 && j == 0 ? 5 :
5450 i == Xsand_stoneout_2 && j == 1 ? 6 :
5451 i == Xsand_stoneout_2 && j == 2 ? 7 :
5452 i == Xsand_stoneout_2 && j == 3 ? 8 :
5453 i == Xsand_stoneout_2 && j == 4 ? 9 :
5454 i == Xsand_stoneout_2 && j == 5 ? 11 :
5455 i == Xsand_stoneout_2 && j == 6 ? 13 :
5456 i == Xsand_stoneout_2 && j == 7 ? 15 :
5457 i == Xboom_bug && j == 1 ? 2 :
5458 i == Xboom_bug && j == 2 ? 2 :
5459 i == Xboom_bug && j == 3 ? 4 :
5460 i == Xboom_bug && j == 4 ? 4 :
5461 i == Xboom_bug && j == 5 ? 2 :
5462 i == Xboom_bug && j == 6 ? 2 :
5463 i == Xboom_bug && j == 7 ? 0 :
5464 i == Xboom_bomb && j == 1 ? 2 :
5465 i == Xboom_bomb && j == 2 ? 2 :
5466 i == Xboom_bomb && j == 3 ? 4 :
5467 i == Xboom_bomb && j == 4 ? 4 :
5468 i == Xboom_bomb && j == 5 ? 2 :
5469 i == Xboom_bomb && j == 6 ? 2 :
5470 i == Xboom_bomb && j == 7 ? 0 :
5471 i == Xboom_android && j == 7 ? 6 :
5472 i == Xboom_1 && j == 1 ? 2 :
5473 i == Xboom_1 && j == 2 ? 2 :
5474 i == Xboom_1 && j == 3 ? 4 :
5475 i == Xboom_1 && j == 4 ? 4 :
5476 i == Xboom_1 && j == 5 ? 6 :
5477 i == Xboom_1 && j == 6 ? 6 :
5478 i == Xboom_1 && j == 7 ? 8 :
5479 i == Xboom_2 && j == 0 ? 8 :
5480 i == Xboom_2 && j == 1 ? 8 :
5481 i == Xboom_2 && j == 2 ? 10 :
5482 i == Xboom_2 && j == 3 ? 10 :
5483 i == Xboom_2 && j == 4 ? 10 :
5484 i == Xboom_2 && j == 5 ? 12 :
5485 i == Xboom_2 && j == 6 ? 12 :
5486 i == Xboom_2 && j == 7 ? 12 :
5487 special_animation && j == 4 ? 3 :
5488 effective_action != action ? 0 :
5492 Bitmap *debug_bitmap = g_em->bitmap;
5493 int debug_src_x = g_em->src_x;
5494 int debug_src_y = g_em->src_y;
5497 int frame = getAnimationFrame(g->anim_frames,
5500 g->anim_start_frame,
5503 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5504 g->double_movement && is_backside);
5506 g_em->bitmap = src_bitmap;
5507 g_em->src_x = src_x;
5508 g_em->src_y = src_y;
5509 g_em->src_offset_x = 0;
5510 g_em->src_offset_y = 0;
5511 g_em->dst_offset_x = 0;
5512 g_em->dst_offset_y = 0;
5513 g_em->width = TILEX;
5514 g_em->height = TILEY;
5516 g_em->crumbled_bitmap = NULL;
5517 g_em->crumbled_src_x = 0;
5518 g_em->crumbled_src_y = 0;
5519 g_em->crumbled_border_size = 0;
5521 g_em->has_crumbled_graphics = FALSE;
5522 g_em->preserve_background = FALSE;
5525 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5526 printf("::: empty crumbled: %d [%s], %d, %d\n",
5527 effective_element, element_info[effective_element].token_name,
5528 effective_action, direction);
5531 /* if element can be crumbled, but certain action graphics are just empty
5532 space (like snapping sand with the original R'n'D graphics), do not
5533 treat these empty space graphics as crumbled graphics in EMC engine */
5534 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5536 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5538 g_em->has_crumbled_graphics = TRUE;
5539 g_em->crumbled_bitmap = src_bitmap;
5540 g_em->crumbled_src_x = src_x;
5541 g_em->crumbled_src_y = src_y;
5542 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5546 if (element == EL_ROCK &&
5547 effective_action == ACTION_FILLING)
5548 printf("::: has_action_graphics == %d\n", has_action_graphics);
5551 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5552 effective_action == ACTION_MOVING ||
5553 effective_action == ACTION_PUSHING ||
5554 effective_action == ACTION_EATING)) ||
5555 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5556 effective_action == ACTION_EMPTYING)))
5559 (effective_action == ACTION_FALLING ||
5560 effective_action == ACTION_FILLING ||
5561 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5562 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5563 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5564 int num_steps = (i == Ydrip_s1 ? 16 :
5565 i == Ydrip_s1B ? 16 :
5566 i == Ydrip_s2 ? 16 :
5567 i == Ydrip_s2B ? 16 :
5568 i == Xsand_stonein_1 ? 32 :
5569 i == Xsand_stonein_2 ? 32 :
5570 i == Xsand_stonein_3 ? 32 :
5571 i == Xsand_stonein_4 ? 32 :
5572 i == Xsand_stoneout_1 ? 16 :
5573 i == Xsand_stoneout_2 ? 16 : 8);
5574 int cx = ABS(dx) * (TILEX / num_steps);
5575 int cy = ABS(dy) * (TILEY / num_steps);
5576 int step_frame = (i == Ydrip_s2 ? j + 8 :
5577 i == Ydrip_s2B ? j + 8 :
5578 i == Xsand_stonein_2 ? j + 8 :
5579 i == Xsand_stonein_3 ? j + 16 :
5580 i == Xsand_stonein_4 ? j + 24 :
5581 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5582 int step = (is_backside ? step_frame : num_steps - step_frame);
5584 if (is_backside) /* tile where movement starts */
5586 if (dx < 0 || dy < 0)
5588 g_em->src_offset_x = cx * step;
5589 g_em->src_offset_y = cy * step;
5593 g_em->dst_offset_x = cx * step;
5594 g_em->dst_offset_y = cy * step;
5597 else /* tile where movement ends */
5599 if (dx < 0 || dy < 0)
5601 g_em->dst_offset_x = cx * step;
5602 g_em->dst_offset_y = cy * step;
5606 g_em->src_offset_x = cx * step;
5607 g_em->src_offset_y = cy * step;
5611 g_em->width = TILEX - cx * step;
5612 g_em->height = TILEY - cy * step;
5616 /* create unique graphic identifier to decide if tile must be redrawn */
5617 /* bit 31 - 16 (16 bit): EM style graphic
5618 bit 15 - 12 ( 4 bit): EM style frame
5619 bit 11 - 6 ( 6 bit): graphic width
5620 bit 5 - 0 ( 6 bit): graphic height */
5621 g_em->unique_identifier =
5622 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5624 /* create unique graphic identifier to decide if tile must be redrawn */
5625 /* bit 31 - 16 (16 bit): EM style element
5626 bit 15 - 12 ( 4 bit): EM style frame
5627 bit 11 - 6 ( 6 bit): graphic width
5628 bit 5 - 0 ( 6 bit): graphic height */
5629 g_em->unique_identifier =
5630 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5634 if (effective_element == EL_ROCK)
5635 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5636 effective_action, j, graphic, frame, g_em->unique_identifier);
5642 /* skip check for EMC elements not contained in original EMC artwork */
5643 if (element == EL_EMC_FAKE_ACID)
5647 if (g_em->bitmap != debug_bitmap ||
5648 g_em->src_x != debug_src_x ||
5649 g_em->src_y != debug_src_y ||
5650 g_em->src_offset_x != 0 ||
5651 g_em->src_offset_y != 0 ||
5652 g_em->dst_offset_x != 0 ||
5653 g_em->dst_offset_y != 0 ||
5654 g_em->width != TILEX ||
5655 g_em->height != TILEY)
5657 static int last_i = -1;
5665 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5666 i, element, element_info[element].token_name,
5667 element_action_info[effective_action].suffix, direction);
5669 if (element != effective_element)
5670 printf(" [%d ('%s')]",
5672 element_info[effective_element].token_name);
5676 if (g_em->bitmap != debug_bitmap)
5677 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5678 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5680 if (g_em->src_x != debug_src_x ||
5681 g_em->src_y != debug_src_y)
5682 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5683 j, (is_backside ? 'B' : 'F'),
5684 g_em->src_x, g_em->src_y,
5685 g_em->src_x / 32, g_em->src_y / 32,
5686 debug_src_x, debug_src_y,
5687 debug_src_x / 32, debug_src_y / 32);
5689 if (g_em->src_offset_x != 0 ||
5690 g_em->src_offset_y != 0 ||
5691 g_em->dst_offset_x != 0 ||
5692 g_em->dst_offset_y != 0)
5693 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5695 g_em->src_offset_x, g_em->src_offset_y,
5696 g_em->dst_offset_x, g_em->dst_offset_y);
5698 if (g_em->width != TILEX ||
5699 g_em->height != TILEY)
5700 printf(" %d (%d): size %d,%d should be %d,%d\n",
5702 g_em->width, g_em->height, TILEX, TILEY);
5704 num_em_gfx_errors++;
5711 for (i = 0; i < TILE_MAX; i++)
5713 for (j = 0; j < 8; j++)
5715 int element = object_mapping[i].element_rnd;
5716 int action = object_mapping[i].action;
5717 int direction = object_mapping[i].direction;
5718 boolean is_backside = object_mapping[i].is_backside;
5720 int graphic_action = el_act_dir2img(element, action, direction);
5721 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5723 int graphic_action = element_info[element].graphic[action];
5724 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5727 if ((action == ACTION_SMASHED_BY_ROCK ||
5728 action == ACTION_SMASHED_BY_SPRING ||
5729 action == ACTION_EATING) &&
5730 graphic_action == graphic_default)
5732 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5733 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5734 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5735 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5738 /* no separate animation for "smashed by rock" -- use rock instead */
5739 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5740 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5742 g_em->bitmap = g_xx->bitmap;
5743 g_em->src_x = g_xx->src_x;
5744 g_em->src_y = g_xx->src_y;
5745 g_em->src_offset_x = g_xx->src_offset_x;
5746 g_em->src_offset_y = g_xx->src_offset_y;
5747 g_em->dst_offset_x = g_xx->dst_offset_x;
5748 g_em->dst_offset_y = g_xx->dst_offset_y;
5749 g_em->width = g_xx->width;
5750 g_em->height = g_xx->height;
5752 g_em->unique_identifier = g_xx->unique_identifier;
5756 g_em->preserve_background = TRUE;
5761 for (p = 0; p < MAX_PLAYERS; p++)
5763 for (i = 0; i < SPR_MAX; i++)
5765 int element = player_mapping[p][i].element_rnd;
5766 int action = player_mapping[p][i].action;
5767 int direction = player_mapping[p][i].direction;
5769 for (j = 0; j < 8; j++)
5771 int effective_element = element;
5772 int effective_action = action;
5773 int graphic = (direction == MV_NONE ?
5774 el_act2img(effective_element, effective_action) :
5775 el_act_dir2img(effective_element, effective_action,
5777 struct GraphicInfo *g = &graphic_info[graphic];
5778 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5784 Bitmap *debug_bitmap = g_em->bitmap;
5785 int debug_src_x = g_em->src_x;
5786 int debug_src_y = g_em->src_y;
5789 int frame = getAnimationFrame(g->anim_frames,
5792 g->anim_start_frame,
5795 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5797 g_em->bitmap = src_bitmap;
5798 g_em->src_x = src_x;
5799 g_em->src_y = src_y;
5800 g_em->src_offset_x = 0;
5801 g_em->src_offset_y = 0;
5802 g_em->dst_offset_x = 0;
5803 g_em->dst_offset_y = 0;
5804 g_em->width = TILEX;
5805 g_em->height = TILEY;
5810 /* skip check for EMC elements not contained in original EMC artwork */
5811 if (element == EL_PLAYER_3 ||
5812 element == EL_PLAYER_4)
5816 if (g_em->bitmap != debug_bitmap ||
5817 g_em->src_x != debug_src_x ||
5818 g_em->src_y != debug_src_y)
5820 static int last_i = -1;
5828 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5829 p, i, element, element_info[element].token_name,
5830 element_action_info[effective_action].suffix, direction);
5832 if (element != effective_element)
5833 printf(" [%d ('%s')]",
5835 element_info[effective_element].token_name);
5839 if (g_em->bitmap != debug_bitmap)
5840 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5841 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5843 if (g_em->src_x != debug_src_x ||
5844 g_em->src_y != debug_src_y)
5845 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5847 g_em->src_x, g_em->src_y,
5848 g_em->src_x / 32, g_em->src_y / 32,
5849 debug_src_x, debug_src_y,
5850 debug_src_x / 32, debug_src_y / 32);
5852 num_em_gfx_errors++;
5862 printf("::: [%d errors found]\n", num_em_gfx_errors);