1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 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 */
141 RedrawPlayfield_EM(TRUE);
143 /* blit playfield from scroll buffer to normal back buffer for fading in */
144 BlitScreenToBitmap_EM(backbuffer);
146 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
152 width = gfx.sxsize + 2 * TILEX;
153 height = gfx.sysize + 2 * TILEY;
156 if (force_redraw || setup.direct_draw)
159 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
160 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
162 if (setup.direct_draw)
163 SetDrawtoField(DRAW_BACKBUFFER);
165 for (xx = BX1; xx <= BX2; xx++)
166 for (yy = BY1; yy <= BY2; yy++)
167 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
168 DrawScreenField(xx, yy);
171 if (setup.direct_draw)
172 SetDrawtoField(DRAW_DIRECT);
175 if (setup.soft_scrolling)
177 int fx = FX, fy = FY;
179 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
180 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
182 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
194 BlitBitmap(drawto, window, x, y, width, height, x, y);
200 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
202 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
203 redraw_mask &= ~REDRAW_MAIN;
205 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
206 redraw_mask |= REDRAW_FIELD;
208 if (redraw_mask & REDRAW_FIELD)
209 redraw_mask &= ~REDRAW_TILES;
211 if (redraw_mask == REDRAW_NONE)
214 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
216 static boolean last_frame_skipped = FALSE;
217 boolean skip_even_when_not_scrolling = TRUE;
218 boolean just_scrolling = (ScreenMovDir != 0);
219 boolean verbose = FALSE;
221 if (global.fps_slowdown_factor > 1 &&
222 (FrameCounter % global.fps_slowdown_factor) &&
223 (just_scrolling || skip_even_when_not_scrolling))
225 redraw_mask &= ~REDRAW_MAIN;
227 last_frame_skipped = TRUE;
230 printf("FRAME SKIPPED\n");
234 if (last_frame_skipped)
235 redraw_mask |= REDRAW_FIELD;
237 last_frame_skipped = FALSE;
240 printf("frame not skipped\n");
244 /* synchronize X11 graphics at this point; if we would synchronize the
245 display immediately after the buffer switching (after the XFlush),
246 this could mean that we have to wait for the graphics to complete,
247 although we could go on doing calculations for the next frame */
251 if (redraw_mask & REDRAW_ALL)
253 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
255 redraw_mask = REDRAW_NONE;
258 if (redraw_mask & REDRAW_FIELD)
260 if (game_status != GAME_MODE_PLAYING ||
261 redraw_mask & REDRAW_FROM_BACKBUFFER)
263 BlitBitmap(backbuffer, window,
264 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
268 int fx = FX, fy = FY;
270 if (setup.soft_scrolling)
272 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
273 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
276 if (setup.soft_scrolling ||
277 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
278 ABS(ScreenMovPos) == ScrollStepSize ||
279 redraw_tiles > REDRAWTILES_THRESHOLD)
281 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
285 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
287 (setup.soft_scrolling ?
288 "setup.soft_scrolling" :
289 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
290 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
291 ABS(ScreenGfxPos) == ScrollStepSize ?
292 "ABS(ScreenGfxPos) == ScrollStepSize" :
293 "redraw_tiles > REDRAWTILES_THRESHOLD"));
299 redraw_mask &= ~REDRAW_MAIN;
302 if (redraw_mask & REDRAW_DOORS)
304 if (redraw_mask & REDRAW_DOOR_1)
305 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
307 if (redraw_mask & REDRAW_DOOR_2)
308 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
310 if (redraw_mask & REDRAW_DOOR_3)
311 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
313 redraw_mask &= ~REDRAW_DOORS;
316 if (redraw_mask & REDRAW_MICROLEVEL)
318 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
319 SX, SY + 10 * TILEY);
321 redraw_mask &= ~REDRAW_MICROLEVEL;
324 if (redraw_mask & REDRAW_TILES)
326 for (x = 0; x < SCR_FIELDX; x++)
327 for (y = 0 ; y < SCR_FIELDY; y++)
328 if (redraw[redraw_x1 + x][redraw_y1 + y])
329 BlitBitmap(buffer, window,
330 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
331 SX + x * TILEX, SY + y * TILEY);
334 if (redraw_mask & REDRAW_FPS) /* display frames per second */
339 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
340 if (!global.fps_slowdown)
343 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
344 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
349 for (x = 0; x < MAX_BUF_XSIZE; x++)
350 for (y = 0; y < MAX_BUF_YSIZE; y++)
353 redraw_mask = REDRAW_NONE;
359 long fading_delay = 300;
361 if (setup.fading && (redraw_mask & REDRAW_FIELD))
368 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
371 for (i = 0; i < 2 * FULL_SYSIZE; i++)
373 for (y = 0; y < FULL_SYSIZE; y++)
375 BlitBitmap(backbuffer, window,
376 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
384 for (i = 1; i < FULL_SYSIZE; i+=2)
385 BlitBitmap(backbuffer, window,
386 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
392 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
393 BlitBitmapMasked(backbuffer, window,
394 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
399 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
400 BlitBitmapMasked(backbuffer, window,
401 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
406 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
407 BlitBitmapMasked(backbuffer, window,
408 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
413 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
414 BlitBitmapMasked(backbuffer, window,
415 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
420 redraw_mask &= ~REDRAW_MAIN;
427 void FadeExt(int fade_mask, int fade_mode)
429 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
430 int fade_delay = menu.fade_delay;
431 int post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
432 int x, y, width, height;
434 if (fade_mask & REDRAW_FIELD)
439 height = FULL_SYSIZE;
441 else /* REDRAW_ALL */
449 redraw_mask |= fade_mask;
451 if (!setup.fade_screens || fade_delay == 0)
453 if (fade_mode == FADE_MODE_FADE_OUT)
454 ClearRectangle(backbuffer, x, y, width, height);
461 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay);
463 redraw_mask &= ~fade_mask;
466 void FadeIn(int fade_mask)
468 FadeExt(fade_mask, FADE_MODE_FADE_IN);
471 void FadeOut(int fade_mask)
473 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
476 void FadeCross(int fade_mask)
478 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
481 void FadeCrossSaveBackbuffer()
483 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
486 void SetMainBackgroundImageIfDefined(int graphic)
488 if (graphic_info[graphic].bitmap)
489 SetMainBackgroundImage(graphic);
492 void SetMainBackgroundImage(int graphic)
494 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
495 graphic_info[graphic].bitmap ?
496 graphic_info[graphic].bitmap :
497 graphic_info[IMG_BACKGROUND].bitmap);
500 void SetDoorBackgroundImage(int graphic)
502 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
503 graphic_info[graphic].bitmap ?
504 graphic_info[graphic].bitmap :
505 graphic_info[IMG_BACKGROUND].bitmap);
508 void SetPanelBackground()
510 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
511 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
513 SetDoorBackgroundBitmap(bitmap_db_panel);
516 void DrawBackground(int dst_x, int dst_y, int width, int height)
519 ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
521 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
524 redraw_mask |= REDRAW_FIELD;
529 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
531 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
533 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
534 SetDrawtoField(DRAW_BUFFERED);
537 SetDrawtoField(DRAW_BACKBUFFER);
539 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
541 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
542 SetDrawtoField(DRAW_DIRECT);
546 void MarkTileDirty(int x, int y)
548 int xx = redraw_x1 + x;
549 int yy = redraw_y1 + y;
554 redraw[xx][yy] = TRUE;
555 redraw_mask |= REDRAW_TILES;
558 void SetBorderElement()
562 BorderElement = EL_EMPTY;
564 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
566 for (x = 0; x < lev_fieldx; x++)
568 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
569 BorderElement = EL_STEELWALL;
571 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
577 void SetRandomAnimationValue(int x, int y)
579 gfx.anim_random_frame = GfxRandom[x][y];
582 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
584 /* animation synchronized with global frame counter, not move position */
585 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
586 sync_frame = FrameCounter;
588 return getAnimationFrame(graphic_info[graphic].anim_frames,
589 graphic_info[graphic].anim_delay,
590 graphic_info[graphic].anim_mode,
591 graphic_info[graphic].anim_start_frame,
595 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
596 int *x, int *y, boolean get_backside)
598 struct GraphicInfo *g = &graphic_info[graphic];
599 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
600 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
604 if (g->offset_y == 0) /* frames are ordered horizontally */
606 int max_width = g->anim_frames_per_line * g->width;
607 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
609 *x = pos % max_width;
610 *y = src_y % g->height + pos / max_width * g->height;
612 else if (g->offset_x == 0) /* frames are ordered vertically */
614 int max_height = g->anim_frames_per_line * g->height;
615 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
617 *x = src_x % g->width + pos / max_height * g->width;
618 *y = pos % max_height;
620 else /* frames are ordered diagonally */
622 *x = src_x + frame * g->offset_x;
623 *y = src_y + frame * g->offset_y;
627 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
629 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
632 void DrawGraphic(int x, int y, int graphic, int frame)
635 if (!IN_SCR_FIELD(x, y))
637 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
638 printf("DrawGraphic(): This should never happen!\n");
643 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
647 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
653 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
654 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
657 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
660 if (!IN_SCR_FIELD(x, y))
662 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
663 printf("DrawGraphicThruMask(): This should never happen!\n");
668 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
673 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
679 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
681 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
682 dst_x - src_x, dst_y - src_y);
683 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
686 void DrawMiniGraphic(int x, int y, int graphic)
688 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
689 MarkTileDirty(x / 2, y / 2);
692 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
694 struct GraphicInfo *g = &graphic_info[graphic];
696 int mini_starty = g->bitmap->height * 2 / 3;
699 *x = mini_startx + g->src_x / 2;
700 *y = mini_starty + g->src_y / 2;
703 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
708 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
709 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
712 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
713 int graphic, int frame,
714 int cut_mode, int mask_mode)
719 int width = TILEX, height = TILEY;
722 if (dx || dy) /* shifted graphic */
724 if (x < BX1) /* object enters playfield from the left */
731 else if (x > BX2) /* object enters playfield from the right */
737 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
743 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
745 else if (dx) /* general horizontal movement */
746 MarkTileDirty(x + SIGN(dx), y);
748 if (y < BY1) /* object enters playfield from the top */
750 if (cut_mode==CUT_BELOW) /* object completely above top border */
758 else if (y > BY2) /* object enters playfield from the bottom */
764 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
770 else if (dy > 0 && cut_mode == CUT_ABOVE)
772 if (y == BY2) /* object completely above bottom border */
778 MarkTileDirty(x, y + 1);
779 } /* object leaves playfield to the bottom */
780 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
782 else if (dy) /* general vertical movement */
783 MarkTileDirty(x, y + SIGN(dy));
787 if (!IN_SCR_FIELD(x, y))
789 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
790 printf("DrawGraphicShifted(): This should never happen!\n");
795 if (width > 0 && height > 0)
797 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
802 dst_x = FX + x * TILEX + dx;
803 dst_y = FY + y * TILEY + dy;
805 if (mask_mode == USE_MASKING)
807 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
808 dst_x - src_x, dst_y - src_y);
809 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
813 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
820 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
821 int graphic, int frame,
822 int cut_mode, int mask_mode)
827 int width = TILEX, height = TILEY;
830 int x2 = x + SIGN(dx);
831 int y2 = y + SIGN(dy);
832 int anim_frames = graphic_info[graphic].anim_frames;
833 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
834 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
835 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
837 /* re-calculate animation frame for two-tile movement animation */
838 frame = getGraphicAnimationFrame(graphic, sync_frame);
840 /* check if movement start graphic inside screen area and should be drawn */
841 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
843 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
845 dst_x = FX + x1 * TILEX;
846 dst_y = FY + y1 * TILEY;
848 if (mask_mode == USE_MASKING)
850 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
851 dst_x - src_x, dst_y - src_y);
852 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
856 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
859 MarkTileDirty(x1, y1);
862 /* check if movement end graphic inside screen area and should be drawn */
863 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
865 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
867 dst_x = FX + x2 * TILEX;
868 dst_y = FY + y2 * TILEY;
870 if (mask_mode == USE_MASKING)
872 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
873 dst_x - src_x, dst_y - src_y);
874 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
878 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
881 MarkTileDirty(x2, y2);
885 static void DrawGraphicShifted(int x, int y, int dx, int dy,
886 int graphic, int frame,
887 int cut_mode, int mask_mode)
891 DrawGraphic(x, y, graphic, frame);
896 if (graphic_info[graphic].double_movement) /* EM style movement images */
897 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
899 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
902 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
903 int frame, int cut_mode)
905 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
908 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
909 int cut_mode, int mask_mode)
911 int lx = LEVELX(x), ly = LEVELY(y);
915 if (IN_LEV_FIELD(lx, ly))
917 SetRandomAnimationValue(lx, ly);
919 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
920 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
922 /* do not use double (EM style) movement graphic when not moving */
923 if (graphic_info[graphic].double_movement && !dx && !dy)
925 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
926 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
929 else /* border element */
931 graphic = el2img(element);
932 frame = getGraphicAnimationFrame(graphic, -1);
935 if (element == EL_EXPANDABLE_WALL)
937 boolean left_stopped = FALSE, right_stopped = FALSE;
939 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
941 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
942 right_stopped = TRUE;
944 if (left_stopped && right_stopped)
946 else if (left_stopped)
948 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
949 frame = graphic_info[graphic].anim_frames - 1;
951 else if (right_stopped)
953 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
954 frame = graphic_info[graphic].anim_frames - 1;
959 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
960 else if (mask_mode == USE_MASKING)
961 DrawGraphicThruMask(x, y, graphic, frame);
963 DrawGraphic(x, y, graphic, frame);
966 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
967 int cut_mode, int mask_mode)
969 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
970 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
971 cut_mode, mask_mode);
974 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
977 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
980 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
983 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
986 void DrawLevelElementThruMask(int x, int y, int element)
988 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
991 void DrawLevelFieldThruMask(int x, int y)
993 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
996 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1000 int sx = SCREENX(x), sy = SCREENY(y);
1002 int width, height, cx, cy, i;
1003 int crumbled_border_size = graphic_info[graphic].border_size;
1004 static int xy[4][2] =
1012 if (!IN_LEV_FIELD(x, y))
1015 element = TILE_GFX_ELEMENT(x, y);
1017 /* crumble field itself */
1018 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1020 if (!IN_SCR_FIELD(sx, sy))
1023 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1025 for (i = 0; i < 4; i++)
1027 int xx = x + xy[i][0];
1028 int yy = y + xy[i][1];
1030 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1033 /* check if neighbour field is of same type */
1034 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1037 if (i == 1 || i == 2)
1039 width = crumbled_border_size;
1041 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1047 height = crumbled_border_size;
1049 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1052 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1053 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1056 MarkTileDirty(sx, sy);
1058 else /* crumble neighbour fields */
1060 for (i = 0; i < 4; i++)
1062 int xx = x + xy[i][0];
1063 int yy = y + xy[i][1];
1064 int sxx = sx + xy[i][0];
1065 int syy = sy + xy[i][1];
1067 if (!IN_LEV_FIELD(xx, yy) ||
1068 !IN_SCR_FIELD(sxx, syy) ||
1072 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1075 element = TILE_GFX_ELEMENT(xx, yy);
1077 if (!GFX_CRUMBLED(element))
1080 graphic = el_act2crm(element, ACTION_DEFAULT);
1081 crumbled_border_size = graphic_info[graphic].border_size;
1083 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1085 if (i == 1 || i == 2)
1087 width = crumbled_border_size;
1089 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1095 height = crumbled_border_size;
1097 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1100 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1101 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1103 MarkTileDirty(sxx, syy);
1108 void DrawLevelFieldCrumbledSand(int x, int y)
1112 if (!IN_LEV_FIELD(x, y))
1116 /* !!! CHECK THIS !!! */
1119 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1120 GFX_CRUMBLED(GfxElement[x][y]))
1123 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1124 GfxElement[x][y] != EL_UNDEFINED &&
1125 GFX_CRUMBLED(GfxElement[x][y]))
1127 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1134 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1136 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1139 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1142 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1145 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1146 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1147 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1148 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1149 int sx = SCREENX(x), sy = SCREENY(y);
1151 DrawGraphic(sx, sy, graphic1, frame1);
1152 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1155 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1157 int sx = SCREENX(x), sy = SCREENY(y);
1158 static int xy[4][2] =
1167 for (i = 0; i < 4; i++)
1169 int xx = x + xy[i][0];
1170 int yy = y + xy[i][1];
1171 int sxx = sx + xy[i][0];
1172 int syy = sy + xy[i][1];
1174 if (!IN_LEV_FIELD(xx, yy) ||
1175 !IN_SCR_FIELD(sxx, syy) ||
1176 !GFX_CRUMBLED(Feld[xx][yy]) ||
1180 DrawLevelField(xx, yy);
1184 static int getBorderElement(int x, int y)
1188 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1189 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1190 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1191 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1192 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1193 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1194 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1196 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1197 int steel_position = (x == -1 && y == -1 ? 0 :
1198 x == lev_fieldx && y == -1 ? 1 :
1199 x == -1 && y == lev_fieldy ? 2 :
1200 x == lev_fieldx && y == lev_fieldy ? 3 :
1201 x == -1 || x == lev_fieldx ? 4 :
1202 y == -1 || y == lev_fieldy ? 5 : 6);
1204 return border[steel_position][steel_type];
1207 void DrawScreenElement(int x, int y, int element)
1209 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1210 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1213 void DrawLevelElement(int x, int y, int element)
1215 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1216 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1219 void DrawScreenField(int x, int y)
1221 int lx = LEVELX(x), ly = LEVELY(y);
1222 int element, content;
1224 if (!IN_LEV_FIELD(lx, ly))
1226 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1229 element = getBorderElement(lx, ly);
1231 DrawScreenElement(x, y, element);
1235 element = Feld[lx][ly];
1236 content = Store[lx][ly];
1238 if (IS_MOVING(lx, ly))
1240 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1241 boolean cut_mode = NO_CUTTING;
1243 if (element == EL_QUICKSAND_EMPTYING ||
1244 element == EL_MAGIC_WALL_EMPTYING ||
1245 element == EL_BD_MAGIC_WALL_EMPTYING ||
1246 element == EL_AMOEBA_DROPPING)
1247 cut_mode = CUT_ABOVE;
1248 else if (element == EL_QUICKSAND_FILLING ||
1249 element == EL_MAGIC_WALL_FILLING ||
1250 element == EL_BD_MAGIC_WALL_FILLING)
1251 cut_mode = CUT_BELOW;
1253 if (cut_mode == CUT_ABOVE)
1254 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1256 DrawScreenElement(x, y, EL_EMPTY);
1259 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1260 else if (cut_mode == NO_CUTTING)
1261 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1263 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1265 if (content == EL_ACID)
1267 int dir = MovDir[lx][ly];
1268 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1269 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1271 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1274 else if (IS_BLOCKED(lx, ly))
1279 boolean cut_mode = NO_CUTTING;
1280 int element_old, content_old;
1282 Blocked2Moving(lx, ly, &oldx, &oldy);
1285 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1286 MovDir[oldx][oldy] == MV_RIGHT);
1288 element_old = Feld[oldx][oldy];
1289 content_old = Store[oldx][oldy];
1291 if (element_old == EL_QUICKSAND_EMPTYING ||
1292 element_old == EL_MAGIC_WALL_EMPTYING ||
1293 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1294 element_old == EL_AMOEBA_DROPPING)
1295 cut_mode = CUT_ABOVE;
1297 DrawScreenElement(x, y, EL_EMPTY);
1300 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1302 else if (cut_mode == NO_CUTTING)
1303 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1306 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1309 else if (IS_DRAWABLE(element))
1310 DrawScreenElement(x, y, element);
1312 DrawScreenElement(x, y, EL_EMPTY);
1315 void DrawLevelField(int x, int y)
1317 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1318 DrawScreenField(SCREENX(x), SCREENY(y));
1319 else if (IS_MOVING(x, y))
1323 Moving2Blocked(x, y, &newx, &newy);
1324 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1325 DrawScreenField(SCREENX(newx), SCREENY(newy));
1327 else if (IS_BLOCKED(x, y))
1331 Blocked2Moving(x, y, &oldx, &oldy);
1332 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1333 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1337 void DrawMiniElement(int x, int y, int element)
1341 graphic = el2edimg(element);
1342 DrawMiniGraphic(x, y, graphic);
1345 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1347 int x = sx + scroll_x, y = sy + scroll_y;
1349 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1350 DrawMiniElement(sx, sy, EL_EMPTY);
1351 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1352 DrawMiniElement(sx, sy, Feld[x][y]);
1354 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1357 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1358 int x, int y, int xsize, int ysize, int font_nr)
1360 int font_width = getFontWidth(font_nr);
1361 int font_height = getFontHeight(font_nr);
1362 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1365 int dst_x = SX + startx + x * font_width;
1366 int dst_y = SY + starty + y * font_height;
1367 int width = graphic_info[graphic].width;
1368 int height = graphic_info[graphic].height;
1369 int inner_width = MAX(width - 2 * font_width, font_width);
1370 int inner_height = MAX(height - 2 * font_height, font_height);
1371 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1372 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1373 boolean draw_masked = graphic_info[graphic].draw_masked;
1375 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1377 if (src_bitmap == NULL || width < font_width || height < font_height)
1379 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1383 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1384 inner_sx + (x - 1) * font_width % inner_width);
1385 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1386 inner_sy + (y - 1) * font_height % inner_height);
1390 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1391 dst_x - src_x, dst_y - src_y);
1392 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1396 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1400 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1402 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1403 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1404 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1405 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1406 boolean no_delay = (tape.warp_forward);
1407 unsigned long anim_delay = 0;
1408 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1409 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1410 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1411 int font_width = getFontWidth(font_nr);
1412 int font_height = getFontHeight(font_nr);
1413 int max_xsize = level.envelope[envelope_nr].xsize;
1414 int max_ysize = level.envelope[envelope_nr].ysize;
1415 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1416 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1417 int xend = max_xsize;
1418 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1419 int xstep = (xstart < xend ? 1 : 0);
1420 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1423 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1425 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1426 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1427 int sx = (SXSIZE - xsize * font_width) / 2;
1428 int sy = (SYSIZE - ysize * font_height) / 2;
1431 SetDrawtoField(DRAW_BUFFERED);
1433 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1435 SetDrawtoField(DRAW_BACKBUFFER);
1437 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1438 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1440 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1441 level.envelope[envelope_nr].text, font_nr, max_xsize,
1442 xsize - 2, ysize - 2, mask_mode);
1444 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1447 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1451 void ShowEnvelope(int envelope_nr)
1453 int element = EL_ENVELOPE_1 + envelope_nr;
1454 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1455 int sound_opening = element_info[element].sound[ACTION_OPENING];
1456 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1457 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1458 boolean no_delay = (tape.warp_forward);
1459 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1460 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1461 int anim_mode = graphic_info[graphic].anim_mode;
1462 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1463 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1465 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1467 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1469 if (anim_mode == ANIM_DEFAULT)
1470 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1472 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1475 Delay(wait_delay_value);
1477 WaitForEventToContinue();
1479 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1481 if (anim_mode != ANIM_NONE)
1482 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1484 if (anim_mode == ANIM_DEFAULT)
1485 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1487 game.envelope_active = FALSE;
1489 SetDrawtoField(DRAW_BUFFERED);
1491 redraw_mask |= REDRAW_FIELD;
1495 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1500 int width_mult, width_div;
1501 int height_mult, height_div;
1509 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1510 5 - log_2(tilesize));
1511 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1512 int width_mult = offset_calc[offset_calc_pos].width_mult;
1513 int width_div = offset_calc[offset_calc_pos].width_div;
1514 int height_mult = offset_calc[offset_calc_pos].height_mult;
1515 int height_div = offset_calc[offset_calc_pos].height_div;
1516 int mini_startx = src_bitmap->width * width_mult / width_div;
1517 int mini_starty = src_bitmap->height * height_mult / height_div;
1518 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1519 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1521 *bitmap = src_bitmap;
1526 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1530 int graphic = el2preimg(element);
1532 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1533 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1540 SetDrawBackgroundMask(REDRAW_NONE);
1543 for (x = BX1; x <= BX2; x++)
1544 for (y = BY1; y <= BY2; y++)
1545 DrawScreenField(x, y);
1547 redraw_mask |= REDRAW_FIELD;
1550 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1554 for (x = 0; x < size_x; x++)
1555 for (y = 0; y < size_y; y++)
1556 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1558 redraw_mask |= REDRAW_FIELD;
1561 static void DrawPreviewLevelExt(int from_x, int from_y)
1563 boolean show_level_border = (BorderElement != EL_EMPTY);
1564 int dst_x = preview.x;
1565 int dst_y = preview.y;
1566 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1567 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1568 int tile_size = preview.tile_size;
1569 int preview_width = preview.xsize * tile_size;
1570 int preview_height = preview.ysize * tile_size;
1571 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1572 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1575 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1577 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1578 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1580 for (x = 0; x < real_preview_xsize; x++)
1582 for (y = 0; y < real_preview_ysize; y++)
1584 int lx = from_x + x + (show_level_border ? -1 : 0);
1585 int ly = from_y + y + (show_level_border ? -1 : 0);
1586 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1587 getBorderElement(lx, ly));
1589 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1590 element, tile_size);
1594 redraw_mask |= REDRAW_MICROLEVEL;
1597 #define MICROLABEL_EMPTY 0
1598 #define MICROLABEL_LEVEL_NAME 1
1599 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1600 #define MICROLABEL_LEVEL_AUTHOR 3
1601 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1602 #define MICROLABEL_IMPORTED_FROM 5
1603 #define MICROLABEL_IMPORTED_BY_HEAD 6
1604 #define MICROLABEL_IMPORTED_BY 7
1606 static void DrawPreviewLevelLabelExt(int mode)
1608 char label_text[MAX_OUTPUT_LINESIZE + 1];
1609 int max_len_label_text;
1610 int font_nr = FONT_TEXT_2;
1613 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1614 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1615 mode == MICROLABEL_IMPORTED_BY_HEAD)
1616 font_nr = FONT_TEXT_3;
1618 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1620 for (i = 0; i < max_len_label_text; i++)
1621 label_text[i] = ' ';
1622 label_text[max_len_label_text] = '\0';
1624 if (strlen(label_text) > 0)
1626 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1627 int lypos = MICROLABEL2_YPOS;
1629 DrawText(lxpos, lypos, label_text, font_nr);
1633 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1634 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1635 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1636 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1637 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1638 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1639 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1640 max_len_label_text);
1641 label_text[max_len_label_text] = '\0';
1643 if (strlen(label_text) > 0)
1645 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1646 int lypos = MICROLABEL2_YPOS;
1648 DrawText(lxpos, lypos, label_text, font_nr);
1651 redraw_mask |= REDRAW_MICROLEVEL;
1654 void DrawPreviewLevel(boolean restart)
1656 static unsigned long scroll_delay = 0;
1657 static unsigned long label_delay = 0;
1658 static int from_x, from_y, scroll_direction;
1659 static int label_state, label_counter;
1660 unsigned long scroll_delay_value = preview.step_delay;
1661 boolean show_level_border = (BorderElement != EL_EMPTY);
1662 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1663 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1664 int last_game_status = game_status; /* save current game status */
1666 /* force PREVIEW font on preview level */
1667 game_status = GAME_MODE_PSEUDO_PREVIEW;
1671 from_x = from_y = 0;
1672 scroll_direction = MV_RIGHT;
1676 DrawPreviewLevelExt(from_x, from_y);
1677 DrawPreviewLevelLabelExt(label_state);
1679 /* initialize delay counters */
1680 DelayReached(&scroll_delay, 0);
1681 DelayReached(&label_delay, 0);
1683 if (leveldir_current->name)
1685 char label_text[MAX_OUTPUT_LINESIZE + 1];
1686 int font_nr = FONT_TEXT_1;
1687 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1690 strncpy(label_text, leveldir_current->name, max_len_label_text);
1691 label_text[max_len_label_text] = '\0';
1693 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1694 lypos = SY + MICROLABEL1_YPOS;
1696 DrawText(lxpos, lypos, label_text, font_nr);
1699 game_status = last_game_status; /* restore current game status */
1704 /* scroll preview level, if needed */
1705 if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1706 DelayReached(&scroll_delay, scroll_delay_value))
1708 switch (scroll_direction)
1713 from_x -= preview.step_offset;
1714 from_x = (from_x < 0 ? 0 : from_x);
1717 scroll_direction = MV_UP;
1721 if (from_x < level_xsize - preview.xsize)
1723 from_x += preview.step_offset;
1724 from_x = (from_x > level_xsize - preview.xsize ?
1725 level_xsize - preview.xsize : from_x);
1728 scroll_direction = MV_DOWN;
1734 from_y -= preview.step_offset;
1735 from_y = (from_y < 0 ? 0 : from_y);
1738 scroll_direction = MV_RIGHT;
1742 if (from_y < level_ysize - preview.ysize)
1744 from_y += preview.step_offset;
1745 from_y = (from_y > level_ysize - preview.ysize ?
1746 level_ysize - preview.ysize : from_y);
1749 scroll_direction = MV_LEFT;
1756 DrawPreviewLevelExt(from_x, from_y);
1759 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1760 /* redraw micro level label, if needed */
1761 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1762 !strEqual(level.author, ANONYMOUS_NAME) &&
1763 !strEqual(level.author, leveldir_current->name) &&
1764 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1766 int max_label_counter = 23;
1768 if (leveldir_current->imported_from != NULL &&
1769 strlen(leveldir_current->imported_from) > 0)
1770 max_label_counter += 14;
1771 if (leveldir_current->imported_by != NULL &&
1772 strlen(leveldir_current->imported_by) > 0)
1773 max_label_counter += 14;
1775 label_counter = (label_counter + 1) % max_label_counter;
1776 label_state = (label_counter >= 0 && label_counter <= 7 ?
1777 MICROLABEL_LEVEL_NAME :
1778 label_counter >= 9 && label_counter <= 12 ?
1779 MICROLABEL_LEVEL_AUTHOR_HEAD :
1780 label_counter >= 14 && label_counter <= 21 ?
1781 MICROLABEL_LEVEL_AUTHOR :
1782 label_counter >= 23 && label_counter <= 26 ?
1783 MICROLABEL_IMPORTED_FROM_HEAD :
1784 label_counter >= 28 && label_counter <= 35 ?
1785 MICROLABEL_IMPORTED_FROM :
1786 label_counter >= 37 && label_counter <= 40 ?
1787 MICROLABEL_IMPORTED_BY_HEAD :
1788 label_counter >= 42 && label_counter <= 49 ?
1789 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1791 if (leveldir_current->imported_from == NULL &&
1792 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1793 label_state == MICROLABEL_IMPORTED_FROM))
1794 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1795 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1797 DrawPreviewLevelLabelExt(label_state);
1800 game_status = last_game_status; /* restore current game status */
1803 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1804 int graphic, int sync_frame, int mask_mode)
1806 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1808 if (mask_mode == USE_MASKING)
1809 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1811 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1814 inline void DrawGraphicAnimation(int x, int y, int graphic)
1816 int lx = LEVELX(x), ly = LEVELY(y);
1818 if (!IN_SCR_FIELD(x, y))
1821 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1822 graphic, GfxFrame[lx][ly], NO_MASKING);
1823 MarkTileDirty(x, y);
1826 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1828 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1831 void DrawLevelElementAnimation(int x, int y, int element)
1833 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1835 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1838 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1840 int sx = SCREENX(x), sy = SCREENY(y);
1842 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1845 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1848 DrawGraphicAnimation(sx, sy, graphic);
1851 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1852 DrawLevelFieldCrumbledSand(x, y);
1854 if (GFX_CRUMBLED(Feld[x][y]))
1855 DrawLevelFieldCrumbledSand(x, y);
1859 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1861 int sx = SCREENX(x), sy = SCREENY(y);
1864 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1867 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1869 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1872 DrawGraphicAnimation(sx, sy, graphic);
1874 if (GFX_CRUMBLED(element))
1875 DrawLevelFieldCrumbledSand(x, y);
1878 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1880 if (player->use_murphy)
1882 /* this works only because currently only one player can be "murphy" ... */
1883 static int last_horizontal_dir = MV_LEFT;
1884 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1886 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1887 last_horizontal_dir = move_dir;
1889 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1891 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1893 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1899 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1902 static boolean equalGraphics(int graphic1, int graphic2)
1904 struct GraphicInfo *g1 = &graphic_info[graphic1];
1905 struct GraphicInfo *g2 = &graphic_info[graphic2];
1907 return (g1->bitmap == g2->bitmap &&
1908 g1->src_x == g2->src_x &&
1909 g1->src_y == g2->src_y &&
1910 g1->anim_frames == g2->anim_frames &&
1911 g1->anim_delay == g2->anim_delay &&
1912 g1->anim_mode == g2->anim_mode);
1915 void DrawAllPlayers()
1919 for (i = 0; i < MAX_PLAYERS; i++)
1920 if (stored_player[i].active)
1921 DrawPlayer(&stored_player[i]);
1924 void DrawPlayerField(int x, int y)
1926 if (!IS_PLAYER(x, y))
1929 DrawPlayer(PLAYERINFO(x, y));
1932 void DrawPlayer(struct PlayerInfo *player)
1934 int jx = player->jx;
1935 int jy = player->jy;
1936 int move_dir = player->MovDir;
1937 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1938 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1939 int last_jx = (player->is_moving ? jx - dx : jx);
1940 int last_jy = (player->is_moving ? jy - dy : jy);
1941 int next_jx = jx + dx;
1942 int next_jy = jy + dy;
1943 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1944 boolean player_is_opaque = FALSE;
1945 int sx = SCREENX(jx), sy = SCREENY(jy);
1946 int sxx = 0, syy = 0;
1947 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1949 int action = ACTION_DEFAULT;
1950 int last_player_graphic = getPlayerGraphic(player, move_dir);
1951 int last_player_frame = player->Frame;
1954 /* GfxElement[][] is set to the element the player is digging or collecting;
1955 remove also for off-screen player if the player is not moving anymore */
1956 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1957 GfxElement[jx][jy] = EL_UNDEFINED;
1959 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1963 if (!IN_LEV_FIELD(jx, jy))
1965 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1966 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1967 printf("DrawPlayerField(): This should never happen!\n");
1972 if (element == EL_EXPLOSION)
1975 action = (player->is_pushing ? ACTION_PUSHING :
1976 player->is_digging ? ACTION_DIGGING :
1977 player->is_collecting ? ACTION_COLLECTING :
1978 player->is_moving ? ACTION_MOVING :
1979 player->is_snapping ? ACTION_SNAPPING :
1980 player->is_dropping ? ACTION_DROPPING :
1981 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1983 if (player->is_waiting)
1984 move_dir = player->dir_waiting;
1986 InitPlayerGfxAnimation(player, action, move_dir);
1988 /* ----------------------------------------------------------------------- */
1989 /* draw things in the field the player is leaving, if needed */
1990 /* ----------------------------------------------------------------------- */
1992 if (player->is_moving)
1994 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1996 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1998 if (last_element == EL_DYNAMITE_ACTIVE ||
1999 last_element == EL_EM_DYNAMITE_ACTIVE ||
2000 last_element == EL_SP_DISK_RED_ACTIVE)
2001 DrawDynamite(last_jx, last_jy);
2003 DrawLevelFieldThruMask(last_jx, last_jy);
2005 else if (last_element == EL_DYNAMITE_ACTIVE ||
2006 last_element == EL_EM_DYNAMITE_ACTIVE ||
2007 last_element == EL_SP_DISK_RED_ACTIVE)
2008 DrawDynamite(last_jx, last_jy);
2010 /* !!! this is not enough to prevent flickering of players which are
2011 moving next to each others without a free tile between them -- this
2012 can only be solved by drawing all players layer by layer (first the
2013 background, then the foreground etc.) !!! => TODO */
2014 else if (!IS_PLAYER(last_jx, last_jy))
2015 DrawLevelField(last_jx, last_jy);
2018 DrawLevelField(last_jx, last_jy);
2021 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2022 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2025 if (!IN_SCR_FIELD(sx, sy))
2028 if (setup.direct_draw)
2029 SetDrawtoField(DRAW_BUFFERED);
2031 /* ----------------------------------------------------------------------- */
2032 /* draw things behind the player, if needed */
2033 /* ----------------------------------------------------------------------- */
2036 DrawLevelElement(jx, jy, Back[jx][jy]);
2037 else if (IS_ACTIVE_BOMB(element))
2038 DrawLevelElement(jx, jy, EL_EMPTY);
2041 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2043 int old_element = GfxElement[jx][jy];
2044 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2045 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2047 if (GFX_CRUMBLED(old_element))
2048 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2050 DrawGraphic(sx, sy, old_graphic, frame);
2052 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2053 player_is_opaque = TRUE;
2057 GfxElement[jx][jy] = EL_UNDEFINED;
2059 /* make sure that pushed elements are drawn with correct frame rate */
2061 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2063 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2064 GfxFrame[jx][jy] = player->StepFrame;
2066 if (player->is_pushing && player->is_moving)
2067 GfxFrame[jx][jy] = player->StepFrame;
2070 DrawLevelField(jx, jy);
2074 /* ----------------------------------------------------------------------- */
2075 /* draw player himself */
2076 /* ----------------------------------------------------------------------- */
2078 graphic = getPlayerGraphic(player, move_dir);
2080 /* in the case of changed player action or direction, prevent the current
2081 animation frame from being restarted for identical animations */
2082 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2083 player->Frame = last_player_frame;
2085 frame = getGraphicAnimationFrame(graphic, player->Frame);
2089 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2090 sxx = player->GfxPos;
2092 syy = player->GfxPos;
2095 if (!setup.soft_scrolling && ScreenMovPos)
2098 if (player_is_opaque)
2099 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2101 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2103 if (SHIELD_ON(player))
2105 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2106 IMG_SHIELD_NORMAL_ACTIVE);
2107 int frame = getGraphicAnimationFrame(graphic, -1);
2109 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2112 /* ----------------------------------------------------------------------- */
2113 /* draw things the player is pushing, if needed */
2114 /* ----------------------------------------------------------------------- */
2117 printf("::: %d, %d [%d, %d] [%d]\n",
2118 player->is_pushing, player_is_moving, player->GfxAction,
2119 player->is_moving, player_is_moving);
2123 if (player->is_pushing && player->is_moving)
2125 int px = SCREENX(jx), py = SCREENY(jy);
2126 int pxx = (TILEX - ABS(sxx)) * dx;
2127 int pyy = (TILEY - ABS(syy)) * dy;
2128 int gfx_frame = GfxFrame[jx][jy];
2134 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2136 element = Feld[next_jx][next_jy];
2137 gfx_frame = GfxFrame[next_jx][next_jy];
2140 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2143 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2144 frame = getGraphicAnimationFrame(graphic, sync_frame);
2146 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2149 /* draw background element under pushed element (like the Sokoban field) */
2150 if (Back[next_jx][next_jy])
2151 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2153 /* masked drawing is needed for EMC style (double) movement graphics */
2154 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2158 /* ----------------------------------------------------------------------- */
2159 /* draw things in front of player (active dynamite or dynabombs) */
2160 /* ----------------------------------------------------------------------- */
2162 if (IS_ACTIVE_BOMB(element))
2164 graphic = el2img(element);
2165 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2167 if (game.emulation == EMU_SUPAPLEX)
2168 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2170 DrawGraphicThruMask(sx, sy, graphic, frame);
2173 if (player_is_moving && last_element == EL_EXPLOSION)
2175 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2176 GfxElement[last_jx][last_jy] : EL_EMPTY);
2177 int graphic = el_act2img(element, ACTION_EXPLODING);
2178 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2179 int phase = ExplodePhase[last_jx][last_jy] - 1;
2180 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2183 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2186 /* ----------------------------------------------------------------------- */
2187 /* draw elements the player is just walking/passing through/under */
2188 /* ----------------------------------------------------------------------- */
2190 if (player_is_moving)
2192 /* handle the field the player is leaving ... */
2193 if (IS_ACCESSIBLE_INSIDE(last_element))
2194 DrawLevelField(last_jx, last_jy);
2195 else if (IS_ACCESSIBLE_UNDER(last_element))
2196 DrawLevelFieldThruMask(last_jx, last_jy);
2199 /* do not redraw accessible elements if the player is just pushing them */
2200 if (!player_is_moving || !player->is_pushing)
2202 /* ... and the field the player is entering */
2203 if (IS_ACCESSIBLE_INSIDE(element))
2204 DrawLevelField(jx, jy);
2205 else if (IS_ACCESSIBLE_UNDER(element))
2206 DrawLevelFieldThruMask(jx, jy);
2209 if (setup.direct_draw)
2211 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2212 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2213 int x_size = TILEX * (1 + ABS(jx - last_jx));
2214 int y_size = TILEY * (1 + ABS(jy - last_jy));
2216 BlitBitmap(drawto_field, window,
2217 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2218 SetDrawtoField(DRAW_DIRECT);
2221 MarkTileDirty(sx, sy);
2224 /* ------------------------------------------------------------------------- */
2226 void WaitForEventToContinue()
2228 boolean still_wait = TRUE;
2230 /* simulate releasing mouse button over last gadget, if still pressed */
2232 HandleGadgets(-1, -1, 0);
2234 button_status = MB_RELEASED;
2250 case EVENT_BUTTONPRESS:
2251 case EVENT_KEYPRESS:
2255 case EVENT_KEYRELEASE:
2256 ClearPlayerAction();
2260 HandleOtherEvents(&event);
2264 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2271 /* don't eat all CPU time */
2276 #define MAX_REQUEST_LINES 13
2277 #define MAX_REQUEST_LINE_FONT1_LEN 7
2278 #define MAX_REQUEST_LINE_FONT2_LEN 10
2280 boolean Request(char *text, unsigned int req_state)
2282 int mx, my, ty, result = -1;
2283 unsigned int old_door_state;
2284 int last_game_status = game_status; /* save current game status */
2285 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2286 int font_nr = FONT_TEXT_2;
2287 int max_word_len = 0;
2290 for (text_ptr = text; *text_ptr; text_ptr++)
2292 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2294 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2296 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2297 font_nr = FONT_LEVEL_NUMBER;
2303 if (game_status == GAME_MODE_PLAYING &&
2304 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2305 BlitScreenToBitmap_EM(backbuffer);
2307 /* disable deactivated drawing when quick-loading level tape recording */
2308 if (tape.playing && tape.deactivate_display)
2309 TapeDeactivateDisplayOff(TRUE);
2311 SetMouseCursor(CURSOR_DEFAULT);
2313 #if defined(NETWORK_AVALIABLE)
2314 /* pause network game while waiting for request to answer */
2315 if (options.network &&
2316 game_status == GAME_MODE_PLAYING &&
2317 req_state & REQUEST_WAIT_FOR_INPUT)
2318 SendToServer_PausePlaying();
2321 old_door_state = GetDoorState();
2323 /* simulate releasing mouse button over last gadget, if still pressed */
2325 HandleGadgets(-1, -1, 0);
2329 if (old_door_state & DOOR_OPEN_1)
2331 CloseDoor(DOOR_CLOSE_1);
2333 /* save old door content */
2334 BlitBitmap(bitmap_db_door, bitmap_db_door,
2335 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2336 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2340 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2343 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2345 /* clear door drawing field */
2346 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2348 /* force DOOR font on preview level */
2349 game_status = GAME_MODE_PSEUDO_DOOR;
2351 /* write text for request */
2352 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2354 char text_line[max_request_line_len + 1];
2360 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2363 if (!tc || tc == ' ')
2374 strncpy(text_line, text, tl);
2377 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2378 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2379 text_line, font_nr);
2381 text += tl + (tc == ' ' ? 1 : 0);
2384 game_status = last_game_status; /* restore current game status */
2386 if (req_state & REQ_ASK)
2388 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2389 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2391 else if (req_state & REQ_CONFIRM)
2393 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2395 else if (req_state & REQ_PLAYER)
2397 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2398 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2399 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2400 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2403 /* copy request gadgets to door backbuffer */
2404 BlitBitmap(drawto, bitmap_db_door,
2405 DX, DY, DXSIZE, DYSIZE,
2406 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2408 OpenDoor(DOOR_OPEN_1);
2410 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2412 if (game_status == GAME_MODE_PLAYING)
2414 SetPanelBackground();
2415 SetDrawBackgroundMask(REDRAW_DOOR_1);
2419 SetDrawBackgroundMask(REDRAW_FIELD);
2425 if (game_status != GAME_MODE_MAIN)
2428 button_status = MB_RELEASED;
2430 request_gadget_id = -1;
2432 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2444 case EVENT_BUTTONPRESS:
2445 case EVENT_BUTTONRELEASE:
2446 case EVENT_MOTIONNOTIFY:
2448 if (event.type == EVENT_MOTIONNOTIFY)
2450 if (!PointerInWindow(window))
2451 continue; /* window and pointer are on different screens */
2456 motion_status = TRUE;
2457 mx = ((MotionEvent *) &event)->x;
2458 my = ((MotionEvent *) &event)->y;
2462 motion_status = FALSE;
2463 mx = ((ButtonEvent *) &event)->x;
2464 my = ((ButtonEvent *) &event)->y;
2465 if (event.type == EVENT_BUTTONPRESS)
2466 button_status = ((ButtonEvent *) &event)->button;
2468 button_status = MB_RELEASED;
2471 /* this sets 'request_gadget_id' */
2472 HandleGadgets(mx, my, button_status);
2474 switch(request_gadget_id)
2476 case TOOL_CTRL_ID_YES:
2479 case TOOL_CTRL_ID_NO:
2482 case TOOL_CTRL_ID_CONFIRM:
2483 result = TRUE | FALSE;
2486 case TOOL_CTRL_ID_PLAYER_1:
2489 case TOOL_CTRL_ID_PLAYER_2:
2492 case TOOL_CTRL_ID_PLAYER_3:
2495 case TOOL_CTRL_ID_PLAYER_4:
2506 case EVENT_KEYPRESS:
2507 switch(GetEventKey((KeyEvent *)&event, TRUE))
2520 if (req_state & REQ_PLAYER)
2524 case EVENT_KEYRELEASE:
2525 ClearPlayerAction();
2529 HandleOtherEvents(&event);
2533 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2535 int joy = AnyJoystick();
2537 if (joy & JOY_BUTTON_1)
2539 else if (joy & JOY_BUTTON_2)
2545 /* don't eat all CPU time */
2549 if (game_status != GAME_MODE_MAIN)
2554 if (!(req_state & REQ_STAY_OPEN))
2556 CloseDoor(DOOR_CLOSE_1);
2558 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2559 (req_state & REQ_REOPEN))
2560 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2565 if (game_status == GAME_MODE_PLAYING)
2567 SetPanelBackground();
2568 SetDrawBackgroundMask(REDRAW_DOOR_1);
2572 SetDrawBackgroundMask(REDRAW_FIELD);
2575 #if defined(NETWORK_AVALIABLE)
2576 /* continue network game after request */
2577 if (options.network &&
2578 game_status == GAME_MODE_PLAYING &&
2579 req_state & REQUEST_WAIT_FOR_INPUT)
2580 SendToServer_ContinuePlaying();
2583 /* restore deactivated drawing when quick-loading level tape recording */
2584 if (tape.playing && tape.deactivate_display)
2585 TapeDeactivateDisplayOn();
2590 unsigned int OpenDoor(unsigned int door_state)
2592 if (door_state & DOOR_COPY_BACK)
2594 if (door_state & DOOR_OPEN_1)
2595 BlitBitmap(bitmap_db_door, bitmap_db_door,
2596 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2597 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2599 if (door_state & DOOR_OPEN_2)
2600 BlitBitmap(bitmap_db_door, bitmap_db_door,
2601 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2602 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2604 door_state &= ~DOOR_COPY_BACK;
2607 return MoveDoor(door_state);
2610 unsigned int CloseDoor(unsigned int door_state)
2612 unsigned int old_door_state = GetDoorState();
2614 if (!(door_state & DOOR_NO_COPY_BACK))
2616 if (old_door_state & DOOR_OPEN_1)
2617 BlitBitmap(backbuffer, bitmap_db_door,
2618 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2620 if (old_door_state & DOOR_OPEN_2)
2621 BlitBitmap(backbuffer, bitmap_db_door,
2622 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2624 door_state &= ~DOOR_NO_COPY_BACK;
2627 return MoveDoor(door_state);
2630 unsigned int GetDoorState()
2632 return MoveDoor(DOOR_GET_STATE);
2635 unsigned int SetDoorState(unsigned int door_state)
2637 return MoveDoor(door_state | DOOR_SET_STATE);
2640 unsigned int MoveDoor(unsigned int door_state)
2642 static int door1 = DOOR_OPEN_1;
2643 static int door2 = DOOR_CLOSE_2;
2644 unsigned long door_delay = 0;
2645 unsigned long door_delay_value;
2648 if (door_1.width < 0 || door_1.width > DXSIZE)
2649 door_1.width = DXSIZE;
2650 if (door_1.height < 0 || door_1.height > DYSIZE)
2651 door_1.height = DYSIZE;
2652 if (door_2.width < 0 || door_2.width > VXSIZE)
2653 door_2.width = VXSIZE;
2654 if (door_2.height < 0 || door_2.height > VYSIZE)
2655 door_2.height = VYSIZE;
2657 if (door_state == DOOR_GET_STATE)
2658 return (door1 | door2);
2660 if (door_state & DOOR_SET_STATE)
2662 if (door_state & DOOR_ACTION_1)
2663 door1 = door_state & DOOR_ACTION_1;
2664 if (door_state & DOOR_ACTION_2)
2665 door2 = door_state & DOOR_ACTION_2;
2667 return (door1 | door2);
2670 if (!(door_state & DOOR_FORCE_REDRAW))
2672 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2673 door_state &= ~DOOR_OPEN_1;
2674 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2675 door_state &= ~DOOR_CLOSE_1;
2676 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2677 door_state &= ~DOOR_OPEN_2;
2678 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2679 door_state &= ~DOOR_CLOSE_2;
2682 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2685 if (setup.quick_doors)
2687 stepsize = 20; /* must be choosen to always draw last frame */
2688 door_delay_value = 0;
2691 if (global.autoplay_leveldir)
2693 door_state |= DOOR_NO_DELAY;
2694 door_state &= ~DOOR_CLOSE_ALL;
2697 if (door_state & DOOR_ACTION)
2699 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2700 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2701 boolean door_1_done = (!handle_door_1);
2702 boolean door_2_done = (!handle_door_2);
2703 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2704 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2705 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2706 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2707 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2708 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2709 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2710 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2711 int door_skip = max_door_size - door_size;
2712 int end = door_size;
2713 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2716 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2718 /* opening door sound has priority over simultaneously closing door */
2719 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2720 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2721 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2722 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2725 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2728 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2729 GC gc = bitmap->stored_clip_gc;
2731 if (door_state & DOOR_ACTION_1)
2733 int a = MIN(x * door_1.step_offset, end);
2734 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2735 int i = p + door_skip;
2737 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2739 BlitBitmap(bitmap_db_door, drawto,
2740 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2741 DXSIZE, DYSIZE, DX, DY);
2745 BlitBitmap(bitmap_db_door, drawto,
2746 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2747 DXSIZE, DYSIZE - p / 2, DX, DY);
2749 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2752 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2754 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2755 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2756 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2757 int dst2_x = DX, dst2_y = DY;
2758 int width = i, height = DYSIZE;
2760 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2761 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2764 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2765 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2768 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2770 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2771 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2772 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2773 int dst2_x = DX, dst2_y = DY;
2774 int width = DXSIZE, height = i;
2776 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2777 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2780 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2781 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2784 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2786 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2788 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2789 BlitBitmapMasked(bitmap, drawto,
2790 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2791 DX + DXSIZE - i, DY + j);
2792 BlitBitmapMasked(bitmap, drawto,
2793 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2794 DX + DXSIZE - i, DY + 140 + j);
2795 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2796 DY - (DOOR_GFX_PAGEY1 + j));
2797 BlitBitmapMasked(bitmap, drawto,
2798 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2800 BlitBitmapMasked(bitmap, drawto,
2801 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2804 BlitBitmapMasked(bitmap, drawto,
2805 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2807 BlitBitmapMasked(bitmap, drawto,
2808 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2810 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2811 BlitBitmapMasked(bitmap, drawto,
2812 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2813 DX + DXSIZE - i, DY + 77 + j);
2814 BlitBitmapMasked(bitmap, drawto,
2815 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2816 DX + DXSIZE - i, DY + 203 + j);
2819 redraw_mask |= REDRAW_DOOR_1;
2820 door_1_done = (a == end);
2823 if (door_state & DOOR_ACTION_2)
2825 int a = MIN(x * door_2.step_offset, door_size);
2826 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2827 int i = p + door_skip;
2829 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2831 BlitBitmap(bitmap_db_door, drawto,
2832 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2833 VXSIZE, VYSIZE, VX, VY);
2835 else if (x <= VYSIZE)
2837 BlitBitmap(bitmap_db_door, drawto,
2838 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2839 VXSIZE, VYSIZE - p / 2, VX, VY);
2841 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2844 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2846 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2847 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2848 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2849 int dst2_x = VX, dst2_y = VY;
2850 int width = i, height = VYSIZE;
2852 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2853 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2856 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2857 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2860 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2862 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2863 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2864 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2865 int dst2_x = VX, dst2_y = VY;
2866 int width = VXSIZE, height = i;
2868 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2869 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2872 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2873 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2876 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2878 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2880 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2881 BlitBitmapMasked(bitmap, drawto,
2882 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2883 VX + VXSIZE - i, VY + j);
2884 SetClipOrigin(bitmap, gc,
2885 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2886 BlitBitmapMasked(bitmap, drawto,
2887 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2890 BlitBitmapMasked(bitmap, drawto,
2891 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2892 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2893 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2894 BlitBitmapMasked(bitmap, drawto,
2895 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2897 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2900 redraw_mask |= REDRAW_DOOR_2;
2901 door_2_done = (a == VXSIZE);
2904 if (!(door_state & DOOR_NO_DELAY))
2908 if (game_status == GAME_MODE_MAIN)
2911 WaitUntilDelayReached(&door_delay, door_delay_value);
2916 if (door_state & DOOR_ACTION_1)
2917 door1 = door_state & DOOR_ACTION_1;
2918 if (door_state & DOOR_ACTION_2)
2919 door2 = door_state & DOOR_ACTION_2;
2921 return (door1 | door2);
2924 void DrawSpecialEditorDoor()
2926 /* draw bigger toolbox window */
2927 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2928 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2930 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2931 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2934 redraw_mask |= REDRAW_ALL;
2937 void UndrawSpecialEditorDoor()
2939 /* draw normal tape recorder window */
2940 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2941 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2944 redraw_mask |= REDRAW_ALL;
2948 /* ---------- new tool button stuff ---------------------------------------- */
2950 /* graphic position values for tool buttons */
2951 #define TOOL_BUTTON_YES_XPOS 2
2952 #define TOOL_BUTTON_YES_YPOS 250
2953 #define TOOL_BUTTON_YES_GFX_YPOS 0
2954 #define TOOL_BUTTON_YES_XSIZE 46
2955 #define TOOL_BUTTON_YES_YSIZE 28
2956 #define TOOL_BUTTON_NO_XPOS 52
2957 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2958 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2959 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2960 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2961 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2962 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2963 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2964 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2965 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2966 #define TOOL_BUTTON_PLAYER_XSIZE 30
2967 #define TOOL_BUTTON_PLAYER_YSIZE 30
2968 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2969 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2970 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2971 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2972 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2973 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2974 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2975 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2976 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2977 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2978 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2979 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2980 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2981 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2982 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2983 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2984 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2985 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2986 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2987 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2996 } toolbutton_info[NUM_TOOL_BUTTONS] =
2999 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3000 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3001 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3006 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3007 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3008 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3013 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3014 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3015 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3016 TOOL_CTRL_ID_CONFIRM,
3020 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3021 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3022 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3023 TOOL_CTRL_ID_PLAYER_1,
3027 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3028 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3029 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3030 TOOL_CTRL_ID_PLAYER_2,
3034 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3035 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3036 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3037 TOOL_CTRL_ID_PLAYER_3,
3041 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3042 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3043 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3044 TOOL_CTRL_ID_PLAYER_4,
3049 void CreateToolButtons()
3053 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3055 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3056 Bitmap *deco_bitmap = None;
3057 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3058 struct GadgetInfo *gi;
3059 unsigned long event_mask;
3060 int gd_xoffset, gd_yoffset;
3061 int gd_x1, gd_x2, gd_y;
3064 event_mask = GD_EVENT_RELEASED;
3066 gd_xoffset = toolbutton_info[i].xpos;
3067 gd_yoffset = toolbutton_info[i].ypos;
3068 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3069 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3070 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3072 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3074 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3076 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3077 &deco_bitmap, &deco_x, &deco_y);
3078 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3079 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3082 gi = CreateGadget(GDI_CUSTOM_ID, id,
3083 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3084 GDI_X, DX + toolbutton_info[i].x,
3085 GDI_Y, DY + toolbutton_info[i].y,
3086 GDI_WIDTH, toolbutton_info[i].width,
3087 GDI_HEIGHT, toolbutton_info[i].height,
3088 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3089 GDI_STATE, GD_BUTTON_UNPRESSED,
3090 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3091 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3092 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3093 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3094 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3095 GDI_DECORATION_SHIFTING, 1, 1,
3096 GDI_EVENT_MASK, event_mask,
3097 GDI_CALLBACK_ACTION, HandleToolButtons,
3101 Error(ERR_EXIT, "cannot create gadget");
3103 tool_gadget[id] = gi;
3107 void FreeToolButtons()
3111 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3112 FreeGadget(tool_gadget[i]);
3115 static void UnmapToolButtons()
3119 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3120 UnmapGadget(tool_gadget[i]);
3123 static void HandleToolButtons(struct GadgetInfo *gi)
3125 request_gadget_id = gi->custom_id;
3128 static struct Mapping_EM_to_RND_object
3131 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3132 boolean is_backside; /* backside of moving element */
3138 em_object_mapping_list[] =
3141 Xblank, TRUE, FALSE,
3145 Yacid_splash_eB, FALSE, FALSE,
3146 EL_ACID_SPLASH_RIGHT, -1, -1
3149 Yacid_splash_wB, FALSE, FALSE,
3150 EL_ACID_SPLASH_LEFT, -1, -1
3153 #ifdef EM_ENGINE_BAD_ROLL
3155 Xstone_force_e, FALSE, FALSE,
3156 EL_ROCK, -1, MV_BIT_RIGHT
3159 Xstone_force_w, FALSE, FALSE,
3160 EL_ROCK, -1, MV_BIT_LEFT
3163 Xnut_force_e, FALSE, FALSE,
3164 EL_NUT, -1, MV_BIT_RIGHT
3167 Xnut_force_w, FALSE, FALSE,
3168 EL_NUT, -1, MV_BIT_LEFT
3171 Xspring_force_e, FALSE, FALSE,
3172 EL_SPRING, -1, MV_BIT_RIGHT
3175 Xspring_force_w, FALSE, FALSE,
3176 EL_SPRING, -1, MV_BIT_LEFT
3179 Xemerald_force_e, FALSE, FALSE,
3180 EL_EMERALD, -1, MV_BIT_RIGHT
3183 Xemerald_force_w, FALSE, FALSE,
3184 EL_EMERALD, -1, MV_BIT_LEFT
3187 Xdiamond_force_e, FALSE, FALSE,
3188 EL_DIAMOND, -1, MV_BIT_RIGHT
3191 Xdiamond_force_w, FALSE, FALSE,
3192 EL_DIAMOND, -1, MV_BIT_LEFT
3195 Xbomb_force_e, FALSE, FALSE,
3196 EL_BOMB, -1, MV_BIT_RIGHT
3199 Xbomb_force_w, FALSE, FALSE,
3200 EL_BOMB, -1, MV_BIT_LEFT
3202 #endif /* EM_ENGINE_BAD_ROLL */
3205 Xstone, TRUE, FALSE,
3209 Xstone_pause, FALSE, FALSE,
3213 Xstone_fall, FALSE, FALSE,
3217 Ystone_s, FALSE, FALSE,
3218 EL_ROCK, ACTION_FALLING, -1
3221 Ystone_sB, FALSE, TRUE,
3222 EL_ROCK, ACTION_FALLING, -1
3225 Ystone_e, FALSE, FALSE,
3226 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3229 Ystone_eB, FALSE, TRUE,
3230 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3233 Ystone_w, FALSE, FALSE,
3234 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3237 Ystone_wB, FALSE, TRUE,
3238 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3245 Xnut_pause, FALSE, FALSE,
3249 Xnut_fall, FALSE, FALSE,
3253 Ynut_s, FALSE, FALSE,
3254 EL_NUT, ACTION_FALLING, -1
3257 Ynut_sB, FALSE, TRUE,
3258 EL_NUT, ACTION_FALLING, -1
3261 Ynut_e, FALSE, FALSE,
3262 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3265 Ynut_eB, FALSE, TRUE,
3266 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3269 Ynut_w, FALSE, FALSE,
3270 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3273 Ynut_wB, FALSE, TRUE,
3274 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3277 Xbug_n, TRUE, FALSE,
3281 Xbug_e, TRUE, FALSE,
3282 EL_BUG_RIGHT, -1, -1
3285 Xbug_s, TRUE, FALSE,
3289 Xbug_w, TRUE, FALSE,
3293 Xbug_gon, FALSE, FALSE,
3297 Xbug_goe, FALSE, FALSE,
3298 EL_BUG_RIGHT, -1, -1
3301 Xbug_gos, FALSE, FALSE,
3305 Xbug_gow, FALSE, FALSE,
3309 Ybug_n, FALSE, FALSE,
3310 EL_BUG, ACTION_MOVING, MV_BIT_UP
3313 Ybug_nB, FALSE, TRUE,
3314 EL_BUG, ACTION_MOVING, MV_BIT_UP
3317 Ybug_e, FALSE, FALSE,
3318 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3321 Ybug_eB, FALSE, TRUE,
3322 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3325 Ybug_s, FALSE, FALSE,
3326 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3329 Ybug_sB, FALSE, TRUE,
3330 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3333 Ybug_w, FALSE, FALSE,
3334 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3337 Ybug_wB, FALSE, TRUE,
3338 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3341 Ybug_w_n, FALSE, FALSE,
3342 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3345 Ybug_n_e, FALSE, FALSE,
3346 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3349 Ybug_e_s, FALSE, FALSE,
3350 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3353 Ybug_s_w, FALSE, FALSE,
3354 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3357 Ybug_e_n, FALSE, FALSE,
3358 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3361 Ybug_s_e, FALSE, FALSE,
3362 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3365 Ybug_w_s, FALSE, FALSE,
3366 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3369 Ybug_n_w, FALSE, FALSE,
3370 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3373 Ybug_stone, FALSE, FALSE,
3374 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3377 Ybug_spring, FALSE, FALSE,
3378 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3381 Xtank_n, TRUE, FALSE,
3382 EL_SPACESHIP_UP, -1, -1
3385 Xtank_e, TRUE, FALSE,
3386 EL_SPACESHIP_RIGHT, -1, -1
3389 Xtank_s, TRUE, FALSE,
3390 EL_SPACESHIP_DOWN, -1, -1
3393 Xtank_w, TRUE, FALSE,
3394 EL_SPACESHIP_LEFT, -1, -1
3397 Xtank_gon, FALSE, FALSE,
3398 EL_SPACESHIP_UP, -1, -1
3401 Xtank_goe, FALSE, FALSE,
3402 EL_SPACESHIP_RIGHT, -1, -1
3405 Xtank_gos, FALSE, FALSE,
3406 EL_SPACESHIP_DOWN, -1, -1
3409 Xtank_gow, FALSE, FALSE,
3410 EL_SPACESHIP_LEFT, -1, -1
3413 Ytank_n, FALSE, FALSE,
3414 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3417 Ytank_nB, FALSE, TRUE,
3418 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3421 Ytank_e, FALSE, FALSE,
3422 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3425 Ytank_eB, FALSE, TRUE,
3426 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3429 Ytank_s, FALSE, FALSE,
3430 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3433 Ytank_sB, FALSE, TRUE,
3434 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3437 Ytank_w, FALSE, FALSE,
3438 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3441 Ytank_wB, FALSE, TRUE,
3442 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3445 Ytank_w_n, FALSE, FALSE,
3446 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3449 Ytank_n_e, FALSE, FALSE,
3450 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3453 Ytank_e_s, FALSE, FALSE,
3454 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3457 Ytank_s_w, FALSE, FALSE,
3458 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3461 Ytank_e_n, FALSE, FALSE,
3462 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3465 Ytank_s_e, FALSE, FALSE,
3466 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3469 Ytank_w_s, FALSE, FALSE,
3470 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3473 Ytank_n_w, FALSE, FALSE,
3474 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3477 Ytank_stone, FALSE, FALSE,
3478 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3481 Ytank_spring, FALSE, FALSE,
3482 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3485 Xandroid, TRUE, FALSE,
3486 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3489 Xandroid_1_n, FALSE, FALSE,
3490 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3493 Xandroid_2_n, FALSE, FALSE,
3494 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3497 Xandroid_1_e, FALSE, FALSE,
3498 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3501 Xandroid_2_e, FALSE, FALSE,
3502 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3505 Xandroid_1_w, FALSE, FALSE,
3506 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3509 Xandroid_2_w, FALSE, FALSE,
3510 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3513 Xandroid_1_s, FALSE, FALSE,
3514 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3517 Xandroid_2_s, FALSE, FALSE,
3518 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3521 Yandroid_n, FALSE, FALSE,
3522 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3525 Yandroid_nB, FALSE, TRUE,
3526 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3529 Yandroid_ne, FALSE, FALSE,
3530 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3533 Yandroid_neB, FALSE, TRUE,
3534 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3537 Yandroid_e, FALSE, FALSE,
3538 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3541 Yandroid_eB, FALSE, TRUE,
3542 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3545 Yandroid_se, FALSE, FALSE,
3546 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3549 Yandroid_seB, FALSE, TRUE,
3550 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3553 Yandroid_s, FALSE, FALSE,
3554 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3557 Yandroid_sB, FALSE, TRUE,
3558 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3561 Yandroid_sw, FALSE, FALSE,
3562 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3565 Yandroid_swB, FALSE, TRUE,
3566 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3569 Yandroid_w, FALSE, FALSE,
3570 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3573 Yandroid_wB, FALSE, TRUE,
3574 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3577 Yandroid_nw, FALSE, FALSE,
3578 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3581 Yandroid_nwB, FALSE, TRUE,
3582 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3585 Xspring, TRUE, FALSE,
3589 Xspring_pause, FALSE, FALSE,
3593 Xspring_e, FALSE, FALSE,
3597 Xspring_w, FALSE, FALSE,
3601 Xspring_fall, FALSE, FALSE,
3605 Yspring_s, FALSE, FALSE,
3606 EL_SPRING, ACTION_FALLING, -1
3609 Yspring_sB, FALSE, TRUE,
3610 EL_SPRING, ACTION_FALLING, -1
3613 Yspring_e, FALSE, FALSE,
3614 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3617 Yspring_eB, FALSE, TRUE,
3618 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3621 Yspring_w, FALSE, FALSE,
3622 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3625 Yspring_wB, FALSE, TRUE,
3626 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3629 Yspring_kill_e, FALSE, FALSE,
3630 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3633 Yspring_kill_eB, FALSE, TRUE,
3634 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3637 Yspring_kill_w, FALSE, FALSE,
3638 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3641 Yspring_kill_wB, FALSE, TRUE,
3642 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3645 Xeater_n, TRUE, FALSE,
3646 EL_YAMYAM_UP, -1, -1
3649 Xeater_e, TRUE, FALSE,
3650 EL_YAMYAM_RIGHT, -1, -1
3653 Xeater_w, TRUE, FALSE,
3654 EL_YAMYAM_LEFT, -1, -1
3657 Xeater_s, TRUE, FALSE,
3658 EL_YAMYAM_DOWN, -1, -1
3661 Yeater_n, FALSE, FALSE,
3662 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3665 Yeater_nB, FALSE, TRUE,
3666 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3669 Yeater_e, FALSE, FALSE,
3670 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3673 Yeater_eB, FALSE, TRUE,
3674 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3677 Yeater_s, FALSE, FALSE,
3678 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3681 Yeater_sB, FALSE, TRUE,
3682 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3685 Yeater_w, FALSE, FALSE,
3686 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3689 Yeater_wB, FALSE, TRUE,
3690 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3693 Yeater_stone, FALSE, FALSE,
3694 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3697 Yeater_spring, FALSE, FALSE,
3698 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3701 Xalien, TRUE, FALSE,
3705 Xalien_pause, FALSE, FALSE,
3709 Yalien_n, FALSE, FALSE,
3710 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3713 Yalien_nB, FALSE, TRUE,
3714 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3717 Yalien_e, FALSE, FALSE,
3718 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3721 Yalien_eB, FALSE, TRUE,
3722 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3725 Yalien_s, FALSE, FALSE,
3726 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3729 Yalien_sB, FALSE, TRUE,
3730 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3733 Yalien_w, FALSE, FALSE,
3734 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3737 Yalien_wB, FALSE, TRUE,
3738 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3741 Yalien_stone, FALSE, FALSE,
3742 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3745 Yalien_spring, FALSE, FALSE,
3746 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3749 Xemerald, TRUE, FALSE,
3753 Xemerald_pause, FALSE, FALSE,
3757 Xemerald_fall, FALSE, FALSE,
3761 Xemerald_shine, FALSE, FALSE,
3762 EL_EMERALD, ACTION_TWINKLING, -1
3765 Yemerald_s, FALSE, FALSE,
3766 EL_EMERALD, ACTION_FALLING, -1
3769 Yemerald_sB, FALSE, TRUE,
3770 EL_EMERALD, ACTION_FALLING, -1
3773 Yemerald_e, FALSE, FALSE,
3774 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3777 Yemerald_eB, FALSE, TRUE,
3778 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3781 Yemerald_w, FALSE, FALSE,
3782 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3785 Yemerald_wB, FALSE, TRUE,
3786 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3789 Yemerald_eat, FALSE, FALSE,
3790 EL_EMERALD, ACTION_COLLECTING, -1
3793 Yemerald_stone, FALSE, FALSE,
3794 EL_NUT, ACTION_BREAKING, -1
3797 Xdiamond, TRUE, FALSE,
3801 Xdiamond_pause, FALSE, FALSE,
3805 Xdiamond_fall, FALSE, FALSE,
3809 Xdiamond_shine, FALSE, FALSE,
3810 EL_DIAMOND, ACTION_TWINKLING, -1
3813 Ydiamond_s, FALSE, FALSE,
3814 EL_DIAMOND, ACTION_FALLING, -1
3817 Ydiamond_sB, FALSE, TRUE,
3818 EL_DIAMOND, ACTION_FALLING, -1
3821 Ydiamond_e, FALSE, FALSE,
3822 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3825 Ydiamond_eB, FALSE, TRUE,
3826 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3829 Ydiamond_w, FALSE, FALSE,
3830 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3833 Ydiamond_wB, FALSE, TRUE,
3834 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3837 Ydiamond_eat, FALSE, FALSE,
3838 EL_DIAMOND, ACTION_COLLECTING, -1
3841 Ydiamond_stone, FALSE, FALSE,
3842 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3845 Xdrip_fall, TRUE, FALSE,
3846 EL_AMOEBA_DROP, -1, -1
3849 Xdrip_stretch, FALSE, FALSE,
3850 EL_AMOEBA_DROP, ACTION_FALLING, -1
3853 Xdrip_stretchB, FALSE, TRUE,
3854 EL_AMOEBA_DROP, ACTION_FALLING, -1
3857 Xdrip_eat, FALSE, FALSE,
3858 EL_AMOEBA_DROP, ACTION_GROWING, -1
3861 Ydrip_s1, FALSE, FALSE,
3862 EL_AMOEBA_DROP, ACTION_FALLING, -1
3865 Ydrip_s1B, FALSE, TRUE,
3866 EL_AMOEBA_DROP, ACTION_FALLING, -1
3869 Ydrip_s2, FALSE, FALSE,
3870 EL_AMOEBA_DROP, ACTION_FALLING, -1
3873 Ydrip_s2B, FALSE, TRUE,
3874 EL_AMOEBA_DROP, ACTION_FALLING, -1
3881 Xbomb_pause, FALSE, FALSE,
3885 Xbomb_fall, FALSE, FALSE,
3889 Ybomb_s, FALSE, FALSE,
3890 EL_BOMB, ACTION_FALLING, -1
3893 Ybomb_sB, FALSE, TRUE,
3894 EL_BOMB, ACTION_FALLING, -1
3897 Ybomb_e, FALSE, FALSE,
3898 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3901 Ybomb_eB, FALSE, TRUE,
3902 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3905 Ybomb_w, FALSE, FALSE,
3906 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3909 Ybomb_wB, FALSE, TRUE,
3910 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3913 Ybomb_eat, FALSE, FALSE,
3914 EL_BOMB, ACTION_ACTIVATING, -1
3917 Xballoon, TRUE, FALSE,
3921 Yballoon_n, FALSE, FALSE,
3922 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3925 Yballoon_nB, FALSE, TRUE,
3926 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3929 Yballoon_e, FALSE, FALSE,
3930 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3933 Yballoon_eB, FALSE, TRUE,
3934 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3937 Yballoon_s, FALSE, FALSE,
3938 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3941 Yballoon_sB, FALSE, TRUE,
3942 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3945 Yballoon_w, FALSE, FALSE,
3946 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3949 Yballoon_wB, FALSE, TRUE,
3950 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3953 Xgrass, TRUE, FALSE,
3954 EL_EMC_GRASS, -1, -1
3957 Ygrass_nB, FALSE, FALSE,
3958 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3961 Ygrass_eB, FALSE, FALSE,
3962 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3965 Ygrass_sB, FALSE, FALSE,
3966 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3969 Ygrass_wB, FALSE, FALSE,
3970 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3977 Ydirt_nB, FALSE, FALSE,
3978 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3981 Ydirt_eB, FALSE, FALSE,
3982 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3985 Ydirt_sB, FALSE, FALSE,
3986 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
3989 Ydirt_wB, FALSE, FALSE,
3990 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
3993 Xacid_ne, TRUE, FALSE,
3994 EL_ACID_POOL_TOPRIGHT, -1, -1
3997 Xacid_se, TRUE, FALSE,
3998 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4001 Xacid_s, TRUE, FALSE,
4002 EL_ACID_POOL_BOTTOM, -1, -1
4005 Xacid_sw, TRUE, FALSE,
4006 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4009 Xacid_nw, TRUE, FALSE,
4010 EL_ACID_POOL_TOPLEFT, -1, -1
4013 Xacid_1, TRUE, FALSE,
4017 Xacid_2, FALSE, FALSE,
4021 Xacid_3, FALSE, FALSE,
4025 Xacid_4, FALSE, FALSE,
4029 Xacid_5, FALSE, FALSE,
4033 Xacid_6, FALSE, FALSE,
4037 Xacid_7, FALSE, FALSE,
4041 Xacid_8, FALSE, FALSE,
4045 Xball_1, TRUE, FALSE,
4046 EL_EMC_MAGIC_BALL, -1, -1
4049 Xball_1B, FALSE, FALSE,
4050 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4053 Xball_2, FALSE, FALSE,
4054 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4057 Xball_2B, FALSE, FALSE,
4058 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4061 Yball_eat, FALSE, FALSE,
4062 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4065 Ykey_1_eat, FALSE, FALSE,
4066 EL_EM_KEY_1, ACTION_COLLECTING, -1
4069 Ykey_2_eat, FALSE, FALSE,
4070 EL_EM_KEY_2, ACTION_COLLECTING, -1
4073 Ykey_3_eat, FALSE, FALSE,
4074 EL_EM_KEY_3, ACTION_COLLECTING, -1
4077 Ykey_4_eat, FALSE, FALSE,
4078 EL_EM_KEY_4, ACTION_COLLECTING, -1
4081 Ykey_5_eat, FALSE, FALSE,
4082 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4085 Ykey_6_eat, FALSE, FALSE,
4086 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4089 Ykey_7_eat, FALSE, FALSE,
4090 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4093 Ykey_8_eat, FALSE, FALSE,
4094 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4097 Ylenses_eat, FALSE, FALSE,
4098 EL_EMC_LENSES, ACTION_COLLECTING, -1
4101 Ymagnify_eat, FALSE, FALSE,
4102 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4105 Ygrass_eat, FALSE, FALSE,
4106 EL_EMC_GRASS, ACTION_SNAPPING, -1
4109 Ydirt_eat, FALSE, FALSE,
4110 EL_SAND, ACTION_SNAPPING, -1
4113 Xgrow_ns, TRUE, FALSE,
4114 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4117 Ygrow_ns_eat, FALSE, FALSE,
4118 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4121 Xgrow_ew, TRUE, FALSE,
4122 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4125 Ygrow_ew_eat, FALSE, FALSE,
4126 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4129 Xwonderwall, TRUE, FALSE,
4130 EL_MAGIC_WALL, -1, -1
4133 XwonderwallB, FALSE, FALSE,
4134 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4137 Xamoeba_1, TRUE, FALSE,
4138 EL_AMOEBA_DRY, ACTION_OTHER, -1
4141 Xamoeba_2, FALSE, FALSE,
4142 EL_AMOEBA_DRY, ACTION_OTHER, -1
4145 Xamoeba_3, FALSE, FALSE,
4146 EL_AMOEBA_DRY, ACTION_OTHER, -1
4149 Xamoeba_4, FALSE, FALSE,
4150 EL_AMOEBA_DRY, ACTION_OTHER, -1
4153 Xamoeba_5, TRUE, FALSE,
4154 EL_AMOEBA_WET, ACTION_OTHER, -1
4157 Xamoeba_6, FALSE, FALSE,
4158 EL_AMOEBA_WET, ACTION_OTHER, -1
4161 Xamoeba_7, FALSE, FALSE,
4162 EL_AMOEBA_WET, ACTION_OTHER, -1
4165 Xamoeba_8, FALSE, FALSE,
4166 EL_AMOEBA_WET, ACTION_OTHER, -1
4169 Xdoor_1, TRUE, FALSE,
4170 EL_EM_GATE_1, -1, -1
4173 Xdoor_2, TRUE, FALSE,
4174 EL_EM_GATE_2, -1, -1
4177 Xdoor_3, TRUE, FALSE,
4178 EL_EM_GATE_3, -1, -1
4181 Xdoor_4, TRUE, FALSE,
4182 EL_EM_GATE_4, -1, -1
4185 Xdoor_5, TRUE, FALSE,
4186 EL_EMC_GATE_5, -1, -1
4189 Xdoor_6, TRUE, FALSE,
4190 EL_EMC_GATE_6, -1, -1
4193 Xdoor_7, TRUE, FALSE,
4194 EL_EMC_GATE_7, -1, -1
4197 Xdoor_8, TRUE, FALSE,
4198 EL_EMC_GATE_8, -1, -1
4201 Xkey_1, TRUE, FALSE,
4205 Xkey_2, TRUE, FALSE,
4209 Xkey_3, TRUE, FALSE,
4213 Xkey_4, TRUE, FALSE,
4217 Xkey_5, TRUE, FALSE,
4218 EL_EMC_KEY_5, -1, -1
4221 Xkey_6, TRUE, FALSE,
4222 EL_EMC_KEY_6, -1, -1
4225 Xkey_7, TRUE, FALSE,
4226 EL_EMC_KEY_7, -1, -1
4229 Xkey_8, TRUE, FALSE,
4230 EL_EMC_KEY_8, -1, -1
4233 Xwind_n, TRUE, FALSE,
4234 EL_BALLOON_SWITCH_UP, -1, -1
4237 Xwind_e, TRUE, FALSE,
4238 EL_BALLOON_SWITCH_RIGHT, -1, -1
4241 Xwind_s, TRUE, FALSE,
4242 EL_BALLOON_SWITCH_DOWN, -1, -1
4245 Xwind_w, TRUE, FALSE,
4246 EL_BALLOON_SWITCH_LEFT, -1, -1
4249 Xwind_nesw, TRUE, FALSE,
4250 EL_BALLOON_SWITCH_ANY, -1, -1
4253 Xwind_stop, TRUE, FALSE,
4254 EL_BALLOON_SWITCH_NONE, -1, -1
4258 EL_EXIT_CLOSED, -1, -1
4261 Xexit_1, TRUE, FALSE,
4262 EL_EXIT_OPEN, -1, -1
4265 Xexit_2, FALSE, FALSE,
4266 EL_EXIT_OPEN, -1, -1
4269 Xexit_3, FALSE, FALSE,
4270 EL_EXIT_OPEN, -1, -1
4273 Xdynamite, TRUE, FALSE,
4274 EL_EM_DYNAMITE, -1, -1
4277 Ydynamite_eat, FALSE, FALSE,
4278 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4281 Xdynamite_1, TRUE, FALSE,
4282 EL_EM_DYNAMITE_ACTIVE, -1, -1
4285 Xdynamite_2, FALSE, FALSE,
4286 EL_EM_DYNAMITE_ACTIVE, -1, -1
4289 Xdynamite_3, FALSE, FALSE,
4290 EL_EM_DYNAMITE_ACTIVE, -1, -1
4293 Xdynamite_4, FALSE, FALSE,
4294 EL_EM_DYNAMITE_ACTIVE, -1, -1
4297 Xbumper, TRUE, FALSE,
4298 EL_EMC_SPRING_BUMPER, -1, -1
4301 XbumperB, FALSE, FALSE,
4302 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4305 Xwheel, TRUE, FALSE,
4306 EL_ROBOT_WHEEL, -1, -1
4309 XwheelB, FALSE, FALSE,
4310 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4313 Xswitch, TRUE, FALSE,
4314 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4317 XswitchB, FALSE, FALSE,
4318 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4322 EL_QUICKSAND_EMPTY, -1, -1
4325 Xsand_stone, TRUE, FALSE,
4326 EL_QUICKSAND_FULL, -1, -1
4329 Xsand_stonein_1, FALSE, TRUE,
4330 EL_ROCK, ACTION_FILLING, -1
4333 Xsand_stonein_2, FALSE, TRUE,
4334 EL_ROCK, ACTION_FILLING, -1
4337 Xsand_stonein_3, FALSE, TRUE,
4338 EL_ROCK, ACTION_FILLING, -1
4341 Xsand_stonein_4, FALSE, TRUE,
4342 EL_ROCK, ACTION_FILLING, -1
4345 Xsand_stonesand_1, FALSE, FALSE,
4346 EL_QUICKSAND_FULL, -1, -1
4349 Xsand_stonesand_2, FALSE, FALSE,
4350 EL_QUICKSAND_FULL, -1, -1
4353 Xsand_stonesand_3, FALSE, FALSE,
4354 EL_QUICKSAND_FULL, -1, -1
4357 Xsand_stonesand_4, FALSE, FALSE,
4358 EL_QUICKSAND_FULL, -1, -1
4361 Xsand_stoneout_1, FALSE, FALSE,
4362 EL_ROCK, ACTION_EMPTYING, -1
4365 Xsand_stoneout_2, FALSE, FALSE,
4366 EL_ROCK, ACTION_EMPTYING, -1
4369 Xsand_sandstone_1, FALSE, FALSE,
4370 EL_QUICKSAND_FULL, -1, -1
4373 Xsand_sandstone_2, FALSE, FALSE,
4374 EL_QUICKSAND_FULL, -1, -1
4377 Xsand_sandstone_3, FALSE, FALSE,
4378 EL_QUICKSAND_FULL, -1, -1
4381 Xsand_sandstone_4, FALSE, FALSE,
4382 EL_QUICKSAND_FULL, -1, -1
4385 Xplant, TRUE, FALSE,
4386 EL_EMC_PLANT, -1, -1
4389 Yplant, FALSE, FALSE,
4390 EL_EMC_PLANT, -1, -1
4393 Xlenses, TRUE, FALSE,
4394 EL_EMC_LENSES, -1, -1
4397 Xmagnify, TRUE, FALSE,
4398 EL_EMC_MAGNIFIER, -1, -1
4401 Xdripper, TRUE, FALSE,
4402 EL_EMC_DRIPPER, -1, -1
4405 XdripperB, FALSE, FALSE,
4406 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4409 Xfake_blank, TRUE, FALSE,
4410 EL_INVISIBLE_WALL, -1, -1
4413 Xfake_blankB, FALSE, FALSE,
4414 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4417 Xfake_grass, TRUE, FALSE,
4418 EL_EMC_FAKE_GRASS, -1, -1
4421 Xfake_grassB, FALSE, FALSE,
4422 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4425 Xfake_door_1, TRUE, FALSE,
4426 EL_EM_GATE_1_GRAY, -1, -1
4429 Xfake_door_2, TRUE, FALSE,
4430 EL_EM_GATE_2_GRAY, -1, -1
4433 Xfake_door_3, TRUE, FALSE,
4434 EL_EM_GATE_3_GRAY, -1, -1
4437 Xfake_door_4, TRUE, FALSE,
4438 EL_EM_GATE_4_GRAY, -1, -1
4441 Xfake_door_5, TRUE, FALSE,
4442 EL_EMC_GATE_5_GRAY, -1, -1
4445 Xfake_door_6, TRUE, FALSE,
4446 EL_EMC_GATE_6_GRAY, -1, -1
4449 Xfake_door_7, TRUE, FALSE,
4450 EL_EMC_GATE_7_GRAY, -1, -1
4453 Xfake_door_8, TRUE, FALSE,
4454 EL_EMC_GATE_8_GRAY, -1, -1
4457 Xfake_acid_1, TRUE, FALSE,
4458 EL_EMC_FAKE_ACID, -1, -1
4461 Xfake_acid_2, FALSE, FALSE,
4462 EL_EMC_FAKE_ACID, -1, -1
4465 Xfake_acid_3, FALSE, FALSE,
4466 EL_EMC_FAKE_ACID, -1, -1
4469 Xfake_acid_4, FALSE, FALSE,
4470 EL_EMC_FAKE_ACID, -1, -1
4473 Xfake_acid_5, FALSE, FALSE,
4474 EL_EMC_FAKE_ACID, -1, -1
4477 Xfake_acid_6, FALSE, FALSE,
4478 EL_EMC_FAKE_ACID, -1, -1
4481 Xfake_acid_7, FALSE, FALSE,
4482 EL_EMC_FAKE_ACID, -1, -1
4485 Xfake_acid_8, FALSE, FALSE,
4486 EL_EMC_FAKE_ACID, -1, -1
4489 Xsteel_1, TRUE, FALSE,
4490 EL_STEELWALL, -1, -1
4493 Xsteel_2, TRUE, FALSE,
4494 EL_EMC_STEELWALL_2, -1, -1
4497 Xsteel_3, TRUE, FALSE,
4498 EL_EMC_STEELWALL_3, -1, -1
4501 Xsteel_4, TRUE, FALSE,
4502 EL_EMC_STEELWALL_4, -1, -1
4505 Xwall_1, TRUE, FALSE,
4509 Xwall_2, TRUE, FALSE,
4510 EL_EMC_WALL_14, -1, -1
4513 Xwall_3, TRUE, FALSE,
4514 EL_EMC_WALL_15, -1, -1
4517 Xwall_4, TRUE, FALSE,
4518 EL_EMC_WALL_16, -1, -1
4521 Xround_wall_1, TRUE, FALSE,
4522 EL_WALL_SLIPPERY, -1, -1
4525 Xround_wall_2, TRUE, FALSE,
4526 EL_EMC_WALL_SLIPPERY_2, -1, -1
4529 Xround_wall_3, TRUE, FALSE,
4530 EL_EMC_WALL_SLIPPERY_3, -1, -1
4533 Xround_wall_4, TRUE, FALSE,
4534 EL_EMC_WALL_SLIPPERY_4, -1, -1
4537 Xdecor_1, TRUE, FALSE,
4538 EL_EMC_WALL_8, -1, -1
4541 Xdecor_2, TRUE, FALSE,
4542 EL_EMC_WALL_6, -1, -1
4545 Xdecor_3, TRUE, FALSE,
4546 EL_EMC_WALL_4, -1, -1
4549 Xdecor_4, TRUE, FALSE,
4550 EL_EMC_WALL_7, -1, -1
4553 Xdecor_5, TRUE, FALSE,
4554 EL_EMC_WALL_5, -1, -1
4557 Xdecor_6, TRUE, FALSE,
4558 EL_EMC_WALL_9, -1, -1
4561 Xdecor_7, TRUE, FALSE,
4562 EL_EMC_WALL_10, -1, -1
4565 Xdecor_8, TRUE, FALSE,
4566 EL_EMC_WALL_1, -1, -1
4569 Xdecor_9, TRUE, FALSE,
4570 EL_EMC_WALL_2, -1, -1
4573 Xdecor_10, TRUE, FALSE,
4574 EL_EMC_WALL_3, -1, -1
4577 Xdecor_11, TRUE, FALSE,
4578 EL_EMC_WALL_11, -1, -1
4581 Xdecor_12, TRUE, FALSE,
4582 EL_EMC_WALL_12, -1, -1
4585 Xalpha_0, TRUE, FALSE,
4586 EL_CHAR('0'), -1, -1
4589 Xalpha_1, TRUE, FALSE,
4590 EL_CHAR('1'), -1, -1
4593 Xalpha_2, TRUE, FALSE,
4594 EL_CHAR('2'), -1, -1
4597 Xalpha_3, TRUE, FALSE,
4598 EL_CHAR('3'), -1, -1
4601 Xalpha_4, TRUE, FALSE,
4602 EL_CHAR('4'), -1, -1
4605 Xalpha_5, TRUE, FALSE,
4606 EL_CHAR('5'), -1, -1
4609 Xalpha_6, TRUE, FALSE,
4610 EL_CHAR('6'), -1, -1
4613 Xalpha_7, TRUE, FALSE,
4614 EL_CHAR('7'), -1, -1
4617 Xalpha_8, TRUE, FALSE,
4618 EL_CHAR('8'), -1, -1
4621 Xalpha_9, TRUE, FALSE,
4622 EL_CHAR('9'), -1, -1
4625 Xalpha_excla, TRUE, FALSE,
4626 EL_CHAR('!'), -1, -1
4629 Xalpha_quote, TRUE, FALSE,
4630 EL_CHAR('"'), -1, -1
4633 Xalpha_comma, TRUE, FALSE,
4634 EL_CHAR(','), -1, -1
4637 Xalpha_minus, TRUE, FALSE,
4638 EL_CHAR('-'), -1, -1
4641 Xalpha_perio, TRUE, FALSE,
4642 EL_CHAR('.'), -1, -1
4645 Xalpha_colon, TRUE, FALSE,
4646 EL_CHAR(':'), -1, -1
4649 Xalpha_quest, TRUE, FALSE,
4650 EL_CHAR('?'), -1, -1
4653 Xalpha_a, TRUE, FALSE,
4654 EL_CHAR('A'), -1, -1
4657 Xalpha_b, TRUE, FALSE,
4658 EL_CHAR('B'), -1, -1
4661 Xalpha_c, TRUE, FALSE,
4662 EL_CHAR('C'), -1, -1
4665 Xalpha_d, TRUE, FALSE,
4666 EL_CHAR('D'), -1, -1
4669 Xalpha_e, TRUE, FALSE,
4670 EL_CHAR('E'), -1, -1
4673 Xalpha_f, TRUE, FALSE,
4674 EL_CHAR('F'), -1, -1
4677 Xalpha_g, TRUE, FALSE,
4678 EL_CHAR('G'), -1, -1
4681 Xalpha_h, TRUE, FALSE,
4682 EL_CHAR('H'), -1, -1
4685 Xalpha_i, TRUE, FALSE,
4686 EL_CHAR('I'), -1, -1
4689 Xalpha_j, TRUE, FALSE,
4690 EL_CHAR('J'), -1, -1
4693 Xalpha_k, TRUE, FALSE,
4694 EL_CHAR('K'), -1, -1
4697 Xalpha_l, TRUE, FALSE,
4698 EL_CHAR('L'), -1, -1
4701 Xalpha_m, TRUE, FALSE,
4702 EL_CHAR('M'), -1, -1
4705 Xalpha_n, TRUE, FALSE,
4706 EL_CHAR('N'), -1, -1
4709 Xalpha_o, TRUE, FALSE,
4710 EL_CHAR('O'), -1, -1
4713 Xalpha_p, TRUE, FALSE,
4714 EL_CHAR('P'), -1, -1
4717 Xalpha_q, TRUE, FALSE,
4718 EL_CHAR('Q'), -1, -1
4721 Xalpha_r, TRUE, FALSE,
4722 EL_CHAR('R'), -1, -1
4725 Xalpha_s, TRUE, FALSE,
4726 EL_CHAR('S'), -1, -1
4729 Xalpha_t, TRUE, FALSE,
4730 EL_CHAR('T'), -1, -1
4733 Xalpha_u, TRUE, FALSE,
4734 EL_CHAR('U'), -1, -1
4737 Xalpha_v, TRUE, FALSE,
4738 EL_CHAR('V'), -1, -1
4741 Xalpha_w, TRUE, FALSE,
4742 EL_CHAR('W'), -1, -1
4745 Xalpha_x, TRUE, FALSE,
4746 EL_CHAR('X'), -1, -1
4749 Xalpha_y, TRUE, FALSE,
4750 EL_CHAR('Y'), -1, -1
4753 Xalpha_z, TRUE, FALSE,
4754 EL_CHAR('Z'), -1, -1
4757 Xalpha_arrow_e, TRUE, FALSE,
4758 EL_CHAR('>'), -1, -1
4761 Xalpha_arrow_w, TRUE, FALSE,
4762 EL_CHAR('<'), -1, -1
4765 Xalpha_copyr, TRUE, FALSE,
4766 EL_CHAR('©'), -1, -1
4770 Xboom_bug, FALSE, FALSE,
4771 EL_BUG, ACTION_EXPLODING, -1
4774 Xboom_bomb, FALSE, FALSE,
4775 EL_BOMB, ACTION_EXPLODING, -1
4778 Xboom_android, FALSE, FALSE,
4779 EL_EMC_ANDROID, ACTION_OTHER, -1
4782 Xboom_1, FALSE, FALSE,
4783 EL_DEFAULT, ACTION_EXPLODING, -1
4786 Xboom_2, FALSE, FALSE,
4787 EL_DEFAULT, ACTION_EXPLODING, -1
4790 Znormal, FALSE, FALSE,
4794 Zdynamite, FALSE, FALSE,
4798 Zplayer, FALSE, FALSE,
4802 ZBORDER, FALSE, FALSE,
4812 static struct Mapping_EM_to_RND_player
4821 em_player_mapping_list[] =
4825 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4829 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4833 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4837 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4841 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4845 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4849 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4853 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4857 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4861 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4865 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4869 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4873 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4877 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4881 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4885 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4889 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4893 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4897 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4901 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4905 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4909 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4913 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4917 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4921 EL_PLAYER_1, ACTION_DEFAULT, -1,
4925 EL_PLAYER_2, ACTION_DEFAULT, -1,
4929 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4933 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4937 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4941 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4945 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4949 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4953 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4957 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4961 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4965 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4969 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4973 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4977 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4981 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4985 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
4989 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
4993 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
4997 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5001 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5005 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5009 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5013 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5017 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5021 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5025 EL_PLAYER_3, ACTION_DEFAULT, -1,
5029 EL_PLAYER_4, ACTION_DEFAULT, -1,
5038 int map_element_RND_to_EM(int element_rnd)
5040 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5041 static boolean mapping_initialized = FALSE;
5043 if (!mapping_initialized)
5047 /* return "Xalpha_quest" for all undefined elements in mapping array */
5048 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5049 mapping_RND_to_EM[i] = Xalpha_quest;
5051 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5052 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5053 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5054 em_object_mapping_list[i].element_em;
5056 mapping_initialized = TRUE;
5059 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5060 return mapping_RND_to_EM[element_rnd];
5062 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5067 int map_element_EM_to_RND(int element_em)
5069 static unsigned short mapping_EM_to_RND[TILE_MAX];
5070 static boolean mapping_initialized = FALSE;
5072 if (!mapping_initialized)
5076 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5077 for (i = 0; i < TILE_MAX; i++)
5078 mapping_EM_to_RND[i] = EL_UNKNOWN;
5080 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5081 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5082 em_object_mapping_list[i].element_rnd;
5084 mapping_initialized = TRUE;
5087 if (element_em >= 0 && element_em < TILE_MAX)
5088 return mapping_EM_to_RND[element_em];
5090 Error(ERR_WARN, "invalid EM level element %d", element_em);
5095 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5097 struct LevelInfo_EM *level_em = level->native_em_level;
5098 struct LEVEL *lev = level_em->lev;
5101 for (i = 0; i < TILE_MAX; i++)
5102 lev->android_array[i] = Xblank;
5104 for (i = 0; i < level->num_android_clone_elements; i++)
5106 int element_rnd = level->android_clone_element[i];
5107 int element_em = map_element_RND_to_EM(element_rnd);
5109 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5110 if (em_object_mapping_list[j].element_rnd == element_rnd)
5111 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5115 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5117 struct LevelInfo_EM *level_em = level->native_em_level;
5118 struct LEVEL *lev = level_em->lev;
5121 level->num_android_clone_elements = 0;
5123 for (i = 0; i < TILE_MAX; i++)
5125 int element_em = lev->android_array[i];
5127 boolean element_found = FALSE;
5129 if (element_em == Xblank)
5132 element_rnd = map_element_EM_to_RND(element_em);
5134 for (j = 0; j < level->num_android_clone_elements; j++)
5135 if (level->android_clone_element[j] == element_rnd)
5136 element_found = TRUE;
5140 level->android_clone_element[level->num_android_clone_elements++] =
5143 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5148 if (level->num_android_clone_elements == 0)
5150 level->num_android_clone_elements = 1;
5151 level->android_clone_element[0] = EL_EMPTY;
5155 int map_direction_RND_to_EM(int direction)
5157 return (direction == MV_UP ? 0 :
5158 direction == MV_RIGHT ? 1 :
5159 direction == MV_DOWN ? 2 :
5160 direction == MV_LEFT ? 3 :
5164 int map_direction_EM_to_RND(int direction)
5166 return (direction == 0 ? MV_UP :
5167 direction == 1 ? MV_RIGHT :
5168 direction == 2 ? MV_DOWN :
5169 direction == 3 ? MV_LEFT :
5173 int get_next_element(int element)
5177 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5178 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5179 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5180 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5181 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5182 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5183 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5185 default: return element;
5190 int el_act_dir2img(int element, int action, int direction)
5192 element = GFX_ELEMENT(element);
5194 if (direction == MV_NONE)
5195 return element_info[element].graphic[action];
5197 direction = MV_DIR_TO_BIT(direction);
5199 return element_info[element].direction_graphic[action][direction];
5202 int el_act_dir2img(int element, int action, int direction)
5204 element = GFX_ELEMENT(element);
5205 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5207 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5208 return element_info[element].direction_graphic[action][direction];
5213 static int el_act_dir2crm(int element, int action, int direction)
5215 element = GFX_ELEMENT(element);
5217 if (direction == MV_NONE)
5218 return element_info[element].crumbled[action];
5220 direction = MV_DIR_TO_BIT(direction);
5222 return element_info[element].direction_crumbled[action][direction];
5225 static int el_act_dir2crm(int element, int action, int direction)
5227 element = GFX_ELEMENT(element);
5228 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5230 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5231 return element_info[element].direction_crumbled[action][direction];
5235 int el_act2img(int element, int action)
5237 element = GFX_ELEMENT(element);
5239 return element_info[element].graphic[action];
5242 int el_act2crm(int element, int action)
5244 element = GFX_ELEMENT(element);
5246 return element_info[element].crumbled[action];
5249 int el_dir2img(int element, int direction)
5251 element = GFX_ELEMENT(element);
5253 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5256 int el2baseimg(int element)
5258 return element_info[element].graphic[ACTION_DEFAULT];
5261 int el2img(int element)
5263 element = GFX_ELEMENT(element);
5265 return element_info[element].graphic[ACTION_DEFAULT];
5268 int el2edimg(int element)
5270 element = GFX_ELEMENT(element);
5272 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5275 int el2preimg(int element)
5277 element = GFX_ELEMENT(element);
5279 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5282 int font2baseimg(int font_nr)
5284 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5287 int getNumActivePlayers_EM()
5289 int num_players = 0;
5295 for (i = 0; i < MAX_PLAYERS; i++)
5296 if (tape.player_participates[i])
5302 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5304 int game_frame_delay_value;
5306 game_frame_delay_value =
5307 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5308 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5311 if (tape.playing && tape.warp_forward && !tape.pausing)
5312 game_frame_delay_value = 0;
5314 return game_frame_delay_value;
5317 unsigned int InitRND(long seed)
5319 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5320 return InitEngineRandom_EM(seed);
5322 return InitEngineRandom_RND(seed);
5325 void InitGraphicInfo_EM(void)
5327 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5328 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5332 int num_em_gfx_errors = 0;
5334 if (graphic_info_em_object[0][0].bitmap == NULL)
5336 /* EM graphics not yet initialized in em_open_all() */
5341 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5344 /* always start with reliable default values */
5345 for (i = 0; i < TILE_MAX; i++)
5347 object_mapping[i].element_rnd = EL_UNKNOWN;
5348 object_mapping[i].is_backside = FALSE;
5349 object_mapping[i].action = ACTION_DEFAULT;
5350 object_mapping[i].direction = MV_NONE;
5353 /* always start with reliable default values */
5354 for (p = 0; p < MAX_PLAYERS; p++)
5356 for (i = 0; i < SPR_MAX; i++)
5358 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5359 player_mapping[p][i].action = ACTION_DEFAULT;
5360 player_mapping[p][i].direction = MV_NONE;
5364 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5366 int e = em_object_mapping_list[i].element_em;
5368 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5369 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5371 if (em_object_mapping_list[i].action != -1)
5372 object_mapping[e].action = em_object_mapping_list[i].action;
5374 if (em_object_mapping_list[i].direction != -1)
5375 object_mapping[e].direction =
5376 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5379 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5381 int a = em_player_mapping_list[i].action_em;
5382 int p = em_player_mapping_list[i].player_nr;
5384 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5386 if (em_player_mapping_list[i].action != -1)
5387 player_mapping[p][a].action = em_player_mapping_list[i].action;
5389 if (em_player_mapping_list[i].direction != -1)
5390 player_mapping[p][a].direction =
5391 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5394 for (i = 0; i < TILE_MAX; i++)
5396 int element = object_mapping[i].element_rnd;
5397 int action = object_mapping[i].action;
5398 int direction = object_mapping[i].direction;
5399 boolean is_backside = object_mapping[i].is_backside;
5400 boolean action_removing = (action == ACTION_DIGGING ||
5401 action == ACTION_SNAPPING ||
5402 action == ACTION_COLLECTING);
5403 boolean action_exploding = ((action == ACTION_EXPLODING ||
5404 action == ACTION_SMASHED_BY_ROCK ||
5405 action == ACTION_SMASHED_BY_SPRING) &&
5406 element != EL_DIAMOND);
5407 boolean action_active = (action == ACTION_ACTIVE);
5408 boolean action_other = (action == ACTION_OTHER);
5410 for (j = 0; j < 8; j++)
5412 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5413 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5415 i == Xdrip_stretch ? element :
5416 i == Xdrip_stretchB ? element :
5417 i == Ydrip_s1 ? element :
5418 i == Ydrip_s1B ? element :
5419 i == Xball_1B ? element :
5420 i == Xball_2 ? element :
5421 i == Xball_2B ? element :
5422 i == Yball_eat ? element :
5423 i == Ykey_1_eat ? element :
5424 i == Ykey_2_eat ? element :
5425 i == Ykey_3_eat ? element :
5426 i == Ykey_4_eat ? element :
5427 i == Ykey_5_eat ? element :
5428 i == Ykey_6_eat ? element :
5429 i == Ykey_7_eat ? element :
5430 i == Ykey_8_eat ? element :
5431 i == Ylenses_eat ? element :
5432 i == Ymagnify_eat ? element :
5433 i == Ygrass_eat ? element :
5434 i == Ydirt_eat ? element :
5435 i == Yemerald_stone ? EL_EMERALD :
5436 i == Ydiamond_stone ? EL_ROCK :
5437 i == Xsand_stonein_1 ? element :
5438 i == Xsand_stonein_2 ? element :
5439 i == Xsand_stonein_3 ? element :
5440 i == Xsand_stonein_4 ? element :
5441 is_backside ? EL_EMPTY :
5442 action_removing ? EL_EMPTY :
5444 int effective_action = (j < 7 ? action :
5445 i == Xdrip_stretch ? action :
5446 i == Xdrip_stretchB ? action :
5447 i == Ydrip_s1 ? action :
5448 i == Ydrip_s1B ? action :
5449 i == Xball_1B ? action :
5450 i == Xball_2 ? action :
5451 i == Xball_2B ? action :
5452 i == Yball_eat ? action :
5453 i == Ykey_1_eat ? action :
5454 i == Ykey_2_eat ? action :
5455 i == Ykey_3_eat ? action :
5456 i == Ykey_4_eat ? action :
5457 i == Ykey_5_eat ? action :
5458 i == Ykey_6_eat ? action :
5459 i == Ykey_7_eat ? action :
5460 i == Ykey_8_eat ? action :
5461 i == Ylenses_eat ? action :
5462 i == Ymagnify_eat ? action :
5463 i == Ygrass_eat ? action :
5464 i == Ydirt_eat ? action :
5465 i == Xsand_stonein_1 ? action :
5466 i == Xsand_stonein_2 ? action :
5467 i == Xsand_stonein_3 ? action :
5468 i == Xsand_stonein_4 ? action :
5469 i == Xsand_stoneout_1 ? action :
5470 i == Xsand_stoneout_2 ? action :
5471 i == Xboom_android ? ACTION_EXPLODING :
5472 action_exploding ? ACTION_EXPLODING :
5473 action_active ? action :
5474 action_other ? action :
5476 int graphic = (el_act_dir2img(effective_element, effective_action,
5478 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5480 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5481 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5482 boolean has_action_graphics = (graphic != base_graphic);
5483 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5484 struct GraphicInfo *g = &graphic_info[graphic];
5485 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5488 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5489 boolean special_animation = (action != ACTION_DEFAULT &&
5490 g->anim_frames == 3 &&
5491 g->anim_delay == 2 &&
5492 g->anim_mode & ANIM_LINEAR);
5493 int sync_frame = (i == Xdrip_stretch ? 7 :
5494 i == Xdrip_stretchB ? 7 :
5495 i == Ydrip_s2 ? j + 8 :
5496 i == Ydrip_s2B ? j + 8 :
5505 i == Xfake_acid_1 ? 0 :
5506 i == Xfake_acid_2 ? 10 :
5507 i == Xfake_acid_3 ? 20 :
5508 i == Xfake_acid_4 ? 30 :
5509 i == Xfake_acid_5 ? 40 :
5510 i == Xfake_acid_6 ? 50 :
5511 i == Xfake_acid_7 ? 60 :
5512 i == Xfake_acid_8 ? 70 :
5514 i == Xball_2B ? j + 8 :
5515 i == Yball_eat ? j + 1 :
5516 i == Ykey_1_eat ? j + 1 :
5517 i == Ykey_2_eat ? j + 1 :
5518 i == Ykey_3_eat ? j + 1 :
5519 i == Ykey_4_eat ? j + 1 :
5520 i == Ykey_5_eat ? j + 1 :
5521 i == Ykey_6_eat ? j + 1 :
5522 i == Ykey_7_eat ? j + 1 :
5523 i == Ykey_8_eat ? j + 1 :
5524 i == Ylenses_eat ? j + 1 :
5525 i == Ymagnify_eat ? j + 1 :
5526 i == Ygrass_eat ? j + 1 :
5527 i == Ydirt_eat ? j + 1 :
5528 i == Xamoeba_1 ? 0 :
5529 i == Xamoeba_2 ? 1 :
5530 i == Xamoeba_3 ? 2 :
5531 i == Xamoeba_4 ? 3 :
5532 i == Xamoeba_5 ? 0 :
5533 i == Xamoeba_6 ? 1 :
5534 i == Xamoeba_7 ? 2 :
5535 i == Xamoeba_8 ? 3 :
5536 i == Xexit_2 ? j + 8 :
5537 i == Xexit_3 ? j + 16 :
5538 i == Xdynamite_1 ? 0 :
5539 i == Xdynamite_2 ? 8 :
5540 i == Xdynamite_3 ? 16 :
5541 i == Xdynamite_4 ? 24 :
5542 i == Xsand_stonein_1 ? j + 1 :
5543 i == Xsand_stonein_2 ? j + 9 :
5544 i == Xsand_stonein_3 ? j + 17 :
5545 i == Xsand_stonein_4 ? j + 25 :
5546 i == Xsand_stoneout_1 && j == 0 ? 0 :
5547 i == Xsand_stoneout_1 && j == 1 ? 0 :
5548 i == Xsand_stoneout_1 && j == 2 ? 1 :
5549 i == Xsand_stoneout_1 && j == 3 ? 2 :
5550 i == Xsand_stoneout_1 && j == 4 ? 2 :
5551 i == Xsand_stoneout_1 && j == 5 ? 3 :
5552 i == Xsand_stoneout_1 && j == 6 ? 4 :
5553 i == Xsand_stoneout_1 && j == 7 ? 4 :
5554 i == Xsand_stoneout_2 && j == 0 ? 5 :
5555 i == Xsand_stoneout_2 && j == 1 ? 6 :
5556 i == Xsand_stoneout_2 && j == 2 ? 7 :
5557 i == Xsand_stoneout_2 && j == 3 ? 8 :
5558 i == Xsand_stoneout_2 && j == 4 ? 9 :
5559 i == Xsand_stoneout_2 && j == 5 ? 11 :
5560 i == Xsand_stoneout_2 && j == 6 ? 13 :
5561 i == Xsand_stoneout_2 && j == 7 ? 15 :
5562 i == Xboom_bug && j == 1 ? 2 :
5563 i == Xboom_bug && j == 2 ? 2 :
5564 i == Xboom_bug && j == 3 ? 4 :
5565 i == Xboom_bug && j == 4 ? 4 :
5566 i == Xboom_bug && j == 5 ? 2 :
5567 i == Xboom_bug && j == 6 ? 2 :
5568 i == Xboom_bug && j == 7 ? 0 :
5569 i == Xboom_bomb && j == 1 ? 2 :
5570 i == Xboom_bomb && j == 2 ? 2 :
5571 i == Xboom_bomb && j == 3 ? 4 :
5572 i == Xboom_bomb && j == 4 ? 4 :
5573 i == Xboom_bomb && j == 5 ? 2 :
5574 i == Xboom_bomb && j == 6 ? 2 :
5575 i == Xboom_bomb && j == 7 ? 0 :
5576 i == Xboom_android && j == 7 ? 6 :
5577 i == Xboom_1 && j == 1 ? 2 :
5578 i == Xboom_1 && j == 2 ? 2 :
5579 i == Xboom_1 && j == 3 ? 4 :
5580 i == Xboom_1 && j == 4 ? 4 :
5581 i == Xboom_1 && j == 5 ? 6 :
5582 i == Xboom_1 && j == 6 ? 6 :
5583 i == Xboom_1 && j == 7 ? 8 :
5584 i == Xboom_2 && j == 0 ? 8 :
5585 i == Xboom_2 && j == 1 ? 8 :
5586 i == Xboom_2 && j == 2 ? 10 :
5587 i == Xboom_2 && j == 3 ? 10 :
5588 i == Xboom_2 && j == 4 ? 10 :
5589 i == Xboom_2 && j == 5 ? 12 :
5590 i == Xboom_2 && j == 6 ? 12 :
5591 i == Xboom_2 && j == 7 ? 12 :
5592 special_animation && j == 4 ? 3 :
5593 effective_action != action ? 0 :
5597 Bitmap *debug_bitmap = g_em->bitmap;
5598 int debug_src_x = g_em->src_x;
5599 int debug_src_y = g_em->src_y;
5602 int frame = getAnimationFrame(g->anim_frames,
5605 g->anim_start_frame,
5608 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5609 g->double_movement && is_backside);
5611 g_em->bitmap = src_bitmap;
5612 g_em->src_x = src_x;
5613 g_em->src_y = src_y;
5614 g_em->src_offset_x = 0;
5615 g_em->src_offset_y = 0;
5616 g_em->dst_offset_x = 0;
5617 g_em->dst_offset_y = 0;
5618 g_em->width = TILEX;
5619 g_em->height = TILEY;
5621 g_em->crumbled_bitmap = NULL;
5622 g_em->crumbled_src_x = 0;
5623 g_em->crumbled_src_y = 0;
5624 g_em->crumbled_border_size = 0;
5626 g_em->has_crumbled_graphics = FALSE;
5627 g_em->preserve_background = FALSE;
5630 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5631 printf("::: empty crumbled: %d [%s], %d, %d\n",
5632 effective_element, element_info[effective_element].token_name,
5633 effective_action, direction);
5636 /* if element can be crumbled, but certain action graphics are just empty
5637 space (like snapping sand with the original R'n'D graphics), do not
5638 treat these empty space graphics as crumbled graphics in EMC engine */
5639 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5641 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5643 g_em->has_crumbled_graphics = TRUE;
5644 g_em->crumbled_bitmap = src_bitmap;
5645 g_em->crumbled_src_x = src_x;
5646 g_em->crumbled_src_y = src_y;
5647 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5651 if (element == EL_ROCK &&
5652 effective_action == ACTION_FILLING)
5653 printf("::: has_action_graphics == %d\n", has_action_graphics);
5656 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5657 effective_action == ACTION_MOVING ||
5658 effective_action == ACTION_PUSHING ||
5659 effective_action == ACTION_EATING)) ||
5660 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5661 effective_action == ACTION_EMPTYING)))
5664 (effective_action == ACTION_FALLING ||
5665 effective_action == ACTION_FILLING ||
5666 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5667 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5668 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5669 int num_steps = (i == Ydrip_s1 ? 16 :
5670 i == Ydrip_s1B ? 16 :
5671 i == Ydrip_s2 ? 16 :
5672 i == Ydrip_s2B ? 16 :
5673 i == Xsand_stonein_1 ? 32 :
5674 i == Xsand_stonein_2 ? 32 :
5675 i == Xsand_stonein_3 ? 32 :
5676 i == Xsand_stonein_4 ? 32 :
5677 i == Xsand_stoneout_1 ? 16 :
5678 i == Xsand_stoneout_2 ? 16 : 8);
5679 int cx = ABS(dx) * (TILEX / num_steps);
5680 int cy = ABS(dy) * (TILEY / num_steps);
5681 int step_frame = (i == Ydrip_s2 ? j + 8 :
5682 i == Ydrip_s2B ? j + 8 :
5683 i == Xsand_stonein_2 ? j + 8 :
5684 i == Xsand_stonein_3 ? j + 16 :
5685 i == Xsand_stonein_4 ? j + 24 :
5686 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5687 int step = (is_backside ? step_frame : num_steps - step_frame);
5689 if (is_backside) /* tile where movement starts */
5691 if (dx < 0 || dy < 0)
5693 g_em->src_offset_x = cx * step;
5694 g_em->src_offset_y = cy * step;
5698 g_em->dst_offset_x = cx * step;
5699 g_em->dst_offset_y = cy * step;
5702 else /* tile where movement ends */
5704 if (dx < 0 || dy < 0)
5706 g_em->dst_offset_x = cx * step;
5707 g_em->dst_offset_y = cy * step;
5711 g_em->src_offset_x = cx * step;
5712 g_em->src_offset_y = cy * step;
5716 g_em->width = TILEX - cx * step;
5717 g_em->height = TILEY - cy * step;
5720 /* create unique graphic identifier to decide if tile must be redrawn */
5721 /* bit 31 - 16 (16 bit): EM style graphic
5722 bit 15 - 12 ( 4 bit): EM style frame
5723 bit 11 - 6 ( 6 bit): graphic width
5724 bit 5 - 0 ( 6 bit): graphic height */
5725 g_em->unique_identifier =
5726 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5730 /* skip check for EMC elements not contained in original EMC artwork */
5731 if (element == EL_EMC_FAKE_ACID)
5734 if (g_em->bitmap != debug_bitmap ||
5735 g_em->src_x != debug_src_x ||
5736 g_em->src_y != debug_src_y ||
5737 g_em->src_offset_x != 0 ||
5738 g_em->src_offset_y != 0 ||
5739 g_em->dst_offset_x != 0 ||
5740 g_em->dst_offset_y != 0 ||
5741 g_em->width != TILEX ||
5742 g_em->height != TILEY)
5744 static int last_i = -1;
5752 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5753 i, element, element_info[element].token_name,
5754 element_action_info[effective_action].suffix, direction);
5756 if (element != effective_element)
5757 printf(" [%d ('%s')]",
5759 element_info[effective_element].token_name);
5763 if (g_em->bitmap != debug_bitmap)
5764 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5765 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5767 if (g_em->src_x != debug_src_x ||
5768 g_em->src_y != debug_src_y)
5769 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5770 j, (is_backside ? 'B' : 'F'),
5771 g_em->src_x, g_em->src_y,
5772 g_em->src_x / 32, g_em->src_y / 32,
5773 debug_src_x, debug_src_y,
5774 debug_src_x / 32, debug_src_y / 32);
5776 if (g_em->src_offset_x != 0 ||
5777 g_em->src_offset_y != 0 ||
5778 g_em->dst_offset_x != 0 ||
5779 g_em->dst_offset_y != 0)
5780 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5782 g_em->src_offset_x, g_em->src_offset_y,
5783 g_em->dst_offset_x, g_em->dst_offset_y);
5785 if (g_em->width != TILEX ||
5786 g_em->height != TILEY)
5787 printf(" %d (%d): size %d,%d should be %d,%d\n",
5789 g_em->width, g_em->height, TILEX, TILEY);
5791 num_em_gfx_errors++;
5798 for (i = 0; i < TILE_MAX; i++)
5800 for (j = 0; j < 8; j++)
5802 int element = object_mapping[i].element_rnd;
5803 int action = object_mapping[i].action;
5804 int direction = object_mapping[i].direction;
5805 boolean is_backside = object_mapping[i].is_backside;
5806 int graphic_action = el_act_dir2img(element, action, direction);
5807 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5809 if ((action == ACTION_SMASHED_BY_ROCK ||
5810 action == ACTION_SMASHED_BY_SPRING ||
5811 action == ACTION_EATING) &&
5812 graphic_action == graphic_default)
5814 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5815 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5816 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5817 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5820 /* no separate animation for "smashed by rock" -- use rock instead */
5821 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5822 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5824 g_em->bitmap = g_xx->bitmap;
5825 g_em->src_x = g_xx->src_x;
5826 g_em->src_y = g_xx->src_y;
5827 g_em->src_offset_x = g_xx->src_offset_x;
5828 g_em->src_offset_y = g_xx->src_offset_y;
5829 g_em->dst_offset_x = g_xx->dst_offset_x;
5830 g_em->dst_offset_y = g_xx->dst_offset_y;
5831 g_em->width = g_xx->width;
5832 g_em->height = g_xx->height;
5833 g_em->unique_identifier = g_xx->unique_identifier;
5836 g_em->preserve_background = TRUE;
5841 for (p = 0; p < MAX_PLAYERS; p++)
5843 for (i = 0; i < SPR_MAX; i++)
5845 int element = player_mapping[p][i].element_rnd;
5846 int action = player_mapping[p][i].action;
5847 int direction = player_mapping[p][i].direction;
5849 for (j = 0; j < 8; j++)
5851 int effective_element = element;
5852 int effective_action = action;
5853 int graphic = (direction == MV_NONE ?
5854 el_act2img(effective_element, effective_action) :
5855 el_act_dir2img(effective_element, effective_action,
5857 struct GraphicInfo *g = &graphic_info[graphic];
5858 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5864 Bitmap *debug_bitmap = g_em->bitmap;
5865 int debug_src_x = g_em->src_x;
5866 int debug_src_y = g_em->src_y;
5869 int frame = getAnimationFrame(g->anim_frames,
5872 g->anim_start_frame,
5875 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5877 g_em->bitmap = src_bitmap;
5878 g_em->src_x = src_x;
5879 g_em->src_y = src_y;
5880 g_em->src_offset_x = 0;
5881 g_em->src_offset_y = 0;
5882 g_em->dst_offset_x = 0;
5883 g_em->dst_offset_y = 0;
5884 g_em->width = TILEX;
5885 g_em->height = TILEY;
5889 /* skip check for EMC elements not contained in original EMC artwork */
5890 if (element == EL_PLAYER_3 ||
5891 element == EL_PLAYER_4)
5894 if (g_em->bitmap != debug_bitmap ||
5895 g_em->src_x != debug_src_x ||
5896 g_em->src_y != debug_src_y)
5898 static int last_i = -1;
5906 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5907 p, i, element, element_info[element].token_name,
5908 element_action_info[effective_action].suffix, direction);
5910 if (element != effective_element)
5911 printf(" [%d ('%s')]",
5913 element_info[effective_element].token_name);
5917 if (g_em->bitmap != debug_bitmap)
5918 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5919 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5921 if (g_em->src_x != debug_src_x ||
5922 g_em->src_y != debug_src_y)
5923 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5925 g_em->src_x, g_em->src_y,
5926 g_em->src_x / 32, g_em->src_y / 32,
5927 debug_src_x, debug_src_y,
5928 debug_src_x / 32, debug_src_y / 32);
5930 num_em_gfx_errors++;
5940 printf("::: [%d errors found]\n", num_em_gfx_errors);
5946 void PlayMenuSound()
5948 int sound = menu.sound[game_status];
5950 if (sound == SND_UNDEFINED)
5953 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5954 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5957 if (IS_LOOP_SOUND(sound))
5958 PlaySoundLoop(sound);
5963 void PlayMenuSoundStereo(int sound, int stereo_position)
5965 if (sound == SND_UNDEFINED)
5968 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5969 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5972 if (IS_LOOP_SOUND(sound))
5973 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
5975 PlaySoundStereo(sound, stereo_position);
5978 void PlayMenuSoundIfLoop()
5980 int sound = menu.sound[game_status];
5982 if (sound == SND_UNDEFINED)
5985 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
5986 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
5989 if (IS_LOOP_SOUND(sound))
5990 PlaySoundLoop(sound);
5993 void PlayMenuMusic()
5995 int music = menu.music[game_status];
5997 if (music == MUS_UNDEFINED)
6003 void ToggleFullscreenIfNeeded()
6005 if (setup.fullscreen != video.fullscreen_enabled ||
6006 setup.fullscreen_mode != video.fullscreen_mode_current)
6008 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6010 /* save backbuffer content which gets lost when toggling fullscreen mode */
6011 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6013 if (setup.fullscreen && video.fullscreen_enabled)
6015 /* keep fullscreen mode, but change screen mode */
6016 video.fullscreen_mode_current = setup.fullscreen_mode;
6017 video.fullscreen_enabled = FALSE;
6020 /* toggle fullscreen */
6021 ChangeVideoModeIfNeeded(setup.fullscreen);
6022 setup.fullscreen = video.fullscreen_enabled;
6024 /* restore backbuffer content from temporary backbuffer backup bitmap */
6025 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6027 FreeBitmap(tmp_backbuffer);
6029 redraw_mask = REDRAW_ALL;