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);
245 redraw_mask = REDRAW_NONE;
248 if (redraw_mask & REDRAW_FIELD)
250 if (game_status != GAME_MODE_PLAYING ||
251 redraw_mask & REDRAW_FROM_BACKBUFFER)
253 BlitBitmap(backbuffer, window,
254 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
258 int fx = FX, fy = FY;
260 if (setup.soft_scrolling)
262 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
263 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
266 if (setup.soft_scrolling ||
267 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
268 ABS(ScreenMovPos) == ScrollStepSize ||
269 redraw_tiles > REDRAWTILES_THRESHOLD)
271 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
275 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
277 (setup.soft_scrolling ?
278 "setup.soft_scrolling" :
279 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
280 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
281 ABS(ScreenGfxPos) == ScrollStepSize ?
282 "ABS(ScreenGfxPos) == ScrollStepSize" :
283 "redraw_tiles > REDRAWTILES_THRESHOLD"));
289 redraw_mask &= ~REDRAW_MAIN;
292 if (redraw_mask & REDRAW_DOORS)
294 if (redraw_mask & REDRAW_DOOR_1)
295 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
297 if (redraw_mask & REDRAW_DOOR_2)
298 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
300 if (redraw_mask & REDRAW_DOOR_3)
301 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
303 redraw_mask &= ~REDRAW_DOORS;
306 if (redraw_mask & REDRAW_MICROLEVEL)
308 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
309 SX, SY + 10 * TILEY);
311 redraw_mask &= ~REDRAW_MICROLEVEL;
314 if (redraw_mask & REDRAW_TILES)
316 for (x = 0; x < SCR_FIELDX; x++)
317 for (y = 0 ; y < SCR_FIELDY; y++)
318 if (redraw[redraw_x1 + x][redraw_y1 + y])
319 BlitBitmap(buffer, window,
320 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
321 SX + x * TILEX, SY + y * TILEY);
324 if (redraw_mask & REDRAW_FPS) /* display frames per second */
329 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
330 if (!global.fps_slowdown)
333 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
334 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
339 for (x = 0; x < MAX_BUF_XSIZE; x++)
340 for (y = 0; y < MAX_BUF_YSIZE; y++)
343 redraw_mask = REDRAW_NONE;
349 long fading_delay = 300;
351 if (setup.fading && (redraw_mask & REDRAW_FIELD))
358 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
361 for (i = 0; i < 2 * FULL_SYSIZE; i++)
363 for (y = 0; y < FULL_SYSIZE; y++)
365 BlitBitmap(backbuffer, window,
366 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
374 for (i = 1; i < FULL_SYSIZE; i+=2)
375 BlitBitmap(backbuffer, window,
376 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
382 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
383 BlitBitmapMasked(backbuffer, window,
384 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
389 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
390 BlitBitmapMasked(backbuffer, window,
391 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
396 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
397 BlitBitmapMasked(backbuffer, window,
398 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
403 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
404 BlitBitmapMasked(backbuffer, window,
405 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
410 redraw_mask &= ~REDRAW_MAIN;
417 void FadeIn(int fade_delay)
426 FadeScreen(NULL, FADE_MODE_FADE_IN, fade_delay, 0);
428 redraw_mask = REDRAW_NONE;
431 void FadeOut(int fade_delay, int post_delay)
435 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
441 FadeScreen(NULL, FADE_MODE_FADE_OUT, fade_delay, post_delay);
443 redraw_mask = REDRAW_NONE;
446 void FadeCross(int fade_delay)
450 BlitBitmap(bitmap_db_title, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
456 FadeScreen(bitmap_db_title, FADE_MODE_CROSSFADE, fade_delay, 0);
458 redraw_mask = REDRAW_NONE;
461 void SetMainBackgroundImageIfDefined(int graphic)
463 if (graphic_info[graphic].bitmap)
464 SetMainBackgroundImage(graphic);
467 void SetMainBackgroundImage(int graphic)
469 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
470 graphic_info[graphic].bitmap ?
471 graphic_info[graphic].bitmap :
472 graphic_info[IMG_BACKGROUND].bitmap);
475 void SetDoorBackgroundImage(int graphic)
477 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
478 graphic_info[graphic].bitmap ?
479 graphic_info[graphic].bitmap :
480 graphic_info[IMG_BACKGROUND].bitmap);
483 void DrawBackground(int dst_x, int dst_y, int width, int height)
485 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
487 redraw_mask |= REDRAW_FIELD;
492 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
494 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
496 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
497 SetDrawtoField(DRAW_BUFFERED);
500 SetDrawtoField(DRAW_BACKBUFFER);
502 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
504 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
505 SetDrawtoField(DRAW_DIRECT);
509 void MarkTileDirty(int x, int y)
511 int xx = redraw_x1 + x;
512 int yy = redraw_y1 + y;
517 redraw[xx][yy] = TRUE;
518 redraw_mask |= REDRAW_TILES;
521 void SetBorderElement()
525 BorderElement = EL_EMPTY;
527 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
529 for (x = 0; x < lev_fieldx; x++)
531 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
532 BorderElement = EL_STEELWALL;
534 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
540 void SetRandomAnimationValue(int x, int y)
542 gfx.anim_random_frame = GfxRandom[x][y];
545 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
547 /* animation synchronized with global frame counter, not move position */
548 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
549 sync_frame = FrameCounter;
552 if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
558 printf("::: FOO!\n");
562 return getAnimationFrame(graphic_info[graphic].anim_frames,
563 graphic_info[graphic].anim_delay,
564 graphic_info[graphic].anim_mode,
565 graphic_info[graphic].anim_start_frame,
569 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
570 int *x, int *y, boolean get_backside)
572 struct GraphicInfo *g = &graphic_info[graphic];
573 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
574 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
578 if (g->offset_y == 0) /* frames are ordered horizontally */
580 int max_width = g->anim_frames_per_line * g->width;
581 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
583 *x = pos % max_width;
584 *y = src_y % g->height + pos / max_width * g->height;
586 else if (g->offset_x == 0) /* frames are ordered vertically */
588 int max_height = g->anim_frames_per_line * g->height;
589 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
591 *x = src_x % g->width + pos / max_height * g->width;
592 *y = pos % max_height;
594 else /* frames are ordered diagonally */
596 *x = src_x + frame * g->offset_x;
597 *y = src_y + frame * g->offset_y;
601 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
603 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
606 void DrawGraphic(int x, int y, int graphic, int frame)
609 if (!IN_SCR_FIELD(x, y))
611 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
612 printf("DrawGraphic(): This should never happen!\n");
617 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
621 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
627 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
628 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
631 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
634 if (!IN_SCR_FIELD(x, y))
636 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
637 printf("DrawGraphicThruMask(): This should never happen!\n");
642 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
647 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
653 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
655 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
656 dst_x - src_x, dst_y - src_y);
657 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
660 void DrawMiniGraphic(int x, int y, int graphic)
662 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
663 MarkTileDirty(x / 2, y / 2);
666 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
668 struct GraphicInfo *g = &graphic_info[graphic];
670 int mini_starty = g->bitmap->height * 2 / 3;
673 *x = mini_startx + g->src_x / 2;
674 *y = mini_starty + g->src_y / 2;
677 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
682 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
683 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
686 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
687 int graphic, int frame,
688 int cut_mode, int mask_mode)
693 int width = TILEX, height = TILEY;
696 if (dx || dy) /* shifted graphic */
698 if (x < BX1) /* object enters playfield from the left */
705 else if (x > BX2) /* object enters playfield from the right */
711 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
717 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
719 else if (dx) /* general horizontal movement */
720 MarkTileDirty(x + SIGN(dx), y);
722 if (y < BY1) /* object enters playfield from the top */
724 if (cut_mode==CUT_BELOW) /* object completely above top border */
732 else if (y > BY2) /* object enters playfield from the bottom */
738 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
744 else if (dy > 0 && cut_mode == CUT_ABOVE)
746 if (y == BY2) /* object completely above bottom border */
752 MarkTileDirty(x, y + 1);
753 } /* object leaves playfield to the bottom */
754 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
756 else if (dy) /* general vertical movement */
757 MarkTileDirty(x, y + SIGN(dy));
761 if (!IN_SCR_FIELD(x, y))
763 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
764 printf("DrawGraphicShifted(): This should never happen!\n");
769 if (width > 0 && height > 0)
771 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
776 dst_x = FX + x * TILEX + dx;
777 dst_y = FY + y * TILEY + dy;
779 if (mask_mode == USE_MASKING)
781 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
782 dst_x - src_x, dst_y - src_y);
783 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
787 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
794 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
795 int graphic, int frame,
796 int cut_mode, int mask_mode)
801 int width = TILEX, height = TILEY;
804 int x2 = x + SIGN(dx);
805 int y2 = y + SIGN(dy);
806 int anim_frames = graphic_info[graphic].anim_frames;
807 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
808 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
809 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
811 /* re-calculate animation frame for two-tile movement animation */
812 frame = getGraphicAnimationFrame(graphic, sync_frame);
814 /* check if movement start graphic inside screen area and should be drawn */
815 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
817 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
819 dst_x = FX + x1 * TILEX;
820 dst_y = FY + y1 * TILEY;
822 if (mask_mode == USE_MASKING)
824 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
825 dst_x - src_x, dst_y - src_y);
826 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
830 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
833 MarkTileDirty(x1, y1);
836 /* check if movement end graphic inside screen area and should be drawn */
837 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
839 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
841 dst_x = FX + x2 * TILEX;
842 dst_y = FY + y2 * TILEY;
844 if (mask_mode == USE_MASKING)
846 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
847 dst_x - src_x, dst_y - src_y);
848 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
852 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
855 MarkTileDirty(x2, y2);
859 static void DrawGraphicShifted(int x, int y, int dx, int dy,
860 int graphic, int frame,
861 int cut_mode, int mask_mode)
865 DrawGraphic(x, y, graphic, frame);
870 if (graphic_info[graphic].double_movement) /* EM style movement images */
871 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
873 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
876 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
877 int frame, int cut_mode)
879 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
882 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
883 int cut_mode, int mask_mode)
885 int lx = LEVELX(x), ly = LEVELY(y);
889 if (IN_LEV_FIELD(lx, ly))
891 SetRandomAnimationValue(lx, ly);
893 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
894 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
896 /* do not use double (EM style) movement graphic when not moving */
897 if (graphic_info[graphic].double_movement && !dx && !dy)
899 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
900 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
903 else /* border element */
905 graphic = el2img(element);
906 frame = getGraphicAnimationFrame(graphic, -1);
909 if (element == EL_EXPANDABLE_WALL)
911 boolean left_stopped = FALSE, right_stopped = FALSE;
913 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
915 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
916 right_stopped = TRUE;
918 if (left_stopped && right_stopped)
920 else if (left_stopped)
922 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
923 frame = graphic_info[graphic].anim_frames - 1;
925 else if (right_stopped)
927 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
928 frame = graphic_info[graphic].anim_frames - 1;
933 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
934 else if (mask_mode == USE_MASKING)
935 DrawGraphicThruMask(x, y, graphic, frame);
937 DrawGraphic(x, y, graphic, frame);
940 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
941 int cut_mode, int mask_mode)
943 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
944 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
945 cut_mode, mask_mode);
948 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
951 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
954 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
957 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
960 void DrawLevelElementThruMask(int x, int y, int element)
962 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
965 void DrawLevelFieldThruMask(int x, int y)
967 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
970 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
974 int sx = SCREENX(x), sy = SCREENY(y);
976 int width, height, cx, cy, i;
977 int crumbled_border_size = graphic_info[graphic].border_size;
978 static int xy[4][2] =
986 if (!IN_LEV_FIELD(x, y))
989 element = TILE_GFX_ELEMENT(x, y);
991 /* crumble field itself */
992 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
994 if (!IN_SCR_FIELD(sx, sy))
997 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
999 for (i = 0; i < 4; i++)
1001 int xx = x + xy[i][0];
1002 int yy = y + xy[i][1];
1004 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1007 /* check if neighbour field is of same type */
1008 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1011 if (i == 1 || i == 2)
1013 width = crumbled_border_size;
1015 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1021 height = crumbled_border_size;
1023 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1026 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1027 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1030 MarkTileDirty(sx, sy);
1032 else /* crumble neighbour fields */
1034 for (i = 0; i < 4; i++)
1036 int xx = x + xy[i][0];
1037 int yy = y + xy[i][1];
1038 int sxx = sx + xy[i][0];
1039 int syy = sy + xy[i][1];
1042 if (!IN_LEV_FIELD(xx, yy) ||
1043 !IN_SCR_FIELD(sxx, syy) ||
1048 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1052 element = TILE_GFX_ELEMENT(xx, yy);
1054 if (!GFX_CRUMBLED(element))
1057 if (!IN_LEV_FIELD(xx, yy) ||
1058 !IN_SCR_FIELD(sxx, syy) ||
1059 !GFX_CRUMBLED(Feld[xx][yy]) ||
1065 graphic = el_act2crm(element, ACTION_DEFAULT);
1067 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1069 crumbled_border_size = graphic_info[graphic].border_size;
1071 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1073 if (i == 1 || i == 2)
1075 width = crumbled_border_size;
1077 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1083 height = crumbled_border_size;
1085 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1088 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1089 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1091 MarkTileDirty(sxx, syy);
1096 void DrawLevelFieldCrumbledSand(int x, int y)
1100 if (!IN_LEV_FIELD(x, y))
1104 /* !!! CHECK THIS !!! */
1107 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1108 GFX_CRUMBLED(GfxElement[x][y]))
1111 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1112 GfxElement[x][y] != EL_UNDEFINED &&
1113 GFX_CRUMBLED(GfxElement[x][y]))
1115 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1122 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1124 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1127 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1130 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1133 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1134 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1135 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1136 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1137 int sx = SCREENX(x), sy = SCREENY(y);
1139 DrawGraphic(sx, sy, graphic1, frame1);
1140 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1143 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1145 int sx = SCREENX(x), sy = SCREENY(y);
1146 static int xy[4][2] =
1155 for (i = 0; i < 4; i++)
1157 int xx = x + xy[i][0];
1158 int yy = y + xy[i][1];
1159 int sxx = sx + xy[i][0];
1160 int syy = sy + xy[i][1];
1162 if (!IN_LEV_FIELD(xx, yy) ||
1163 !IN_SCR_FIELD(sxx, syy) ||
1164 !GFX_CRUMBLED(Feld[xx][yy]) ||
1168 DrawLevelField(xx, yy);
1172 static int getBorderElement(int x, int y)
1176 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1177 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1178 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1179 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1180 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1181 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1182 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1184 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1185 int steel_position = (x == -1 && y == -1 ? 0 :
1186 x == lev_fieldx && y == -1 ? 1 :
1187 x == -1 && y == lev_fieldy ? 2 :
1188 x == lev_fieldx && y == lev_fieldy ? 3 :
1189 x == -1 || x == lev_fieldx ? 4 :
1190 y == -1 || y == lev_fieldy ? 5 : 6);
1192 return border[steel_position][steel_type];
1195 void DrawScreenElement(int x, int y, int element)
1197 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1198 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1201 void DrawLevelElement(int x, int y, int element)
1203 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1204 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1207 void DrawScreenField(int x, int y)
1209 int lx = LEVELX(x), ly = LEVELY(y);
1210 int element, content;
1212 if (!IN_LEV_FIELD(lx, ly))
1214 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1217 element = getBorderElement(lx, ly);
1219 DrawScreenElement(x, y, element);
1223 element = Feld[lx][ly];
1224 content = Store[lx][ly];
1226 if (IS_MOVING(lx, ly))
1228 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1229 boolean cut_mode = NO_CUTTING;
1231 if (element == EL_QUICKSAND_EMPTYING ||
1232 element == EL_MAGIC_WALL_EMPTYING ||
1233 element == EL_BD_MAGIC_WALL_EMPTYING ||
1234 element == EL_AMOEBA_DROPPING)
1235 cut_mode = CUT_ABOVE;
1236 else if (element == EL_QUICKSAND_FILLING ||
1237 element == EL_MAGIC_WALL_FILLING ||
1238 element == EL_BD_MAGIC_WALL_FILLING)
1239 cut_mode = CUT_BELOW;
1241 if (cut_mode == CUT_ABOVE)
1242 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1244 DrawScreenElement(x, y, EL_EMPTY);
1247 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1248 else if (cut_mode == NO_CUTTING)
1249 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1251 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1253 if (content == EL_ACID)
1255 int dir = MovDir[lx][ly];
1256 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1257 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1259 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1262 else if (IS_BLOCKED(lx, ly))
1267 boolean cut_mode = NO_CUTTING;
1268 int element_old, content_old;
1270 Blocked2Moving(lx, ly, &oldx, &oldy);
1273 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1274 MovDir[oldx][oldy] == MV_RIGHT);
1276 element_old = Feld[oldx][oldy];
1277 content_old = Store[oldx][oldy];
1279 if (element_old == EL_QUICKSAND_EMPTYING ||
1280 element_old == EL_MAGIC_WALL_EMPTYING ||
1281 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1282 element_old == EL_AMOEBA_DROPPING)
1283 cut_mode = CUT_ABOVE;
1285 DrawScreenElement(x, y, EL_EMPTY);
1288 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1290 else if (cut_mode == NO_CUTTING)
1291 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1294 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1297 else if (IS_DRAWABLE(element))
1298 DrawScreenElement(x, y, element);
1300 DrawScreenElement(x, y, EL_EMPTY);
1303 void DrawLevelField(int x, int y)
1305 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1306 DrawScreenField(SCREENX(x), SCREENY(y));
1307 else if (IS_MOVING(x, y))
1311 Moving2Blocked(x, y, &newx, &newy);
1312 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1313 DrawScreenField(SCREENX(newx), SCREENY(newy));
1315 else if (IS_BLOCKED(x, y))
1319 Blocked2Moving(x, y, &oldx, &oldy);
1320 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1321 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1325 void DrawMiniElement(int x, int y, int element)
1329 graphic = el2edimg(element);
1330 DrawMiniGraphic(x, y, graphic);
1333 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1335 int x = sx + scroll_x, y = sy + scroll_y;
1337 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1338 DrawMiniElement(sx, sy, EL_EMPTY);
1339 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1340 DrawMiniElement(sx, sy, Feld[x][y]);
1342 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1345 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1346 int x, int y, int xsize, int ysize, int font_nr)
1348 int font_width = getFontWidth(font_nr);
1349 int font_height = getFontHeight(font_nr);
1350 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1353 int dst_x = SX + startx + x * font_width;
1354 int dst_y = SY + starty + y * font_height;
1355 int width = graphic_info[graphic].width;
1356 int height = graphic_info[graphic].height;
1357 int inner_width = MAX(width - 2 * font_width, font_width);
1358 int inner_height = MAX(height - 2 * font_height, font_height);
1359 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1360 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1361 boolean draw_masked = graphic_info[graphic].draw_masked;
1363 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1365 if (src_bitmap == NULL || width < font_width || height < font_height)
1367 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1371 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1372 inner_sx + (x - 1) * font_width % inner_width);
1373 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1374 inner_sy + (y - 1) * font_height % inner_height);
1378 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1379 dst_x - src_x, dst_y - src_y);
1380 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1384 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1388 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1390 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1391 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1392 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1393 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1394 boolean no_delay = (tape.warp_forward);
1395 unsigned long anim_delay = 0;
1396 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1397 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1398 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1399 int font_width = getFontWidth(font_nr);
1400 int font_height = getFontHeight(font_nr);
1401 int max_xsize = level.envelope[envelope_nr].xsize;
1402 int max_ysize = level.envelope[envelope_nr].ysize;
1403 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1404 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1405 int xend = max_xsize;
1406 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1407 int xstep = (xstart < xend ? 1 : 0);
1408 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1411 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1413 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1414 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1415 int sx = (SXSIZE - xsize * font_width) / 2;
1416 int sy = (SYSIZE - ysize * font_height) / 2;
1419 SetDrawtoField(DRAW_BUFFERED);
1421 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1423 SetDrawtoField(DRAW_BACKBUFFER);
1425 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1426 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1428 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1429 level.envelope[envelope_nr].text, font_nr, max_xsize,
1430 xsize - 2, ysize - 2, mask_mode);
1432 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1435 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1439 void ShowEnvelope(int envelope_nr)
1441 int element = EL_ENVELOPE_1 + envelope_nr;
1442 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1443 int sound_opening = element_info[element].sound[ACTION_OPENING];
1444 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1445 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1446 boolean no_delay = (tape.warp_forward);
1447 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1448 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1449 int anim_mode = graphic_info[graphic].anim_mode;
1450 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1451 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1453 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1455 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1457 if (anim_mode == ANIM_DEFAULT)
1458 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1460 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1463 Delay(wait_delay_value);
1465 WaitForEventToContinue();
1467 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1469 if (anim_mode != ANIM_NONE)
1470 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1472 if (anim_mode == ANIM_DEFAULT)
1473 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1475 game.envelope_active = FALSE;
1477 SetDrawtoField(DRAW_BUFFERED);
1479 redraw_mask |= REDRAW_FIELD;
1483 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1488 int width_mult, width_div;
1489 int height_mult, height_div;
1497 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1498 5 - log_2(tilesize));
1499 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1500 int width_mult = offset_calc[offset_calc_pos].width_mult;
1501 int width_div = offset_calc[offset_calc_pos].width_div;
1502 int height_mult = offset_calc[offset_calc_pos].height_mult;
1503 int height_div = offset_calc[offset_calc_pos].height_div;
1504 int mini_startx = src_bitmap->width * width_mult / width_div;
1505 int mini_starty = src_bitmap->height * height_mult / height_div;
1506 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1507 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1509 *bitmap = src_bitmap;
1514 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1518 int graphic = el2preimg(element);
1520 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1521 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1528 SetDrawBackgroundMask(REDRAW_NONE);
1531 for (x = BX1; x <= BX2; x++)
1532 for (y = BY1; y <= BY2; y++)
1533 DrawScreenField(x, y);
1535 redraw_mask |= REDRAW_FIELD;
1538 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1542 for (x = 0; x < size_x; x++)
1543 for (y = 0; y < size_y; y++)
1544 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1546 redraw_mask |= REDRAW_FIELD;
1549 static void DrawPreviewLevelExt(int from_x, int from_y)
1551 boolean show_level_border = (BorderElement != EL_EMPTY);
1552 int dst_x = preview.x;
1553 int dst_y = preview.y;
1554 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1555 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1556 int tile_size = preview.tile_size;
1557 int preview_width = preview.xsize * tile_size;
1558 int preview_height = preview.ysize * tile_size;
1559 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1560 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1563 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1565 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1566 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1568 for (x = 0; x < real_preview_xsize; x++)
1570 for (y = 0; y < real_preview_ysize; y++)
1572 int lx = from_x + x + (show_level_border ? -1 : 0);
1573 int ly = from_y + y + (show_level_border ? -1 : 0);
1574 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1575 getBorderElement(lx, ly));
1577 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1578 element, tile_size);
1582 redraw_mask |= REDRAW_MICROLEVEL;
1585 #define MICROLABEL_EMPTY 0
1586 #define MICROLABEL_LEVEL_NAME 1
1587 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1588 #define MICROLABEL_LEVEL_AUTHOR 3
1589 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1590 #define MICROLABEL_IMPORTED_FROM 5
1591 #define MICROLABEL_IMPORTED_BY_HEAD 6
1592 #define MICROLABEL_IMPORTED_BY 7
1594 static void DrawPreviewLevelLabelExt(int mode)
1596 char label_text[MAX_OUTPUT_LINESIZE + 1];
1597 int max_len_label_text;
1598 int font_nr = FONT_TEXT_2;
1601 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1602 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1603 mode == MICROLABEL_IMPORTED_BY_HEAD)
1604 font_nr = FONT_TEXT_3;
1606 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1608 for (i = 0; i < max_len_label_text; i++)
1609 label_text[i] = ' ';
1610 label_text[max_len_label_text] = '\0';
1612 if (strlen(label_text) > 0)
1614 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1615 int lypos = MICROLABEL2_YPOS;
1617 DrawText(lxpos, lypos, label_text, font_nr);
1621 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1622 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1623 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1624 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1625 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1626 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1627 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1628 max_len_label_text);
1629 label_text[max_len_label_text] = '\0';
1631 if (strlen(label_text) > 0)
1633 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1634 int lypos = MICROLABEL2_YPOS;
1636 DrawText(lxpos, lypos, label_text, font_nr);
1639 redraw_mask |= REDRAW_MICROLEVEL;
1642 void DrawPreviewLevel(boolean restart)
1644 static unsigned long scroll_delay = 0;
1645 static unsigned long label_delay = 0;
1646 static int from_x, from_y, scroll_direction;
1647 static int label_state, label_counter;
1648 unsigned long scroll_delay_value = preview.step_delay;
1649 boolean show_level_border = (BorderElement != EL_EMPTY);
1650 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1651 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1652 int last_game_status = game_status; /* save current game status */
1654 /* force PREVIEW font on preview level */
1655 game_status = GAME_MODE_PSEUDO_PREVIEW;
1659 from_x = from_y = 0;
1660 scroll_direction = MV_RIGHT;
1664 DrawPreviewLevelExt(from_x, from_y);
1665 DrawPreviewLevelLabelExt(label_state);
1667 /* initialize delay counters */
1668 DelayReached(&scroll_delay, 0);
1669 DelayReached(&label_delay, 0);
1671 if (leveldir_current->name)
1673 char label_text[MAX_OUTPUT_LINESIZE + 1];
1674 int font_nr = FONT_TEXT_1;
1675 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1678 strncpy(label_text, leveldir_current->name, max_len_label_text);
1679 label_text[max_len_label_text] = '\0';
1681 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1682 lypos = SY + MICROLABEL1_YPOS;
1684 DrawText(lxpos, lypos, label_text, font_nr);
1687 game_status = last_game_status; /* restore current game status */
1692 /* scroll preview level, if needed */
1693 if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1694 DelayReached(&scroll_delay, scroll_delay_value))
1696 switch (scroll_direction)
1701 from_x -= preview.step_offset;
1702 from_x = (from_x < 0 ? 0 : from_x);
1705 scroll_direction = MV_UP;
1709 if (from_x < level_xsize - preview.xsize)
1711 from_x += preview.step_offset;
1712 from_x = (from_x > level_xsize - preview.xsize ?
1713 level_xsize - preview.xsize : from_x);
1716 scroll_direction = MV_DOWN;
1722 from_y -= preview.step_offset;
1723 from_y = (from_y < 0 ? 0 : from_y);
1726 scroll_direction = MV_RIGHT;
1730 if (from_y < level_ysize - preview.ysize)
1732 from_y += preview.step_offset;
1733 from_y = (from_y > level_ysize - preview.ysize ?
1734 level_ysize - preview.ysize : from_y);
1737 scroll_direction = MV_LEFT;
1744 DrawPreviewLevelExt(from_x, from_y);
1747 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1748 /* redraw micro level label, if needed */
1749 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1750 !strEqual(level.author, ANONYMOUS_NAME) &&
1751 !strEqual(level.author, leveldir_current->name) &&
1752 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1754 int max_label_counter = 23;
1756 if (leveldir_current->imported_from != NULL &&
1757 strlen(leveldir_current->imported_from) > 0)
1758 max_label_counter += 14;
1759 if (leveldir_current->imported_by != NULL &&
1760 strlen(leveldir_current->imported_by) > 0)
1761 max_label_counter += 14;
1763 label_counter = (label_counter + 1) % max_label_counter;
1764 label_state = (label_counter >= 0 && label_counter <= 7 ?
1765 MICROLABEL_LEVEL_NAME :
1766 label_counter >= 9 && label_counter <= 12 ?
1767 MICROLABEL_LEVEL_AUTHOR_HEAD :
1768 label_counter >= 14 && label_counter <= 21 ?
1769 MICROLABEL_LEVEL_AUTHOR :
1770 label_counter >= 23 && label_counter <= 26 ?
1771 MICROLABEL_IMPORTED_FROM_HEAD :
1772 label_counter >= 28 && label_counter <= 35 ?
1773 MICROLABEL_IMPORTED_FROM :
1774 label_counter >= 37 && label_counter <= 40 ?
1775 MICROLABEL_IMPORTED_BY_HEAD :
1776 label_counter >= 42 && label_counter <= 49 ?
1777 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1779 if (leveldir_current->imported_from == NULL &&
1780 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1781 label_state == MICROLABEL_IMPORTED_FROM))
1782 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1783 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1785 DrawPreviewLevelLabelExt(label_state);
1788 game_status = last_game_status; /* restore current game status */
1791 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1792 int graphic, int sync_frame, int mask_mode)
1794 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1796 if (mask_mode == USE_MASKING)
1797 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1799 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1802 inline void DrawGraphicAnimation(int x, int y, int graphic)
1804 int lx = LEVELX(x), ly = LEVELY(y);
1806 if (!IN_SCR_FIELD(x, y))
1809 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1810 graphic, GfxFrame[lx][ly], NO_MASKING);
1811 MarkTileDirty(x, y);
1814 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1816 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1819 void DrawLevelElementAnimation(int x, int y, int element)
1821 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1823 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1826 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1828 int sx = SCREENX(x), sy = SCREENY(y);
1830 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1833 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1836 DrawGraphicAnimation(sx, sy, graphic);
1839 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1840 DrawLevelFieldCrumbledSand(x, y);
1842 if (GFX_CRUMBLED(Feld[x][y]))
1843 DrawLevelFieldCrumbledSand(x, y);
1847 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1849 int sx = SCREENX(x), sy = SCREENY(y);
1852 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1855 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1857 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1860 DrawGraphicAnimation(sx, sy, graphic);
1862 if (GFX_CRUMBLED(element))
1863 DrawLevelFieldCrumbledSand(x, y);
1866 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1868 if (player->use_murphy)
1870 /* this works only because currently only one player can be "murphy" ... */
1871 static int last_horizontal_dir = MV_LEFT;
1872 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1874 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1875 last_horizontal_dir = move_dir;
1877 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1879 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1881 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1887 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1890 static boolean equalGraphics(int graphic1, int graphic2)
1892 struct GraphicInfo *g1 = &graphic_info[graphic1];
1893 struct GraphicInfo *g2 = &graphic_info[graphic2];
1895 return (g1->bitmap == g2->bitmap &&
1896 g1->src_x == g2->src_x &&
1897 g1->src_y == g2->src_y &&
1898 g1->anim_frames == g2->anim_frames &&
1899 g1->anim_delay == g2->anim_delay &&
1900 g1->anim_mode == g2->anim_mode);
1903 void DrawAllPlayers()
1907 for (i = 0; i < MAX_PLAYERS; i++)
1908 if (stored_player[i].active)
1909 DrawPlayer(&stored_player[i]);
1912 void DrawPlayerField(int x, int y)
1914 if (!IS_PLAYER(x, y))
1917 DrawPlayer(PLAYERINFO(x, y));
1920 void DrawPlayer(struct PlayerInfo *player)
1922 int jx = player->jx;
1923 int jy = player->jy;
1924 int move_dir = player->MovDir;
1925 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1926 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1927 int last_jx = (player->is_moving ? jx - dx : jx);
1928 int last_jy = (player->is_moving ? jy - dy : jy);
1929 int next_jx = jx + dx;
1930 int next_jy = jy + dy;
1931 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1932 boolean player_is_opaque = FALSE;
1933 int sx = SCREENX(jx), sy = SCREENY(jy);
1934 int sxx = 0, syy = 0;
1935 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1937 int action = ACTION_DEFAULT;
1938 int last_player_graphic = getPlayerGraphic(player, move_dir);
1939 int last_player_frame = player->Frame;
1943 /* GfxElement[][] is set to the element the player is digging or collecting;
1944 remove also for off-screen player if the player is not moving anymore */
1945 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1946 GfxElement[jx][jy] = EL_UNDEFINED;
1949 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1953 if (!IN_LEV_FIELD(jx, jy))
1955 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1956 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1957 printf("DrawPlayerField(): This should never happen!\n");
1962 if (element == EL_EXPLOSION)
1965 action = (player->is_pushing ? ACTION_PUSHING :
1966 player->is_digging ? ACTION_DIGGING :
1967 player->is_collecting ? ACTION_COLLECTING :
1968 player->is_moving ? ACTION_MOVING :
1969 player->is_snapping ? ACTION_SNAPPING :
1970 player->is_dropping ? ACTION_DROPPING :
1971 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1974 if (player->is_waiting)
1975 move_dir = player->dir_waiting;
1978 InitPlayerGfxAnimation(player, action, move_dir);
1980 /* ----------------------------------------------------------------------- */
1981 /* draw things in the field the player is leaving, if needed */
1982 /* ----------------------------------------------------------------------- */
1984 if (player->is_moving)
1986 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1988 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1990 if (last_element == EL_DYNAMITE_ACTIVE ||
1991 last_element == EL_EM_DYNAMITE_ACTIVE ||
1992 last_element == EL_SP_DISK_RED_ACTIVE)
1993 DrawDynamite(last_jx, last_jy);
1995 DrawLevelFieldThruMask(last_jx, last_jy);
1997 else if (last_element == EL_DYNAMITE_ACTIVE ||
1998 last_element == EL_EM_DYNAMITE_ACTIVE ||
1999 last_element == EL_SP_DISK_RED_ACTIVE)
2000 DrawDynamite(last_jx, last_jy);
2002 /* !!! this is not enough to prevent flickering of players which are
2003 moving next to each others without a free tile between them -- this
2004 can only be solved by drawing all players layer by layer (first the
2005 background, then the foreground etc.) !!! => TODO */
2006 else if (!IS_PLAYER(last_jx, last_jy))
2007 DrawLevelField(last_jx, last_jy);
2010 DrawLevelField(last_jx, last_jy);
2013 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2014 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2017 if (!IN_SCR_FIELD(sx, sy))
2020 if (setup.direct_draw)
2021 SetDrawtoField(DRAW_BUFFERED);
2023 /* ----------------------------------------------------------------------- */
2024 /* draw things behind the player, if needed */
2025 /* ----------------------------------------------------------------------- */
2028 DrawLevelElement(jx, jy, Back[jx][jy]);
2029 else if (IS_ACTIVE_BOMB(element))
2030 DrawLevelElement(jx, jy, EL_EMPTY);
2033 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2035 int old_element = GfxElement[jx][jy];
2036 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2037 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2039 if (GFX_CRUMBLED(old_element))
2040 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2042 DrawGraphic(sx, sy, old_graphic, frame);
2044 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2045 player_is_opaque = TRUE;
2049 GfxElement[jx][jy] = EL_UNDEFINED;
2051 /* make sure that pushed elements are drawn with correct frame rate */
2052 if (player->is_pushing && player->is_moving)
2053 GfxFrame[jx][jy] = player->StepFrame;
2055 DrawLevelField(jx, jy);
2059 /* ----------------------------------------------------------------------- */
2060 /* draw player himself */
2061 /* ----------------------------------------------------------------------- */
2063 graphic = getPlayerGraphic(player, move_dir);
2065 /* in the case of changed player action or direction, prevent the current
2066 animation frame from being restarted for identical animations */
2067 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2068 player->Frame = last_player_frame;
2070 frame = getGraphicAnimationFrame(graphic, player->Frame);
2074 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2075 sxx = player->GfxPos;
2077 syy = player->GfxPos;
2080 if (!setup.soft_scrolling && ScreenMovPos)
2083 if (player_is_opaque)
2084 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2086 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2088 if (SHIELD_ON(player))
2090 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2091 IMG_SHIELD_NORMAL_ACTIVE);
2092 int frame = getGraphicAnimationFrame(graphic, -1);
2094 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2097 /* ----------------------------------------------------------------------- */
2098 /* draw things the player is pushing, if needed */
2099 /* ----------------------------------------------------------------------- */
2102 printf("::: %d, %d [%d, %d] [%d]\n",
2103 player->is_pushing, player_is_moving, player->GfxAction,
2104 player->is_moving, player_is_moving);
2108 if (player->is_pushing && player->is_moving)
2110 int px = SCREENX(jx), py = SCREENY(jy);
2111 int pxx = (TILEX - ABS(sxx)) * dx;
2112 int pyy = (TILEY - ABS(syy)) * dy;
2117 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2118 element = Feld[next_jx][next_jy];
2120 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2121 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2123 /* draw background element under pushed element (like the Sokoban field) */
2124 if (Back[next_jx][next_jy])
2125 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2127 /* masked drawing is needed for EMC style (double) movement graphics */
2128 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2132 /* ----------------------------------------------------------------------- */
2133 /* draw things in front of player (active dynamite or dynabombs) */
2134 /* ----------------------------------------------------------------------- */
2136 if (IS_ACTIVE_BOMB(element))
2138 graphic = el2img(element);
2139 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2141 if (game.emulation == EMU_SUPAPLEX)
2142 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2144 DrawGraphicThruMask(sx, sy, graphic, frame);
2147 if (player_is_moving && last_element == EL_EXPLOSION)
2149 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2150 GfxElement[last_jx][last_jy] : EL_EMPTY);
2151 int graphic = el_act2img(element, ACTION_EXPLODING);
2152 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2153 int phase = ExplodePhase[last_jx][last_jy] - 1;
2154 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2157 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2160 /* ----------------------------------------------------------------------- */
2161 /* draw elements the player is just walking/passing through/under */
2162 /* ----------------------------------------------------------------------- */
2164 if (player_is_moving)
2166 /* handle the field the player is leaving ... */
2167 if (IS_ACCESSIBLE_INSIDE(last_element))
2168 DrawLevelField(last_jx, last_jy);
2169 else if (IS_ACCESSIBLE_UNDER(last_element))
2170 DrawLevelFieldThruMask(last_jx, last_jy);
2173 /* do not redraw accessible elements if the player is just pushing them */
2174 if (!player_is_moving || !player->is_pushing)
2176 /* ... and the field the player is entering */
2177 if (IS_ACCESSIBLE_INSIDE(element))
2178 DrawLevelField(jx, jy);
2179 else if (IS_ACCESSIBLE_UNDER(element))
2180 DrawLevelFieldThruMask(jx, jy);
2183 if (setup.direct_draw)
2185 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2186 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2187 int x_size = TILEX * (1 + ABS(jx - last_jx));
2188 int y_size = TILEY * (1 + ABS(jy - last_jy));
2190 BlitBitmap(drawto_field, window,
2191 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2192 SetDrawtoField(DRAW_DIRECT);
2195 MarkTileDirty(sx, sy);
2198 /* ------------------------------------------------------------------------- */
2200 void WaitForEventToContinue()
2202 boolean still_wait = TRUE;
2204 /* simulate releasing mouse button over last gadget, if still pressed */
2206 HandleGadgets(-1, -1, 0);
2208 button_status = MB_RELEASED;
2220 case EVENT_BUTTONPRESS:
2221 case EVENT_KEYPRESS:
2225 case EVENT_KEYRELEASE:
2226 ClearPlayerAction();
2230 HandleOtherEvents(&event);
2234 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2241 /* don't eat all CPU time */
2246 #define MAX_REQUEST_LINES 13
2247 #define MAX_REQUEST_LINE_FONT1_LEN 7
2248 #define MAX_REQUEST_LINE_FONT2_LEN 10
2250 boolean Request(char *text, unsigned int req_state)
2252 int mx, my, ty, result = -1;
2253 unsigned int old_door_state;
2254 int last_game_status = game_status; /* save current game status */
2255 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2256 int font_nr = FONT_TEXT_2;
2257 int max_word_len = 0;
2260 for (text_ptr = text; *text_ptr; text_ptr++)
2262 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2264 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2266 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2267 font_nr = FONT_LEVEL_NUMBER;
2273 if (game_status == GAME_MODE_PLAYING &&
2274 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2275 BlitScreenToBitmap_EM(backbuffer);
2277 /* disable deactivated drawing when quick-loading level tape recording */
2278 if (tape.playing && tape.deactivate_display)
2279 TapeDeactivateDisplayOff(TRUE);
2281 SetMouseCursor(CURSOR_DEFAULT);
2283 #if defined(NETWORK_AVALIABLE)
2284 /* pause network game while waiting for request to answer */
2285 if (options.network &&
2286 game_status == GAME_MODE_PLAYING &&
2287 req_state & REQUEST_WAIT_FOR_INPUT)
2288 SendToServer_PausePlaying();
2291 old_door_state = GetDoorState();
2293 /* simulate releasing mouse button over last gadget, if still pressed */
2295 HandleGadgets(-1, -1, 0);
2299 if (old_door_state & DOOR_OPEN_1)
2301 CloseDoor(DOOR_CLOSE_1);
2303 /* save old door content */
2304 BlitBitmap(bitmap_db_door, bitmap_db_door,
2305 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2306 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2309 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2311 /* clear door drawing field */
2312 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2314 /* force DOOR font on preview level */
2315 game_status = GAME_MODE_PSEUDO_DOOR;
2317 /* write text for request */
2318 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2320 char text_line[max_request_line_len + 1];
2326 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2329 if (!tc || tc == ' ')
2340 strncpy(text_line, text, tl);
2343 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2344 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2345 text_line, font_nr);
2347 text += tl + (tc == ' ' ? 1 : 0);
2350 game_status = last_game_status; /* restore current game status */
2352 if (req_state & REQ_ASK)
2354 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2355 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2357 else if (req_state & REQ_CONFIRM)
2359 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2361 else if (req_state & REQ_PLAYER)
2363 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2364 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2365 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2366 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2369 /* copy request gadgets to door backbuffer */
2370 BlitBitmap(drawto, bitmap_db_door,
2371 DX, DY, DXSIZE, DYSIZE,
2372 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2374 OpenDoor(DOOR_OPEN_1);
2376 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2378 SetDrawBackgroundMask(REDRAW_FIELD);
2383 if (game_status != GAME_MODE_MAIN)
2386 button_status = MB_RELEASED;
2388 request_gadget_id = -1;
2390 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2402 case EVENT_BUTTONPRESS:
2403 case EVENT_BUTTONRELEASE:
2404 case EVENT_MOTIONNOTIFY:
2406 if (event.type == EVENT_MOTIONNOTIFY)
2408 if (!PointerInWindow(window))
2409 continue; /* window and pointer are on different screens */
2414 motion_status = TRUE;
2415 mx = ((MotionEvent *) &event)->x;
2416 my = ((MotionEvent *) &event)->y;
2420 motion_status = FALSE;
2421 mx = ((ButtonEvent *) &event)->x;
2422 my = ((ButtonEvent *) &event)->y;
2423 if (event.type == EVENT_BUTTONPRESS)
2424 button_status = ((ButtonEvent *) &event)->button;
2426 button_status = MB_RELEASED;
2429 /* this sets 'request_gadget_id' */
2430 HandleGadgets(mx, my, button_status);
2432 switch(request_gadget_id)
2434 case TOOL_CTRL_ID_YES:
2437 case TOOL_CTRL_ID_NO:
2440 case TOOL_CTRL_ID_CONFIRM:
2441 result = TRUE | FALSE;
2444 case TOOL_CTRL_ID_PLAYER_1:
2447 case TOOL_CTRL_ID_PLAYER_2:
2450 case TOOL_CTRL_ID_PLAYER_3:
2453 case TOOL_CTRL_ID_PLAYER_4:
2464 case EVENT_KEYPRESS:
2465 switch(GetEventKey((KeyEvent *)&event, TRUE))
2478 if (req_state & REQ_PLAYER)
2482 case EVENT_KEYRELEASE:
2483 ClearPlayerAction();
2487 HandleOtherEvents(&event);
2491 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2493 int joy = AnyJoystick();
2495 if (joy & JOY_BUTTON_1)
2497 else if (joy & JOY_BUTTON_2)
2503 /* don't eat all CPU time */
2507 if (game_status != GAME_MODE_MAIN)
2512 if (!(req_state & REQ_STAY_OPEN))
2514 CloseDoor(DOOR_CLOSE_1);
2516 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2517 (req_state & REQ_REOPEN))
2518 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2523 SetDrawBackgroundMask(REDRAW_FIELD);
2525 #if defined(NETWORK_AVALIABLE)
2526 /* continue network game after request */
2527 if (options.network &&
2528 game_status == GAME_MODE_PLAYING &&
2529 req_state & REQUEST_WAIT_FOR_INPUT)
2530 SendToServer_ContinuePlaying();
2533 /* restore deactivated drawing when quick-loading level tape recording */
2534 if (tape.playing && tape.deactivate_display)
2535 TapeDeactivateDisplayOn();
2540 unsigned int OpenDoor(unsigned int door_state)
2542 if (door_state & DOOR_COPY_BACK)
2544 if (door_state & DOOR_OPEN_1)
2545 BlitBitmap(bitmap_db_door, bitmap_db_door,
2546 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2547 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2549 if (door_state & DOOR_OPEN_2)
2550 BlitBitmap(bitmap_db_door, bitmap_db_door,
2551 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2552 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2554 door_state &= ~DOOR_COPY_BACK;
2557 return MoveDoor(door_state);
2560 unsigned int CloseDoor(unsigned int door_state)
2562 unsigned int old_door_state = GetDoorState();
2564 if (!(door_state & DOOR_NO_COPY_BACK))
2566 if (old_door_state & DOOR_OPEN_1)
2567 BlitBitmap(backbuffer, bitmap_db_door,
2568 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2570 if (old_door_state & DOOR_OPEN_2)
2571 BlitBitmap(backbuffer, bitmap_db_door,
2572 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2574 door_state &= ~DOOR_NO_COPY_BACK;
2577 return MoveDoor(door_state);
2580 unsigned int GetDoorState()
2582 return MoveDoor(DOOR_GET_STATE);
2585 unsigned int SetDoorState(unsigned int door_state)
2587 return MoveDoor(door_state | DOOR_SET_STATE);
2590 unsigned int MoveDoor(unsigned int door_state)
2592 static int door1 = DOOR_OPEN_1;
2593 static int door2 = DOOR_CLOSE_2;
2594 unsigned long door_delay = 0;
2595 unsigned long door_delay_value;
2598 if (door_1.width < 0 || door_1.width > DXSIZE)
2599 door_1.width = DXSIZE;
2600 if (door_1.height < 0 || door_1.height > DYSIZE)
2601 door_1.height = DYSIZE;
2602 if (door_2.width < 0 || door_2.width > VXSIZE)
2603 door_2.width = VXSIZE;
2604 if (door_2.height < 0 || door_2.height > VYSIZE)
2605 door_2.height = VYSIZE;
2607 if (door_state == DOOR_GET_STATE)
2608 return (door1 | door2);
2610 if (door_state & DOOR_SET_STATE)
2612 if (door_state & DOOR_ACTION_1)
2613 door1 = door_state & DOOR_ACTION_1;
2614 if (door_state & DOOR_ACTION_2)
2615 door2 = door_state & DOOR_ACTION_2;
2617 return (door1 | door2);
2620 if (!(door_state & DOOR_FORCE_REDRAW))
2622 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2623 door_state &= ~DOOR_OPEN_1;
2624 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2625 door_state &= ~DOOR_CLOSE_1;
2626 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2627 door_state &= ~DOOR_OPEN_2;
2628 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2629 door_state &= ~DOOR_CLOSE_2;
2632 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2635 if (setup.quick_doors)
2637 stepsize = 20; /* must be choosen to always draw last frame */
2638 door_delay_value = 0;
2641 if (global.autoplay_leveldir)
2643 door_state |= DOOR_NO_DELAY;
2644 door_state &= ~DOOR_CLOSE_ALL;
2647 if (door_state & DOOR_ACTION)
2649 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2650 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2651 boolean door_1_done = (!handle_door_1);
2652 boolean door_2_done = (!handle_door_2);
2653 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2654 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2655 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2656 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2657 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2658 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2659 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2660 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2661 int door_skip = max_door_size - door_size;
2663 int end = door_size;
2665 int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
2669 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2671 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2675 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2677 /* opening door sound has priority over simultaneously closing door */
2678 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2679 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2680 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2681 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2684 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2687 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2688 GC gc = bitmap->stored_clip_gc;
2690 if (door_state & DOOR_ACTION_1)
2692 int a = MIN(x * door_1.step_offset, end);
2693 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2694 int i = p + door_skip;
2696 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2698 BlitBitmap(bitmap_db_door, drawto,
2699 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2700 DXSIZE, DYSIZE, DX, DY);
2704 BlitBitmap(bitmap_db_door, drawto,
2705 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2706 DXSIZE, DYSIZE - p / 2, DX, DY);
2708 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2711 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2713 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2714 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2715 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2716 int dst2_x = DX, dst2_y = DY;
2717 int width = i, height = DYSIZE;
2719 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2720 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2723 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2724 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2727 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2729 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2730 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2731 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2732 int dst2_x = DX, dst2_y = DY;
2733 int width = DXSIZE, height = i;
2735 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2736 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2739 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2740 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2743 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2745 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2747 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2748 BlitBitmapMasked(bitmap, drawto,
2749 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2750 DX + DXSIZE - i, DY + j);
2751 BlitBitmapMasked(bitmap, drawto,
2752 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2753 DX + DXSIZE - i, DY + 140 + j);
2754 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2755 DY - (DOOR_GFX_PAGEY1 + j));
2756 BlitBitmapMasked(bitmap, drawto,
2757 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2759 BlitBitmapMasked(bitmap, drawto,
2760 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2763 BlitBitmapMasked(bitmap, drawto,
2764 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2766 BlitBitmapMasked(bitmap, drawto,
2767 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2769 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2770 BlitBitmapMasked(bitmap, drawto,
2771 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2772 DX + DXSIZE - i, DY + 77 + j);
2773 BlitBitmapMasked(bitmap, drawto,
2774 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2775 DX + DXSIZE - i, DY + 203 + j);
2778 redraw_mask |= REDRAW_DOOR_1;
2779 door_1_done = (a == end);
2782 if (door_state & DOOR_ACTION_2)
2785 int a = MIN(x * door_2.step_offset, door_size);
2786 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2787 int i = p + door_skip;
2789 int a = MIN(x * door_2.step_offset, door_size_2);
2790 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2791 int i = p + door_skip;
2794 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2796 BlitBitmap(bitmap_db_door, drawto,
2797 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2798 VXSIZE, VYSIZE, VX, VY);
2800 else if (x <= VYSIZE)
2802 BlitBitmap(bitmap_db_door, drawto,
2803 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2804 VXSIZE, VYSIZE - p / 2, VX, VY);
2806 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2809 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2811 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2812 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2813 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2814 int dst2_x = VX, dst2_y = VY;
2815 int width = i, height = VYSIZE;
2817 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2818 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2821 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2822 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2825 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2827 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2828 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2829 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2830 int dst2_x = VX, dst2_y = VY;
2831 int width = VXSIZE, height = i;
2833 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2834 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2837 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2838 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2841 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2843 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2845 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2846 BlitBitmapMasked(bitmap, drawto,
2847 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2848 VX + VXSIZE - i, VY + j);
2849 SetClipOrigin(bitmap, gc,
2850 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2851 BlitBitmapMasked(bitmap, drawto,
2852 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2855 BlitBitmapMasked(bitmap, drawto,
2856 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2857 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2858 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2859 BlitBitmapMasked(bitmap, drawto,
2860 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2862 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2865 redraw_mask |= REDRAW_DOOR_2;
2866 door_2_done = (a == VXSIZE);
2869 if (!(door_state & DOOR_NO_DELAY))
2873 if (game_status == GAME_MODE_MAIN)
2876 WaitUntilDelayReached(&door_delay, door_delay_value);
2881 if (door_state & DOOR_ACTION_1)
2882 door1 = door_state & DOOR_ACTION_1;
2883 if (door_state & DOOR_ACTION_2)
2884 door2 = door_state & DOOR_ACTION_2;
2886 return (door1 | door2);
2889 void DrawSpecialEditorDoor()
2891 /* draw bigger toolbox window */
2892 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2893 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2895 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2896 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2899 redraw_mask |= REDRAW_ALL;
2902 void UndrawSpecialEditorDoor()
2904 /* draw normal tape recorder window */
2905 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2906 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2909 redraw_mask |= REDRAW_ALL;
2913 /* ---------- new tool button stuff ---------------------------------------- */
2915 /* graphic position values for tool buttons */
2916 #define TOOL_BUTTON_YES_XPOS 2
2917 #define TOOL_BUTTON_YES_YPOS 250
2918 #define TOOL_BUTTON_YES_GFX_YPOS 0
2919 #define TOOL_BUTTON_YES_XSIZE 46
2920 #define TOOL_BUTTON_YES_YSIZE 28
2921 #define TOOL_BUTTON_NO_XPOS 52
2922 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2923 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2924 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2925 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2926 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2927 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2928 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2929 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2930 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2931 #define TOOL_BUTTON_PLAYER_XSIZE 30
2932 #define TOOL_BUTTON_PLAYER_YSIZE 30
2933 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2934 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2935 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2936 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2937 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2938 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2939 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2940 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2941 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2942 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2943 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2944 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2945 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2946 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2947 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2948 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2949 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2950 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2951 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2952 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2961 } toolbutton_info[NUM_TOOL_BUTTONS] =
2964 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2965 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2966 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2971 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2972 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2973 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2978 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2979 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2980 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2981 TOOL_CTRL_ID_CONFIRM,
2985 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2986 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2987 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2988 TOOL_CTRL_ID_PLAYER_1,
2992 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2993 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2994 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2995 TOOL_CTRL_ID_PLAYER_2,
2999 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3000 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3001 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3002 TOOL_CTRL_ID_PLAYER_3,
3006 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3007 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3008 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3009 TOOL_CTRL_ID_PLAYER_4,
3014 void CreateToolButtons()
3018 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3020 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3021 Bitmap *deco_bitmap = None;
3022 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3023 struct GadgetInfo *gi;
3024 unsigned long event_mask;
3025 int gd_xoffset, gd_yoffset;
3026 int gd_x1, gd_x2, gd_y;
3029 event_mask = GD_EVENT_RELEASED;
3031 gd_xoffset = toolbutton_info[i].xpos;
3032 gd_yoffset = toolbutton_info[i].ypos;
3033 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3034 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3035 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3037 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3039 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3041 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3042 &deco_bitmap, &deco_x, &deco_y);
3043 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3044 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3047 gi = CreateGadget(GDI_CUSTOM_ID, id,
3048 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3049 GDI_X, DX + toolbutton_info[i].x,
3050 GDI_Y, DY + toolbutton_info[i].y,
3051 GDI_WIDTH, toolbutton_info[i].width,
3052 GDI_HEIGHT, toolbutton_info[i].height,
3053 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3054 GDI_STATE, GD_BUTTON_UNPRESSED,
3055 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3056 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3057 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3058 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3059 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3060 GDI_DECORATION_SHIFTING, 1, 1,
3061 GDI_EVENT_MASK, event_mask,
3062 GDI_CALLBACK_ACTION, HandleToolButtons,
3066 Error(ERR_EXIT, "cannot create gadget");
3068 tool_gadget[id] = gi;
3072 void FreeToolButtons()
3076 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3077 FreeGadget(tool_gadget[i]);
3080 static void UnmapToolButtons()
3084 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3085 UnmapGadget(tool_gadget[i]);
3088 static void HandleToolButtons(struct GadgetInfo *gi)
3090 request_gadget_id = gi->custom_id;
3093 static struct Mapping_EM_to_RND_object
3096 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3097 boolean is_backside; /* backside of moving element */
3103 em_object_mapping_list[] =
3106 Xblank, TRUE, FALSE,
3110 Yacid_splash_eB, FALSE, FALSE,
3111 EL_ACID_SPLASH_RIGHT, -1, -1
3114 Yacid_splash_wB, FALSE, FALSE,
3115 EL_ACID_SPLASH_LEFT, -1, -1
3118 #ifdef EM_ENGINE_BAD_ROLL
3120 Xstone_force_e, FALSE, FALSE,
3121 EL_ROCK, -1, MV_BIT_RIGHT
3124 Xstone_force_w, FALSE, FALSE,
3125 EL_ROCK, -1, MV_BIT_LEFT
3128 Xnut_force_e, FALSE, FALSE,
3129 EL_NUT, -1, MV_BIT_RIGHT
3132 Xnut_force_w, FALSE, FALSE,
3133 EL_NUT, -1, MV_BIT_LEFT
3136 Xspring_force_e, FALSE, FALSE,
3137 EL_SPRING, -1, MV_BIT_RIGHT
3140 Xspring_force_w, FALSE, FALSE,
3141 EL_SPRING, -1, MV_BIT_LEFT
3144 Xemerald_force_e, FALSE, FALSE,
3145 EL_EMERALD, -1, MV_BIT_RIGHT
3148 Xemerald_force_w, FALSE, FALSE,
3149 EL_EMERALD, -1, MV_BIT_LEFT
3152 Xdiamond_force_e, FALSE, FALSE,
3153 EL_DIAMOND, -1, MV_BIT_RIGHT
3156 Xdiamond_force_w, FALSE, FALSE,
3157 EL_DIAMOND, -1, MV_BIT_LEFT
3160 Xbomb_force_e, FALSE, FALSE,
3161 EL_BOMB, -1, MV_BIT_RIGHT
3164 Xbomb_force_w, FALSE, FALSE,
3165 EL_BOMB, -1, MV_BIT_LEFT
3167 #endif /* EM_ENGINE_BAD_ROLL */
3170 Xstone, TRUE, FALSE,
3174 Xstone_pause, FALSE, FALSE,
3178 Xstone_fall, FALSE, FALSE,
3182 Ystone_s, FALSE, FALSE,
3183 EL_ROCK, ACTION_FALLING, -1
3186 Ystone_sB, FALSE, TRUE,
3187 EL_ROCK, ACTION_FALLING, -1
3190 Ystone_e, FALSE, FALSE,
3191 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3194 Ystone_eB, FALSE, TRUE,
3195 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3198 Ystone_w, FALSE, FALSE,
3199 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3202 Ystone_wB, FALSE, TRUE,
3203 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3210 Xnut_pause, FALSE, FALSE,
3214 Xnut_fall, FALSE, FALSE,
3218 Ynut_s, FALSE, FALSE,
3219 EL_NUT, ACTION_FALLING, -1
3222 Ynut_sB, FALSE, TRUE,
3223 EL_NUT, ACTION_FALLING, -1
3226 Ynut_e, FALSE, FALSE,
3227 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3230 Ynut_eB, FALSE, TRUE,
3231 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3234 Ynut_w, FALSE, FALSE,
3235 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3238 Ynut_wB, FALSE, TRUE,
3239 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3242 Xbug_n, TRUE, FALSE,
3246 Xbug_e, TRUE, FALSE,
3247 EL_BUG_RIGHT, -1, -1
3250 Xbug_s, TRUE, FALSE,
3254 Xbug_w, TRUE, FALSE,
3258 Xbug_gon, FALSE, FALSE,
3262 Xbug_goe, FALSE, FALSE,
3263 EL_BUG_RIGHT, -1, -1
3266 Xbug_gos, FALSE, FALSE,
3270 Xbug_gow, FALSE, FALSE,
3274 Ybug_n, FALSE, FALSE,
3275 EL_BUG, ACTION_MOVING, MV_BIT_UP
3278 Ybug_nB, FALSE, TRUE,
3279 EL_BUG, ACTION_MOVING, MV_BIT_UP
3282 Ybug_e, FALSE, FALSE,
3283 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3286 Ybug_eB, FALSE, TRUE,
3287 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3290 Ybug_s, FALSE, FALSE,
3291 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3294 Ybug_sB, FALSE, TRUE,
3295 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3298 Ybug_w, FALSE, FALSE,
3299 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3302 Ybug_wB, FALSE, TRUE,
3303 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3306 Ybug_w_n, FALSE, FALSE,
3307 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3310 Ybug_n_e, FALSE, FALSE,
3311 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3314 Ybug_e_s, FALSE, FALSE,
3315 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3318 Ybug_s_w, FALSE, FALSE,
3319 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3322 Ybug_e_n, FALSE, FALSE,
3323 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3326 Ybug_s_e, FALSE, FALSE,
3327 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3330 Ybug_w_s, FALSE, FALSE,
3331 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3334 Ybug_n_w, FALSE, FALSE,
3335 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3338 Ybug_stone, FALSE, FALSE,
3339 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3342 Ybug_spring, FALSE, FALSE,
3343 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3346 Xtank_n, TRUE, FALSE,
3347 EL_SPACESHIP_UP, -1, -1
3350 Xtank_e, TRUE, FALSE,
3351 EL_SPACESHIP_RIGHT, -1, -1
3354 Xtank_s, TRUE, FALSE,
3355 EL_SPACESHIP_DOWN, -1, -1
3358 Xtank_w, TRUE, FALSE,
3359 EL_SPACESHIP_LEFT, -1, -1
3362 Xtank_gon, FALSE, FALSE,
3363 EL_SPACESHIP_UP, -1, -1
3366 Xtank_goe, FALSE, FALSE,
3367 EL_SPACESHIP_RIGHT, -1, -1
3370 Xtank_gos, FALSE, FALSE,
3371 EL_SPACESHIP_DOWN, -1, -1
3374 Xtank_gow, FALSE, FALSE,
3375 EL_SPACESHIP_LEFT, -1, -1
3378 Ytank_n, FALSE, FALSE,
3379 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3382 Ytank_nB, FALSE, TRUE,
3383 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3386 Ytank_e, FALSE, FALSE,
3387 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3390 Ytank_eB, FALSE, TRUE,
3391 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3394 Ytank_s, FALSE, FALSE,
3395 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3398 Ytank_sB, FALSE, TRUE,
3399 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3402 Ytank_w, FALSE, FALSE,
3403 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3406 Ytank_wB, FALSE, TRUE,
3407 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3410 Ytank_w_n, FALSE, FALSE,
3411 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3414 Ytank_n_e, FALSE, FALSE,
3415 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3418 Ytank_e_s, FALSE, FALSE,
3419 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3422 Ytank_s_w, FALSE, FALSE,
3423 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3426 Ytank_e_n, FALSE, FALSE,
3427 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3430 Ytank_s_e, FALSE, FALSE,
3431 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3434 Ytank_w_s, FALSE, FALSE,
3435 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3438 Ytank_n_w, FALSE, FALSE,
3439 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3442 Ytank_stone, FALSE, FALSE,
3443 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3446 Ytank_spring, FALSE, FALSE,
3447 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3450 Xandroid, TRUE, FALSE,
3451 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3454 Xandroid_1_n, FALSE, FALSE,
3455 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3458 Xandroid_2_n, FALSE, FALSE,
3459 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3462 Xandroid_1_e, FALSE, FALSE,
3463 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3466 Xandroid_2_e, FALSE, FALSE,
3467 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3470 Xandroid_1_w, FALSE, FALSE,
3471 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3474 Xandroid_2_w, FALSE, FALSE,
3475 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3478 Xandroid_1_s, FALSE, FALSE,
3479 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3482 Xandroid_2_s, FALSE, FALSE,
3483 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3486 Yandroid_n, FALSE, FALSE,
3487 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3490 Yandroid_nB, FALSE, TRUE,
3491 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3494 Yandroid_ne, FALSE, FALSE,
3495 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3498 Yandroid_neB, FALSE, TRUE,
3499 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3502 Yandroid_e, FALSE, FALSE,
3503 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3506 Yandroid_eB, FALSE, TRUE,
3507 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3510 Yandroid_se, FALSE, FALSE,
3511 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3514 Yandroid_seB, FALSE, TRUE,
3515 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3518 Yandroid_s, FALSE, FALSE,
3519 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3522 Yandroid_sB, FALSE, TRUE,
3523 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3526 Yandroid_sw, FALSE, FALSE,
3527 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3530 Yandroid_swB, FALSE, TRUE,
3531 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3534 Yandroid_w, FALSE, FALSE,
3535 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3538 Yandroid_wB, FALSE, TRUE,
3539 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3542 Yandroid_nw, FALSE, FALSE,
3543 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3546 Yandroid_nwB, FALSE, TRUE,
3547 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3550 Xspring, TRUE, FALSE,
3554 Xspring_pause, FALSE, FALSE,
3558 Xspring_e, FALSE, FALSE,
3562 Xspring_w, FALSE, FALSE,
3566 Xspring_fall, FALSE, FALSE,
3570 Yspring_s, FALSE, FALSE,
3571 EL_SPRING, ACTION_FALLING, -1
3574 Yspring_sB, FALSE, TRUE,
3575 EL_SPRING, ACTION_FALLING, -1
3578 Yspring_e, FALSE, FALSE,
3579 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3582 Yspring_eB, FALSE, TRUE,
3583 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3586 Yspring_w, FALSE, FALSE,
3587 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3590 Yspring_wB, FALSE, TRUE,
3591 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3594 Yspring_kill_e, FALSE, FALSE,
3595 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3598 Yspring_kill_eB, FALSE, TRUE,
3599 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3602 Yspring_kill_w, FALSE, FALSE,
3603 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3606 Yspring_kill_wB, FALSE, TRUE,
3607 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3610 Xeater_n, TRUE, FALSE,
3611 EL_YAMYAM_UP, -1, -1
3614 Xeater_e, TRUE, FALSE,
3615 EL_YAMYAM_RIGHT, -1, -1
3618 Xeater_w, TRUE, FALSE,
3619 EL_YAMYAM_LEFT, -1, -1
3622 Xeater_s, TRUE, FALSE,
3623 EL_YAMYAM_DOWN, -1, -1
3626 Yeater_n, FALSE, FALSE,
3627 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3630 Yeater_nB, FALSE, TRUE,
3631 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3634 Yeater_e, FALSE, FALSE,
3635 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3638 Yeater_eB, FALSE, TRUE,
3639 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3642 Yeater_s, FALSE, FALSE,
3643 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3646 Yeater_sB, FALSE, TRUE,
3647 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3650 Yeater_w, FALSE, FALSE,
3651 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3654 Yeater_wB, FALSE, TRUE,
3655 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3658 Yeater_stone, FALSE, FALSE,
3659 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3662 Yeater_spring, FALSE, FALSE,
3663 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3666 Xalien, TRUE, FALSE,
3670 Xalien_pause, FALSE, FALSE,
3674 Yalien_n, FALSE, FALSE,
3675 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3678 Yalien_nB, FALSE, TRUE,
3679 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3682 Yalien_e, FALSE, FALSE,
3683 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3686 Yalien_eB, FALSE, TRUE,
3687 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3690 Yalien_s, FALSE, FALSE,
3691 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3694 Yalien_sB, FALSE, TRUE,
3695 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3698 Yalien_w, FALSE, FALSE,
3699 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3702 Yalien_wB, FALSE, TRUE,
3703 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3706 Yalien_stone, FALSE, FALSE,
3707 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3710 Yalien_spring, FALSE, FALSE,
3711 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3714 Xemerald, TRUE, FALSE,
3718 Xemerald_pause, FALSE, FALSE,
3722 Xemerald_fall, FALSE, FALSE,
3726 Xemerald_shine, FALSE, FALSE,
3727 EL_EMERALD, ACTION_TWINKLING, -1
3730 Yemerald_s, FALSE, FALSE,
3731 EL_EMERALD, ACTION_FALLING, -1
3734 Yemerald_sB, FALSE, TRUE,
3735 EL_EMERALD, ACTION_FALLING, -1
3738 Yemerald_e, FALSE, FALSE,
3739 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3742 Yemerald_eB, FALSE, TRUE,
3743 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3746 Yemerald_w, FALSE, FALSE,
3747 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3750 Yemerald_wB, FALSE, TRUE,
3751 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3754 Yemerald_eat, FALSE, FALSE,
3755 EL_EMERALD, ACTION_COLLECTING, -1
3758 Yemerald_stone, FALSE, FALSE,
3759 EL_NUT, ACTION_BREAKING, -1
3762 Xdiamond, TRUE, FALSE,
3766 Xdiamond_pause, FALSE, FALSE,
3770 Xdiamond_fall, FALSE, FALSE,
3774 Xdiamond_shine, FALSE, FALSE,
3775 EL_DIAMOND, ACTION_TWINKLING, -1
3778 Ydiamond_s, FALSE, FALSE,
3779 EL_DIAMOND, ACTION_FALLING, -1
3782 Ydiamond_sB, FALSE, TRUE,
3783 EL_DIAMOND, ACTION_FALLING, -1
3786 Ydiamond_e, FALSE, FALSE,
3787 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3790 Ydiamond_eB, FALSE, TRUE,
3791 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3794 Ydiamond_w, FALSE, FALSE,
3795 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3798 Ydiamond_wB, FALSE, TRUE,
3799 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3802 Ydiamond_eat, FALSE, FALSE,
3803 EL_DIAMOND, ACTION_COLLECTING, -1
3806 Ydiamond_stone, FALSE, FALSE,
3807 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3810 Xdrip_fall, TRUE, FALSE,
3811 EL_AMOEBA_DROP, -1, -1
3814 Xdrip_stretch, FALSE, FALSE,
3815 EL_AMOEBA_DROP, ACTION_FALLING, -1
3818 Xdrip_stretchB, FALSE, TRUE,
3819 EL_AMOEBA_DROP, ACTION_FALLING, -1
3822 Xdrip_eat, FALSE, FALSE,
3823 EL_AMOEBA_DROP, ACTION_GROWING, -1
3826 Ydrip_s1, FALSE, FALSE,
3827 EL_AMOEBA_DROP, ACTION_FALLING, -1
3830 Ydrip_s1B, FALSE, TRUE,
3831 EL_AMOEBA_DROP, ACTION_FALLING, -1
3834 Ydrip_s2, FALSE, FALSE,
3835 EL_AMOEBA_DROP, ACTION_FALLING, -1
3838 Ydrip_s2B, FALSE, TRUE,
3839 EL_AMOEBA_DROP, ACTION_FALLING, -1
3846 Xbomb_pause, FALSE, FALSE,
3850 Xbomb_fall, FALSE, FALSE,
3854 Ybomb_s, FALSE, FALSE,
3855 EL_BOMB, ACTION_FALLING, -1
3858 Ybomb_sB, FALSE, TRUE,
3859 EL_BOMB, ACTION_FALLING, -1
3862 Ybomb_e, FALSE, FALSE,
3863 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3866 Ybomb_eB, FALSE, TRUE,
3867 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3870 Ybomb_w, FALSE, FALSE,
3871 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3874 Ybomb_wB, FALSE, TRUE,
3875 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3878 Ybomb_eat, FALSE, FALSE,
3879 EL_BOMB, ACTION_ACTIVATING, -1
3882 Xballoon, TRUE, FALSE,
3886 Yballoon_n, FALSE, FALSE,
3887 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3890 Yballoon_nB, FALSE, TRUE,
3891 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3894 Yballoon_e, FALSE, FALSE,
3895 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3898 Yballoon_eB, FALSE, TRUE,
3899 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3902 Yballoon_s, FALSE, FALSE,
3903 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3906 Yballoon_sB, FALSE, TRUE,
3907 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3910 Yballoon_w, FALSE, FALSE,
3911 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3914 Yballoon_wB, FALSE, TRUE,
3915 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3918 Xgrass, TRUE, FALSE,
3919 EL_EMC_GRASS, -1, -1
3922 Ygrass_nB, FALSE, FALSE,
3923 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3926 Ygrass_eB, FALSE, FALSE,
3927 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3930 Ygrass_sB, FALSE, FALSE,
3931 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3934 Ygrass_wB, FALSE, FALSE,
3935 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3942 Ydirt_nB, FALSE, FALSE,
3943 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3946 Ydirt_eB, FALSE, FALSE,
3947 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3950 Ydirt_sB, FALSE, FALSE,
3951 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3954 Ydirt_wB, FALSE, FALSE,
3955 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3958 Xacid_ne, TRUE, FALSE,
3959 EL_ACID_POOL_TOPRIGHT, -1, -1
3962 Xacid_se, TRUE, FALSE,
3963 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3966 Xacid_s, TRUE, FALSE,
3967 EL_ACID_POOL_BOTTOM, -1, -1
3970 Xacid_sw, TRUE, FALSE,
3971 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3974 Xacid_nw, TRUE, FALSE,
3975 EL_ACID_POOL_TOPLEFT, -1, -1
3978 Xacid_1, TRUE, FALSE,
3982 Xacid_2, FALSE, FALSE,
3986 Xacid_3, FALSE, FALSE,
3990 Xacid_4, FALSE, FALSE,
3994 Xacid_5, FALSE, FALSE,
3998 Xacid_6, FALSE, FALSE,
4002 Xacid_7, FALSE, FALSE,
4006 Xacid_8, FALSE, FALSE,
4010 Xball_1, TRUE, FALSE,
4011 EL_EMC_MAGIC_BALL, -1, -1
4014 Xball_1B, FALSE, FALSE,
4015 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4018 Xball_2, FALSE, FALSE,
4019 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4022 Xball_2B, FALSE, FALSE,
4023 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4026 Yball_eat, FALSE, FALSE,
4027 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4030 Ykey_1_eat, FALSE, FALSE,
4031 EL_EM_KEY_1, ACTION_COLLECTING, -1
4034 Ykey_2_eat, FALSE, FALSE,
4035 EL_EM_KEY_2, ACTION_COLLECTING, -1
4038 Ykey_3_eat, FALSE, FALSE,
4039 EL_EM_KEY_3, ACTION_COLLECTING, -1
4042 Ykey_4_eat, FALSE, FALSE,
4043 EL_EM_KEY_4, ACTION_COLLECTING, -1
4046 Ykey_5_eat, FALSE, FALSE,
4047 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4050 Ykey_6_eat, FALSE, FALSE,
4051 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4054 Ykey_7_eat, FALSE, FALSE,
4055 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4058 Ykey_8_eat, FALSE, FALSE,
4059 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4062 Ylenses_eat, FALSE, FALSE,
4063 EL_EMC_LENSES, ACTION_COLLECTING, -1
4066 Ymagnify_eat, FALSE, FALSE,
4067 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4070 Ygrass_eat, FALSE, FALSE,
4071 EL_EMC_GRASS, ACTION_SNAPPING, -1
4074 Ydirt_eat, FALSE, FALSE,
4075 EL_SAND, ACTION_SNAPPING, -1
4078 Xgrow_ns, TRUE, FALSE,
4079 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4082 Ygrow_ns_eat, FALSE, FALSE,
4083 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4086 Xgrow_ew, TRUE, FALSE,
4087 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4090 Ygrow_ew_eat, FALSE, FALSE,
4091 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4094 Xwonderwall, TRUE, FALSE,
4095 EL_MAGIC_WALL, -1, -1
4098 XwonderwallB, FALSE, FALSE,
4099 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4102 Xamoeba_1, TRUE, FALSE,
4103 EL_AMOEBA_DRY, ACTION_OTHER, -1
4106 Xamoeba_2, FALSE, FALSE,
4107 EL_AMOEBA_DRY, ACTION_OTHER, -1
4110 Xamoeba_3, FALSE, FALSE,
4111 EL_AMOEBA_DRY, ACTION_OTHER, -1
4114 Xamoeba_4, FALSE, FALSE,
4115 EL_AMOEBA_DRY, ACTION_OTHER, -1
4118 Xamoeba_5, TRUE, FALSE,
4119 EL_AMOEBA_WET, ACTION_OTHER, -1
4122 Xamoeba_6, FALSE, FALSE,
4123 EL_AMOEBA_WET, ACTION_OTHER, -1
4126 Xamoeba_7, FALSE, FALSE,
4127 EL_AMOEBA_WET, ACTION_OTHER, -1
4130 Xamoeba_8, FALSE, FALSE,
4131 EL_AMOEBA_WET, ACTION_OTHER, -1
4134 Xdoor_1, TRUE, FALSE,
4135 EL_EM_GATE_1, -1, -1
4138 Xdoor_2, TRUE, FALSE,
4139 EL_EM_GATE_2, -1, -1
4142 Xdoor_3, TRUE, FALSE,
4143 EL_EM_GATE_3, -1, -1
4146 Xdoor_4, TRUE, FALSE,
4147 EL_EM_GATE_4, -1, -1
4150 Xdoor_5, TRUE, FALSE,
4151 EL_EMC_GATE_5, -1, -1
4154 Xdoor_6, TRUE, FALSE,
4155 EL_EMC_GATE_6, -1, -1
4158 Xdoor_7, TRUE, FALSE,
4159 EL_EMC_GATE_7, -1, -1
4162 Xdoor_8, TRUE, FALSE,
4163 EL_EMC_GATE_8, -1, -1
4166 Xkey_1, TRUE, FALSE,
4170 Xkey_2, TRUE, FALSE,
4174 Xkey_3, TRUE, FALSE,
4178 Xkey_4, TRUE, FALSE,
4182 Xkey_5, TRUE, FALSE,
4183 EL_EMC_KEY_5, -1, -1
4186 Xkey_6, TRUE, FALSE,
4187 EL_EMC_KEY_6, -1, -1
4190 Xkey_7, TRUE, FALSE,
4191 EL_EMC_KEY_7, -1, -1
4194 Xkey_8, TRUE, FALSE,
4195 EL_EMC_KEY_8, -1, -1
4198 Xwind_n, TRUE, FALSE,
4199 EL_BALLOON_SWITCH_UP, -1, -1
4202 Xwind_e, TRUE, FALSE,
4203 EL_BALLOON_SWITCH_RIGHT, -1, -1
4206 Xwind_s, TRUE, FALSE,
4207 EL_BALLOON_SWITCH_DOWN, -1, -1
4210 Xwind_w, TRUE, FALSE,
4211 EL_BALLOON_SWITCH_LEFT, -1, -1
4214 Xwind_nesw, TRUE, FALSE,
4215 EL_BALLOON_SWITCH_ANY, -1, -1
4218 Xwind_stop, TRUE, FALSE,
4219 EL_BALLOON_SWITCH_NONE, -1, -1
4223 EL_EXIT_CLOSED, -1, -1
4226 Xexit_1, TRUE, FALSE,
4227 EL_EXIT_OPEN, -1, -1
4230 Xexit_2, FALSE, FALSE,
4231 EL_EXIT_OPEN, -1, -1
4234 Xexit_3, FALSE, FALSE,
4235 EL_EXIT_OPEN, -1, -1
4238 Xdynamite, TRUE, FALSE,
4239 EL_EM_DYNAMITE, -1, -1
4242 Ydynamite_eat, FALSE, FALSE,
4243 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4246 Xdynamite_1, TRUE, FALSE,
4247 EL_EM_DYNAMITE_ACTIVE, -1, -1
4250 Xdynamite_2, FALSE, FALSE,
4251 EL_EM_DYNAMITE_ACTIVE, -1, -1
4254 Xdynamite_3, FALSE, FALSE,
4255 EL_EM_DYNAMITE_ACTIVE, -1, -1
4258 Xdynamite_4, FALSE, FALSE,
4259 EL_EM_DYNAMITE_ACTIVE, -1, -1
4262 Xbumper, TRUE, FALSE,
4263 EL_EMC_SPRING_BUMPER, -1, -1
4266 XbumperB, FALSE, FALSE,
4267 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4270 Xwheel, TRUE, FALSE,
4271 EL_ROBOT_WHEEL, -1, -1
4274 XwheelB, FALSE, FALSE,
4275 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4278 Xswitch, TRUE, FALSE,
4279 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4282 XswitchB, FALSE, FALSE,
4283 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4287 EL_QUICKSAND_EMPTY, -1, -1
4290 Xsand_stone, TRUE, FALSE,
4291 EL_QUICKSAND_FULL, -1, -1
4294 Xsand_stonein_1, FALSE, TRUE,
4295 EL_ROCK, ACTION_FILLING, -1
4298 Xsand_stonein_2, FALSE, TRUE,
4299 EL_ROCK, ACTION_FILLING, -1
4302 Xsand_stonein_3, FALSE, TRUE,
4303 EL_ROCK, ACTION_FILLING, -1
4306 Xsand_stonein_4, FALSE, TRUE,
4307 EL_ROCK, ACTION_FILLING, -1
4310 Xsand_stonesand_1, FALSE, FALSE,
4311 EL_QUICKSAND_FULL, -1, -1
4314 Xsand_stonesand_2, FALSE, FALSE,
4315 EL_QUICKSAND_FULL, -1, -1
4318 Xsand_stonesand_3, FALSE, FALSE,
4319 EL_QUICKSAND_FULL, -1, -1
4322 Xsand_stonesand_4, FALSE, FALSE,
4323 EL_QUICKSAND_FULL, -1, -1
4326 Xsand_stoneout_1, FALSE, FALSE,
4327 EL_ROCK, ACTION_EMPTYING, -1
4330 Xsand_stoneout_2, FALSE, FALSE,
4331 EL_ROCK, ACTION_EMPTYING, -1
4334 Xsand_sandstone_1, FALSE, FALSE,
4335 EL_QUICKSAND_FULL, -1, -1
4338 Xsand_sandstone_2, FALSE, FALSE,
4339 EL_QUICKSAND_FULL, -1, -1
4342 Xsand_sandstone_3, FALSE, FALSE,
4343 EL_QUICKSAND_FULL, -1, -1
4346 Xsand_sandstone_4, FALSE, FALSE,
4347 EL_QUICKSAND_FULL, -1, -1
4350 Xplant, TRUE, FALSE,
4351 EL_EMC_PLANT, -1, -1
4354 Yplant, FALSE, FALSE,
4355 EL_EMC_PLANT, -1, -1
4358 Xlenses, TRUE, FALSE,
4359 EL_EMC_LENSES, -1, -1
4362 Xmagnify, TRUE, FALSE,
4363 EL_EMC_MAGNIFIER, -1, -1
4366 Xdripper, TRUE, FALSE,
4367 EL_EMC_DRIPPER, -1, -1
4370 XdripperB, FALSE, FALSE,
4371 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4374 Xfake_blank, TRUE, FALSE,
4375 EL_INVISIBLE_WALL, -1, -1
4378 Xfake_blankB, FALSE, FALSE,
4379 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4382 Xfake_grass, TRUE, FALSE,
4383 EL_EMC_FAKE_GRASS, -1, -1
4386 Xfake_grassB, FALSE, FALSE,
4387 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4390 Xfake_door_1, TRUE, FALSE,
4391 EL_EM_GATE_1_GRAY, -1, -1
4394 Xfake_door_2, TRUE, FALSE,
4395 EL_EM_GATE_2_GRAY, -1, -1
4398 Xfake_door_3, TRUE, FALSE,
4399 EL_EM_GATE_3_GRAY, -1, -1
4402 Xfake_door_4, TRUE, FALSE,
4403 EL_EM_GATE_4_GRAY, -1, -1
4406 Xfake_door_5, TRUE, FALSE,
4407 EL_EMC_GATE_5_GRAY, -1, -1
4410 Xfake_door_6, TRUE, FALSE,
4411 EL_EMC_GATE_6_GRAY, -1, -1
4414 Xfake_door_7, TRUE, FALSE,
4415 EL_EMC_GATE_7_GRAY, -1, -1
4418 Xfake_door_8, TRUE, FALSE,
4419 EL_EMC_GATE_8_GRAY, -1, -1
4422 Xfake_acid_1, TRUE, FALSE,
4423 EL_EMC_FAKE_ACID, -1, -1
4426 Xfake_acid_2, FALSE, FALSE,
4427 EL_EMC_FAKE_ACID, -1, -1
4430 Xfake_acid_3, FALSE, FALSE,
4431 EL_EMC_FAKE_ACID, -1, -1
4434 Xfake_acid_4, FALSE, FALSE,
4435 EL_EMC_FAKE_ACID, -1, -1
4438 Xfake_acid_5, FALSE, FALSE,
4439 EL_EMC_FAKE_ACID, -1, -1
4442 Xfake_acid_6, FALSE, FALSE,
4443 EL_EMC_FAKE_ACID, -1, -1
4446 Xfake_acid_7, FALSE, FALSE,
4447 EL_EMC_FAKE_ACID, -1, -1
4450 Xfake_acid_8, FALSE, FALSE,
4451 EL_EMC_FAKE_ACID, -1, -1
4454 Xsteel_1, TRUE, FALSE,
4455 EL_STEELWALL, -1, -1
4458 Xsteel_2, TRUE, FALSE,
4459 EL_EMC_STEELWALL_2, -1, -1
4462 Xsteel_3, TRUE, FALSE,
4463 EL_EMC_STEELWALL_3, -1, -1
4466 Xsteel_4, TRUE, FALSE,
4467 EL_EMC_STEELWALL_4, -1, -1
4470 Xwall_1, TRUE, FALSE,
4474 Xwall_2, TRUE, FALSE,
4475 EL_EMC_WALL_14, -1, -1
4478 Xwall_3, TRUE, FALSE,
4479 EL_EMC_WALL_15, -1, -1
4482 Xwall_4, TRUE, FALSE,
4483 EL_EMC_WALL_16, -1, -1
4486 Xround_wall_1, TRUE, FALSE,
4487 EL_WALL_SLIPPERY, -1, -1
4490 Xround_wall_2, TRUE, FALSE,
4491 EL_EMC_WALL_SLIPPERY_2, -1, -1
4494 Xround_wall_3, TRUE, FALSE,
4495 EL_EMC_WALL_SLIPPERY_3, -1, -1
4498 Xround_wall_4, TRUE, FALSE,
4499 EL_EMC_WALL_SLIPPERY_4, -1, -1
4502 Xdecor_1, TRUE, FALSE,
4503 EL_EMC_WALL_8, -1, -1
4506 Xdecor_2, TRUE, FALSE,
4507 EL_EMC_WALL_6, -1, -1
4510 Xdecor_3, TRUE, FALSE,
4511 EL_EMC_WALL_4, -1, -1
4514 Xdecor_4, TRUE, FALSE,
4515 EL_EMC_WALL_7, -1, -1
4518 Xdecor_5, TRUE, FALSE,
4519 EL_EMC_WALL_5, -1, -1
4522 Xdecor_6, TRUE, FALSE,
4523 EL_EMC_WALL_9, -1, -1
4526 Xdecor_7, TRUE, FALSE,
4527 EL_EMC_WALL_10, -1, -1
4530 Xdecor_8, TRUE, FALSE,
4531 EL_EMC_WALL_1, -1, -1
4534 Xdecor_9, TRUE, FALSE,
4535 EL_EMC_WALL_2, -1, -1
4538 Xdecor_10, TRUE, FALSE,
4539 EL_EMC_WALL_3, -1, -1
4542 Xdecor_11, TRUE, FALSE,
4543 EL_EMC_WALL_11, -1, -1
4546 Xdecor_12, TRUE, FALSE,
4547 EL_EMC_WALL_12, -1, -1
4550 Xalpha_0, TRUE, FALSE,
4551 EL_CHAR('0'), -1, -1
4554 Xalpha_1, TRUE, FALSE,
4555 EL_CHAR('1'), -1, -1
4558 Xalpha_2, TRUE, FALSE,
4559 EL_CHAR('2'), -1, -1
4562 Xalpha_3, TRUE, FALSE,
4563 EL_CHAR('3'), -1, -1
4566 Xalpha_4, TRUE, FALSE,
4567 EL_CHAR('4'), -1, -1
4570 Xalpha_5, TRUE, FALSE,
4571 EL_CHAR('5'), -1, -1
4574 Xalpha_6, TRUE, FALSE,
4575 EL_CHAR('6'), -1, -1
4578 Xalpha_7, TRUE, FALSE,
4579 EL_CHAR('7'), -1, -1
4582 Xalpha_8, TRUE, FALSE,
4583 EL_CHAR('8'), -1, -1
4586 Xalpha_9, TRUE, FALSE,
4587 EL_CHAR('9'), -1, -1
4590 Xalpha_excla, TRUE, FALSE,
4591 EL_CHAR('!'), -1, -1
4594 Xalpha_quote, TRUE, FALSE,
4595 EL_CHAR('"'), -1, -1
4598 Xalpha_comma, TRUE, FALSE,
4599 EL_CHAR(','), -1, -1
4602 Xalpha_minus, TRUE, FALSE,
4603 EL_CHAR('-'), -1, -1
4606 Xalpha_perio, TRUE, FALSE,
4607 EL_CHAR('.'), -1, -1
4610 Xalpha_colon, TRUE, FALSE,
4611 EL_CHAR(':'), -1, -1
4614 Xalpha_quest, TRUE, FALSE,
4615 EL_CHAR('?'), -1, -1
4618 Xalpha_a, TRUE, FALSE,
4619 EL_CHAR('A'), -1, -1
4622 Xalpha_b, TRUE, FALSE,
4623 EL_CHAR('B'), -1, -1
4626 Xalpha_c, TRUE, FALSE,
4627 EL_CHAR('C'), -1, -1
4630 Xalpha_d, TRUE, FALSE,
4631 EL_CHAR('D'), -1, -1
4634 Xalpha_e, TRUE, FALSE,
4635 EL_CHAR('E'), -1, -1
4638 Xalpha_f, TRUE, FALSE,
4639 EL_CHAR('F'), -1, -1
4642 Xalpha_g, TRUE, FALSE,
4643 EL_CHAR('G'), -1, -1
4646 Xalpha_h, TRUE, FALSE,
4647 EL_CHAR('H'), -1, -1
4650 Xalpha_i, TRUE, FALSE,
4651 EL_CHAR('I'), -1, -1
4654 Xalpha_j, TRUE, FALSE,
4655 EL_CHAR('J'), -1, -1
4658 Xalpha_k, TRUE, FALSE,
4659 EL_CHAR('K'), -1, -1
4662 Xalpha_l, TRUE, FALSE,
4663 EL_CHAR('L'), -1, -1
4666 Xalpha_m, TRUE, FALSE,
4667 EL_CHAR('M'), -1, -1
4670 Xalpha_n, TRUE, FALSE,
4671 EL_CHAR('N'), -1, -1
4674 Xalpha_o, TRUE, FALSE,
4675 EL_CHAR('O'), -1, -1
4678 Xalpha_p, TRUE, FALSE,
4679 EL_CHAR('P'), -1, -1
4682 Xalpha_q, TRUE, FALSE,
4683 EL_CHAR('Q'), -1, -1
4686 Xalpha_r, TRUE, FALSE,
4687 EL_CHAR('R'), -1, -1
4690 Xalpha_s, TRUE, FALSE,
4691 EL_CHAR('S'), -1, -1
4694 Xalpha_t, TRUE, FALSE,
4695 EL_CHAR('T'), -1, -1
4698 Xalpha_u, TRUE, FALSE,
4699 EL_CHAR('U'), -1, -1
4702 Xalpha_v, TRUE, FALSE,
4703 EL_CHAR('V'), -1, -1
4706 Xalpha_w, TRUE, FALSE,
4707 EL_CHAR('W'), -1, -1
4710 Xalpha_x, TRUE, FALSE,
4711 EL_CHAR('X'), -1, -1
4714 Xalpha_y, TRUE, FALSE,
4715 EL_CHAR('Y'), -1, -1
4718 Xalpha_z, TRUE, FALSE,
4719 EL_CHAR('Z'), -1, -1
4722 Xalpha_arrow_e, TRUE, FALSE,
4723 EL_CHAR('>'), -1, -1
4726 Xalpha_arrow_w, TRUE, FALSE,
4727 EL_CHAR('<'), -1, -1
4730 Xalpha_copyr, TRUE, FALSE,
4731 EL_CHAR('©'), -1, -1
4735 Xboom_bug, FALSE, FALSE,
4736 EL_BUG, ACTION_EXPLODING, -1
4739 Xboom_bomb, FALSE, FALSE,
4740 EL_BOMB, ACTION_EXPLODING, -1
4743 Xboom_android, FALSE, FALSE,
4744 EL_EMC_ANDROID, ACTION_OTHER, -1
4747 Xboom_1, FALSE, FALSE,
4748 EL_DEFAULT, ACTION_EXPLODING, -1
4751 Xboom_2, FALSE, FALSE,
4752 EL_DEFAULT, ACTION_EXPLODING, -1
4755 Znormal, FALSE, FALSE,
4759 Zdynamite, FALSE, FALSE,
4763 Zplayer, FALSE, FALSE,
4767 ZBORDER, FALSE, FALSE,
4777 static struct Mapping_EM_to_RND_player
4786 em_player_mapping_list[] =
4790 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4794 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4798 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4802 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4806 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4810 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4814 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4818 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4822 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4826 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4830 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4834 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4838 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4842 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4846 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4850 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4854 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4858 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4862 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4866 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4870 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4874 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4878 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4882 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4886 EL_PLAYER_1, ACTION_DEFAULT, -1,
4890 EL_PLAYER_2, ACTION_DEFAULT, -1,
4894 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4898 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4902 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4906 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4910 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4914 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4918 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4922 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4926 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4930 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4934 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4938 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4942 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4946 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4950 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4954 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4958 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4962 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
4966 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
4970 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
4974 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
4978 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
4982 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
4986 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
4990 EL_PLAYER_3, ACTION_DEFAULT, -1,
4994 EL_PLAYER_4, ACTION_DEFAULT, -1,
5003 int map_element_RND_to_EM(int element_rnd)
5005 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5006 static boolean mapping_initialized = FALSE;
5008 if (!mapping_initialized)
5012 /* return "Xalpha_quest" for all undefined elements in mapping array */
5013 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5014 mapping_RND_to_EM[i] = Xalpha_quest;
5016 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5017 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5018 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5019 em_object_mapping_list[i].element_em;
5021 mapping_initialized = TRUE;
5024 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5025 return mapping_RND_to_EM[element_rnd];
5027 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5032 int map_element_EM_to_RND(int element_em)
5034 static unsigned short mapping_EM_to_RND[TILE_MAX];
5035 static boolean mapping_initialized = FALSE;
5037 if (!mapping_initialized)
5041 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5042 for (i = 0; i < TILE_MAX; i++)
5043 mapping_EM_to_RND[i] = EL_UNKNOWN;
5045 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5046 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5047 em_object_mapping_list[i].element_rnd;
5049 mapping_initialized = TRUE;
5052 if (element_em >= 0 && element_em < TILE_MAX)
5053 return mapping_EM_to_RND[element_em];
5055 Error(ERR_WARN, "invalid EM level element %d", element_em);
5060 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5062 struct LevelInfo_EM *level_em = level->native_em_level;
5063 struct LEVEL *lev = level_em->lev;
5066 for (i = 0; i < TILE_MAX; i++)
5067 lev->android_array[i] = Xblank;
5069 for (i = 0; i < level->num_android_clone_elements; i++)
5071 int element_rnd = level->android_clone_element[i];
5072 int element_em = map_element_RND_to_EM(element_rnd);
5074 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5075 if (em_object_mapping_list[j].element_rnd == element_rnd)
5076 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5080 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5082 struct LevelInfo_EM *level_em = level->native_em_level;
5083 struct LEVEL *lev = level_em->lev;
5086 level->num_android_clone_elements = 0;
5088 for (i = 0; i < TILE_MAX; i++)
5090 int element_em = lev->android_array[i];
5092 boolean element_found = FALSE;
5094 if (element_em == Xblank)
5097 element_rnd = map_element_EM_to_RND(element_em);
5099 for (j = 0; j < level->num_android_clone_elements; j++)
5100 if (level->android_clone_element[j] == element_rnd)
5101 element_found = TRUE;
5105 level->android_clone_element[level->num_android_clone_elements++] =
5108 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5113 if (level->num_android_clone_elements == 0)
5115 level->num_android_clone_elements = 1;
5116 level->android_clone_element[0] = EL_EMPTY;
5120 int map_direction_RND_to_EM(int direction)
5122 return (direction == MV_UP ? 0 :
5123 direction == MV_RIGHT ? 1 :
5124 direction == MV_DOWN ? 2 :
5125 direction == MV_LEFT ? 3 :
5129 int map_direction_EM_to_RND(int direction)
5131 return (direction == 0 ? MV_UP :
5132 direction == 1 ? MV_RIGHT :
5133 direction == 2 ? MV_DOWN :
5134 direction == 3 ? MV_LEFT :
5138 int get_next_element(int element)
5142 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5143 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5144 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5145 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5146 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5147 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5148 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5150 default: return element;
5155 int el_act_dir2img(int element, int action, int direction)
5157 element = GFX_ELEMENT(element);
5159 if (direction == MV_NONE)
5160 return element_info[element].graphic[action];
5162 direction = MV_DIR_TO_BIT(direction);
5164 return element_info[element].direction_graphic[action][direction];
5167 int el_act_dir2img(int element, int action, int direction)
5169 element = GFX_ELEMENT(element);
5170 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5172 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5173 return element_info[element].direction_graphic[action][direction];
5178 static int el_act_dir2crm(int element, int action, int direction)
5180 element = GFX_ELEMENT(element);
5182 if (direction == MV_NONE)
5183 return element_info[element].crumbled[action];
5185 direction = MV_DIR_TO_BIT(direction);
5187 return element_info[element].direction_crumbled[action][direction];
5190 static int el_act_dir2crm(int element, int action, int direction)
5192 element = GFX_ELEMENT(element);
5193 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5195 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5196 return element_info[element].direction_crumbled[action][direction];
5200 int el_act2img(int element, int action)
5202 element = GFX_ELEMENT(element);
5204 return element_info[element].graphic[action];
5207 int el_act2crm(int element, int action)
5209 element = GFX_ELEMENT(element);
5211 return element_info[element].crumbled[action];
5214 int el_dir2img(int element, int direction)
5216 element = GFX_ELEMENT(element);
5218 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5221 int el2baseimg(int element)
5223 return element_info[element].graphic[ACTION_DEFAULT];
5226 int el2img(int element)
5228 element = GFX_ELEMENT(element);
5230 return element_info[element].graphic[ACTION_DEFAULT];
5233 int el2edimg(int element)
5235 element = GFX_ELEMENT(element);
5237 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5240 int el2preimg(int element)
5242 element = GFX_ELEMENT(element);
5244 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5247 int font2baseimg(int font_nr)
5249 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5253 void setCenteredPlayerNr_EM(int centered_player_nr)
5255 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5258 int getCenteredPlayerNr_EM()
5261 if (game.centered_player_nr_next >= 0 &&
5262 !native_em_level.ply[game.centered_player_nr_next]->alive)
5263 game.centered_player_nr_next = game.centered_player_nr;
5266 if (game.centered_player_nr != game.centered_player_nr_next)
5267 game.centered_player_nr = game.centered_player_nr_next;
5269 return game.centered_player_nr;
5272 void setSetCenteredPlayer_EM(boolean set_centered_player)
5274 game.set_centered_player = set_centered_player;
5277 boolean getSetCenteredPlayer_EM()
5279 return game.set_centered_player;
5283 int getNumActivePlayers_EM()
5285 int num_players = 0;
5291 for (i = 0; i < MAX_PLAYERS; i++)
5292 if (tape.player_participates[i])
5299 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5301 int game_frame_delay_value;
5303 game_frame_delay_value =
5304 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5305 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5308 if (tape.playing && tape.warp_forward && !tape.pausing)
5309 game_frame_delay_value = 0;
5311 return game_frame_delay_value;
5315 unsigned int InitRND(long seed)
5317 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5318 return InitEngineRND_EM(seed);
5320 return InitEngineRND(seed);
5323 void InitGraphicInfo_EM(void)
5325 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5326 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5330 int num_em_gfx_errors = 0;
5332 if (graphic_info_em_object[0][0].bitmap == NULL)
5334 /* EM graphics not yet initialized in em_open_all() */
5339 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5342 /* always start with reliable default values */
5343 for (i = 0; i < TILE_MAX; i++)
5345 object_mapping[i].element_rnd = EL_UNKNOWN;
5346 object_mapping[i].is_backside = FALSE;
5347 object_mapping[i].action = ACTION_DEFAULT;
5348 object_mapping[i].direction = MV_NONE;
5351 /* always start with reliable default values */
5352 for (p = 0; p < MAX_PLAYERS; p++)
5354 for (i = 0; i < SPR_MAX; i++)
5356 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5357 player_mapping[p][i].action = ACTION_DEFAULT;
5358 player_mapping[p][i].direction = MV_NONE;
5362 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5364 int e = em_object_mapping_list[i].element_em;
5366 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5367 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5369 if (em_object_mapping_list[i].action != -1)
5370 object_mapping[e].action = em_object_mapping_list[i].action;
5372 if (em_object_mapping_list[i].direction != -1)
5373 object_mapping[e].direction =
5374 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5377 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5379 int a = em_player_mapping_list[i].action_em;
5380 int p = em_player_mapping_list[i].player_nr;
5382 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5384 if (em_player_mapping_list[i].action != -1)
5385 player_mapping[p][a].action = em_player_mapping_list[i].action;
5387 if (em_player_mapping_list[i].direction != -1)
5388 player_mapping[p][a].direction =
5389 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5392 for (i = 0; i < TILE_MAX; i++)
5394 int element = object_mapping[i].element_rnd;
5395 int action = object_mapping[i].action;
5396 int direction = object_mapping[i].direction;
5397 boolean is_backside = object_mapping[i].is_backside;
5398 boolean action_removing = (action == ACTION_DIGGING ||
5399 action == ACTION_SNAPPING ||
5400 action == ACTION_COLLECTING);
5401 boolean action_exploding = ((action == ACTION_EXPLODING ||
5402 action == ACTION_SMASHED_BY_ROCK ||
5403 action == ACTION_SMASHED_BY_SPRING) &&
5404 element != EL_DIAMOND);
5405 boolean action_active = (action == ACTION_ACTIVE);
5406 boolean action_other = (action == ACTION_OTHER);
5408 for (j = 0; j < 8; j++)
5410 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5411 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5413 i == Xdrip_stretch ? element :
5414 i == Xdrip_stretchB ? element :
5415 i == Ydrip_s1 ? element :
5416 i == Ydrip_s1B ? element :
5417 i == Xball_1B ? element :
5418 i == Xball_2 ? element :
5419 i == Xball_2B ? element :
5420 i == Yball_eat ? element :
5421 i == Ykey_1_eat ? element :
5422 i == Ykey_2_eat ? element :
5423 i == Ykey_3_eat ? element :
5424 i == Ykey_4_eat ? element :
5425 i == Ykey_5_eat ? element :
5426 i == Ykey_6_eat ? element :
5427 i == Ykey_7_eat ? element :
5428 i == Ykey_8_eat ? element :
5429 i == Ylenses_eat ? element :
5430 i == Ymagnify_eat ? element :
5431 i == Ygrass_eat ? element :
5432 i == Ydirt_eat ? element :
5433 i == Yemerald_stone ? EL_EMERALD :
5434 i == Ydiamond_stone ? EL_ROCK :
5435 i == Xsand_stonein_1 ? element :
5436 i == Xsand_stonein_2 ? element :
5437 i == Xsand_stonein_3 ? element :
5438 i == Xsand_stonein_4 ? element :
5439 is_backside ? EL_EMPTY :
5440 action_removing ? EL_EMPTY :
5442 int effective_action = (j < 7 ? action :
5443 i == Xdrip_stretch ? action :
5444 i == Xdrip_stretchB ? action :
5445 i == Ydrip_s1 ? action :
5446 i == Ydrip_s1B ? action :
5447 i == Xball_1B ? action :
5448 i == Xball_2 ? action :
5449 i == Xball_2B ? action :
5450 i == Yball_eat ? action :
5451 i == Ykey_1_eat ? action :
5452 i == Ykey_2_eat ? action :
5453 i == Ykey_3_eat ? action :
5454 i == Ykey_4_eat ? action :
5455 i == Ykey_5_eat ? action :
5456 i == Ykey_6_eat ? action :
5457 i == Ykey_7_eat ? action :
5458 i == Ykey_8_eat ? action :
5459 i == Ylenses_eat ? action :
5460 i == Ymagnify_eat ? action :
5461 i == Ygrass_eat ? action :
5462 i == Ydirt_eat ? action :
5463 i == Xsand_stonein_1 ? action :
5464 i == Xsand_stonein_2 ? action :
5465 i == Xsand_stonein_3 ? action :
5466 i == Xsand_stonein_4 ? action :
5467 i == Xsand_stoneout_1 ? action :
5468 i == Xsand_stoneout_2 ? action :
5469 i == Xboom_android ? ACTION_EXPLODING :
5470 action_exploding ? ACTION_EXPLODING :
5471 action_active ? action :
5472 action_other ? action :
5474 int graphic = (el_act_dir2img(effective_element, effective_action,
5476 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5478 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5479 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5480 boolean has_action_graphics = (graphic != base_graphic);
5481 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5482 struct GraphicInfo *g = &graphic_info[graphic];
5483 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5486 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5487 boolean special_animation = (action != ACTION_DEFAULT &&
5488 g->anim_frames == 3 &&
5489 g->anim_delay == 2 &&
5490 g->anim_mode & ANIM_LINEAR);
5491 int sync_frame = (i == Xdrip_stretch ? 7 :
5492 i == Xdrip_stretchB ? 7 :
5493 i == Ydrip_s2 ? j + 8 :
5494 i == Ydrip_s2B ? j + 8 :
5503 i == Xfake_acid_1 ? 0 :
5504 i == Xfake_acid_2 ? 10 :
5505 i == Xfake_acid_3 ? 20 :
5506 i == Xfake_acid_4 ? 30 :
5507 i == Xfake_acid_5 ? 40 :
5508 i == Xfake_acid_6 ? 50 :
5509 i == Xfake_acid_7 ? 60 :
5510 i == Xfake_acid_8 ? 70 :
5512 i == Xball_2B ? j + 8 :
5513 i == Yball_eat ? j + 1 :
5514 i == Ykey_1_eat ? j + 1 :
5515 i == Ykey_2_eat ? j + 1 :
5516 i == Ykey_3_eat ? j + 1 :
5517 i == Ykey_4_eat ? j + 1 :
5518 i == Ykey_5_eat ? j + 1 :
5519 i == Ykey_6_eat ? j + 1 :
5520 i == Ykey_7_eat ? j + 1 :
5521 i == Ykey_8_eat ? j + 1 :
5522 i == Ylenses_eat ? j + 1 :
5523 i == Ymagnify_eat ? j + 1 :
5524 i == Ygrass_eat ? j + 1 :
5525 i == Ydirt_eat ? j + 1 :
5526 i == Xamoeba_1 ? 0 :
5527 i == Xamoeba_2 ? 1 :
5528 i == Xamoeba_3 ? 2 :
5529 i == Xamoeba_4 ? 3 :
5530 i == Xamoeba_5 ? 0 :
5531 i == Xamoeba_6 ? 1 :
5532 i == Xamoeba_7 ? 2 :
5533 i == Xamoeba_8 ? 3 :
5534 i == Xexit_2 ? j + 8 :
5535 i == Xexit_3 ? j + 16 :
5536 i == Xdynamite_1 ? 0 :
5537 i == Xdynamite_2 ? 8 :
5538 i == Xdynamite_3 ? 16 :
5539 i == Xdynamite_4 ? 24 :
5540 i == Xsand_stonein_1 ? j + 1 :
5541 i == Xsand_stonein_2 ? j + 9 :
5542 i == Xsand_stonein_3 ? j + 17 :
5543 i == Xsand_stonein_4 ? j + 25 :
5544 i == Xsand_stoneout_1 && j == 0 ? 0 :
5545 i == Xsand_stoneout_1 && j == 1 ? 0 :
5546 i == Xsand_stoneout_1 && j == 2 ? 1 :
5547 i == Xsand_stoneout_1 && j == 3 ? 2 :
5548 i == Xsand_stoneout_1 && j == 4 ? 2 :
5549 i == Xsand_stoneout_1 && j == 5 ? 3 :
5550 i == Xsand_stoneout_1 && j == 6 ? 4 :
5551 i == Xsand_stoneout_1 && j == 7 ? 4 :
5552 i == Xsand_stoneout_2 && j == 0 ? 5 :
5553 i == Xsand_stoneout_2 && j == 1 ? 6 :
5554 i == Xsand_stoneout_2 && j == 2 ? 7 :
5555 i == Xsand_stoneout_2 && j == 3 ? 8 :
5556 i == Xsand_stoneout_2 && j == 4 ? 9 :
5557 i == Xsand_stoneout_2 && j == 5 ? 11 :
5558 i == Xsand_stoneout_2 && j == 6 ? 13 :
5559 i == Xsand_stoneout_2 && j == 7 ? 15 :
5560 i == Xboom_bug && j == 1 ? 2 :
5561 i == Xboom_bug && j == 2 ? 2 :
5562 i == Xboom_bug && j == 3 ? 4 :
5563 i == Xboom_bug && j == 4 ? 4 :
5564 i == Xboom_bug && j == 5 ? 2 :
5565 i == Xboom_bug && j == 6 ? 2 :
5566 i == Xboom_bug && j == 7 ? 0 :
5567 i == Xboom_bomb && j == 1 ? 2 :
5568 i == Xboom_bomb && j == 2 ? 2 :
5569 i == Xboom_bomb && j == 3 ? 4 :
5570 i == Xboom_bomb && j == 4 ? 4 :
5571 i == Xboom_bomb && j == 5 ? 2 :
5572 i == Xboom_bomb && j == 6 ? 2 :
5573 i == Xboom_bomb && j == 7 ? 0 :
5574 i == Xboom_android && j == 7 ? 6 :
5575 i == Xboom_1 && j == 1 ? 2 :
5576 i == Xboom_1 && j == 2 ? 2 :
5577 i == Xboom_1 && j == 3 ? 4 :
5578 i == Xboom_1 && j == 4 ? 4 :
5579 i == Xboom_1 && j == 5 ? 6 :
5580 i == Xboom_1 && j == 6 ? 6 :
5581 i == Xboom_1 && j == 7 ? 8 :
5582 i == Xboom_2 && j == 0 ? 8 :
5583 i == Xboom_2 && j == 1 ? 8 :
5584 i == Xboom_2 && j == 2 ? 10 :
5585 i == Xboom_2 && j == 3 ? 10 :
5586 i == Xboom_2 && j == 4 ? 10 :
5587 i == Xboom_2 && j == 5 ? 12 :
5588 i == Xboom_2 && j == 6 ? 12 :
5589 i == Xboom_2 && j == 7 ? 12 :
5590 special_animation && j == 4 ? 3 :
5591 effective_action != action ? 0 :
5595 Bitmap *debug_bitmap = g_em->bitmap;
5596 int debug_src_x = g_em->src_x;
5597 int debug_src_y = g_em->src_y;
5600 int frame = getAnimationFrame(g->anim_frames,
5603 g->anim_start_frame,
5606 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5607 g->double_movement && is_backside);
5609 g_em->bitmap = src_bitmap;
5610 g_em->src_x = src_x;
5611 g_em->src_y = src_y;
5612 g_em->src_offset_x = 0;
5613 g_em->src_offset_y = 0;
5614 g_em->dst_offset_x = 0;
5615 g_em->dst_offset_y = 0;
5616 g_em->width = TILEX;
5617 g_em->height = TILEY;
5619 g_em->crumbled_bitmap = NULL;
5620 g_em->crumbled_src_x = 0;
5621 g_em->crumbled_src_y = 0;
5622 g_em->crumbled_border_size = 0;
5624 g_em->has_crumbled_graphics = FALSE;
5625 g_em->preserve_background = FALSE;
5628 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5629 printf("::: empty crumbled: %d [%s], %d, %d\n",
5630 effective_element, element_info[effective_element].token_name,
5631 effective_action, direction);
5634 /* if element can be crumbled, but certain action graphics are just empty
5635 space (like snapping sand with the original R'n'D graphics), do not
5636 treat these empty space graphics as crumbled graphics in EMC engine */
5637 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5639 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5641 g_em->has_crumbled_graphics = TRUE;
5642 g_em->crumbled_bitmap = src_bitmap;
5643 g_em->crumbled_src_x = src_x;
5644 g_em->crumbled_src_y = src_y;
5645 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5649 if (element == EL_ROCK &&
5650 effective_action == ACTION_FILLING)
5651 printf("::: has_action_graphics == %d\n", has_action_graphics);
5654 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5655 effective_action == ACTION_MOVING ||
5656 effective_action == ACTION_PUSHING ||
5657 effective_action == ACTION_EATING)) ||
5658 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5659 effective_action == ACTION_EMPTYING)))
5662 (effective_action == ACTION_FALLING ||
5663 effective_action == ACTION_FILLING ||
5664 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5665 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5666 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5667 int num_steps = (i == Ydrip_s1 ? 16 :
5668 i == Ydrip_s1B ? 16 :
5669 i == Ydrip_s2 ? 16 :
5670 i == Ydrip_s2B ? 16 :
5671 i == Xsand_stonein_1 ? 32 :
5672 i == Xsand_stonein_2 ? 32 :
5673 i == Xsand_stonein_3 ? 32 :
5674 i == Xsand_stonein_4 ? 32 :
5675 i == Xsand_stoneout_1 ? 16 :
5676 i == Xsand_stoneout_2 ? 16 : 8);
5677 int cx = ABS(dx) * (TILEX / num_steps);
5678 int cy = ABS(dy) * (TILEY / num_steps);
5679 int step_frame = (i == Ydrip_s2 ? j + 8 :
5680 i == Ydrip_s2B ? j + 8 :
5681 i == Xsand_stonein_2 ? j + 8 :
5682 i == Xsand_stonein_3 ? j + 16 :
5683 i == Xsand_stonein_4 ? j + 24 :
5684 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5685 int step = (is_backside ? step_frame : num_steps - step_frame);
5687 if (is_backside) /* tile where movement starts */
5689 if (dx < 0 || dy < 0)
5691 g_em->src_offset_x = cx * step;
5692 g_em->src_offset_y = cy * step;
5696 g_em->dst_offset_x = cx * step;
5697 g_em->dst_offset_y = cy * step;
5700 else /* tile where movement ends */
5702 if (dx < 0 || dy < 0)
5704 g_em->dst_offset_x = cx * step;
5705 g_em->dst_offset_y = cy * step;
5709 g_em->src_offset_x = cx * step;
5710 g_em->src_offset_y = cy * step;
5714 g_em->width = TILEX - cx * step;
5715 g_em->height = TILEY - cy * step;
5719 /* create unique graphic identifier to decide if tile must be redrawn */
5720 /* bit 31 - 16 (16 bit): EM style graphic
5721 bit 15 - 12 ( 4 bit): EM style frame
5722 bit 11 - 6 ( 6 bit): graphic width
5723 bit 5 - 0 ( 6 bit): graphic height */
5724 g_em->unique_identifier =
5725 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5727 /* create unique graphic identifier to decide if tile must be redrawn */
5728 /* bit 31 - 16 (16 bit): EM style element
5729 bit 15 - 12 ( 4 bit): EM style frame
5730 bit 11 - 6 ( 6 bit): graphic width
5731 bit 5 - 0 ( 6 bit): graphic height */
5732 g_em->unique_identifier =
5733 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5737 if (effective_element == EL_ROCK)
5738 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5739 effective_action, j, graphic, frame, g_em->unique_identifier);
5745 /* skip check for EMC elements not contained in original EMC artwork */
5746 if (element == EL_EMC_FAKE_ACID)
5750 if (g_em->bitmap != debug_bitmap ||
5751 g_em->src_x != debug_src_x ||
5752 g_em->src_y != debug_src_y ||
5753 g_em->src_offset_x != 0 ||
5754 g_em->src_offset_y != 0 ||
5755 g_em->dst_offset_x != 0 ||
5756 g_em->dst_offset_y != 0 ||
5757 g_em->width != TILEX ||
5758 g_em->height != TILEY)
5760 static int last_i = -1;
5768 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5769 i, element, element_info[element].token_name,
5770 element_action_info[effective_action].suffix, direction);
5772 if (element != effective_element)
5773 printf(" [%d ('%s')]",
5775 element_info[effective_element].token_name);
5779 if (g_em->bitmap != debug_bitmap)
5780 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5781 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5783 if (g_em->src_x != debug_src_x ||
5784 g_em->src_y != debug_src_y)
5785 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5786 j, (is_backside ? 'B' : 'F'),
5787 g_em->src_x, g_em->src_y,
5788 g_em->src_x / 32, g_em->src_y / 32,
5789 debug_src_x, debug_src_y,
5790 debug_src_x / 32, debug_src_y / 32);
5792 if (g_em->src_offset_x != 0 ||
5793 g_em->src_offset_y != 0 ||
5794 g_em->dst_offset_x != 0 ||
5795 g_em->dst_offset_y != 0)
5796 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5798 g_em->src_offset_x, g_em->src_offset_y,
5799 g_em->dst_offset_x, g_em->dst_offset_y);
5801 if (g_em->width != TILEX ||
5802 g_em->height != TILEY)
5803 printf(" %d (%d): size %d,%d should be %d,%d\n",
5805 g_em->width, g_em->height, TILEX, TILEY);
5807 num_em_gfx_errors++;
5814 for (i = 0; i < TILE_MAX; i++)
5816 for (j = 0; j < 8; j++)
5818 int element = object_mapping[i].element_rnd;
5819 int action = object_mapping[i].action;
5820 int direction = object_mapping[i].direction;
5821 boolean is_backside = object_mapping[i].is_backside;
5823 int graphic_action = el_act_dir2img(element, action, direction);
5824 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5826 int graphic_action = element_info[element].graphic[action];
5827 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5830 if ((action == ACTION_SMASHED_BY_ROCK ||
5831 action == ACTION_SMASHED_BY_SPRING ||
5832 action == ACTION_EATING) &&
5833 graphic_action == graphic_default)
5835 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5836 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5837 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5838 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5841 /* no separate animation for "smashed by rock" -- use rock instead */
5842 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5843 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5845 g_em->bitmap = g_xx->bitmap;
5846 g_em->src_x = g_xx->src_x;
5847 g_em->src_y = g_xx->src_y;
5848 g_em->src_offset_x = g_xx->src_offset_x;
5849 g_em->src_offset_y = g_xx->src_offset_y;
5850 g_em->dst_offset_x = g_xx->dst_offset_x;
5851 g_em->dst_offset_y = g_xx->dst_offset_y;
5852 g_em->width = g_xx->width;
5853 g_em->height = g_xx->height;
5855 g_em->unique_identifier = g_xx->unique_identifier;
5859 g_em->preserve_background = TRUE;
5864 for (p = 0; p < MAX_PLAYERS; p++)
5866 for (i = 0; i < SPR_MAX; i++)
5868 int element = player_mapping[p][i].element_rnd;
5869 int action = player_mapping[p][i].action;
5870 int direction = player_mapping[p][i].direction;
5872 for (j = 0; j < 8; j++)
5874 int effective_element = element;
5875 int effective_action = action;
5876 int graphic = (direction == MV_NONE ?
5877 el_act2img(effective_element, effective_action) :
5878 el_act_dir2img(effective_element, effective_action,
5880 struct GraphicInfo *g = &graphic_info[graphic];
5881 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5887 Bitmap *debug_bitmap = g_em->bitmap;
5888 int debug_src_x = g_em->src_x;
5889 int debug_src_y = g_em->src_y;
5892 int frame = getAnimationFrame(g->anim_frames,
5895 g->anim_start_frame,
5898 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5900 g_em->bitmap = src_bitmap;
5901 g_em->src_x = src_x;
5902 g_em->src_y = src_y;
5903 g_em->src_offset_x = 0;
5904 g_em->src_offset_y = 0;
5905 g_em->dst_offset_x = 0;
5906 g_em->dst_offset_y = 0;
5907 g_em->width = TILEX;
5908 g_em->height = TILEY;
5913 /* skip check for EMC elements not contained in original EMC artwork */
5914 if (element == EL_PLAYER_3 ||
5915 element == EL_PLAYER_4)
5919 if (g_em->bitmap != debug_bitmap ||
5920 g_em->src_x != debug_src_x ||
5921 g_em->src_y != debug_src_y)
5923 static int last_i = -1;
5931 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5932 p, i, element, element_info[element].token_name,
5933 element_action_info[effective_action].suffix, direction);
5935 if (element != effective_element)
5936 printf(" [%d ('%s')]",
5938 element_info[effective_element].token_name);
5942 if (g_em->bitmap != debug_bitmap)
5943 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5944 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5946 if (g_em->src_x != debug_src_x ||
5947 g_em->src_y != debug_src_y)
5948 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5950 g_em->src_x, g_em->src_y,
5951 g_em->src_x / 32, g_em->src_y / 32,
5952 debug_src_x, debug_src_y,
5953 debug_src_x / 32, debug_src_y / 32);
5955 num_em_gfx_errors++;
5965 printf("::: [%d errors found]\n", num_em_gfx_errors);
5971 void PlayMenuSound()
5973 int sound = menu.sound[game_status];
5975 if (sound == SND_UNDEFINED)
5978 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5979 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5982 if (IS_LOOP_SOUND(sound))
5983 PlaySoundLoop(sound);
5988 void PlayMenuSoundStereo(int sound, int stereo_position)
5990 if (sound == SND_UNDEFINED)
5993 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5994 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5997 if (IS_LOOP_SOUND(sound))
5998 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6000 PlaySoundStereo(sound, stereo_position);
6003 void PlayMenuSoundIfLoop()
6005 int sound = menu.sound[game_status];
6007 if (sound == SND_UNDEFINED)
6010 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6011 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6014 if (IS_LOOP_SOUND(sound))
6015 PlaySoundLoop(sound);
6018 void PlayMenuMusic()
6020 int music = menu.music[game_status];
6022 if (music == MUS_UNDEFINED)
6028 void ToggleFullscreenIfNeeded()
6030 if (setup.fullscreen != video.fullscreen_enabled ||
6031 setup.fullscreen_mode != video.fullscreen_mode_current)
6033 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6035 /* save backbuffer content which gets lost when toggling fullscreen mode */
6036 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6038 if (setup.fullscreen && video.fullscreen_enabled)
6040 /* keep fullscreen mode, but change screen mode */
6041 video.fullscreen_mode_current = setup.fullscreen_mode;
6042 video.fullscreen_enabled = FALSE;
6045 /* toggle fullscreen */
6046 ChangeVideoModeIfNeeded(setup.fullscreen);
6047 setup.fullscreen = video.fullscreen_enabled;
6049 /* restore backbuffer content from temporary backbuffer backup bitmap */
6050 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6052 FreeBitmap(tmp_backbuffer);
6054 redraw_mask = REDRAW_ALL;