1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX 0
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES 0
29 #define TOOL_CTRL_ID_NO 1
30 #define TOOL_CTRL_ID_CONFIRM 2
31 #define TOOL_CTRL_ID_PLAYER_1 3
32 #define TOOL_CTRL_ID_PLAYER_2 4
33 #define TOOL_CTRL_ID_PLAYER_3 5
34 #define TOOL_CTRL_ID_PLAYER_4 6
36 #define NUM_TOOL_BUTTONS 7
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
47 static char *print_if_not_empty(int element)
49 static char *s = NULL;
50 char *token_name = element_info[element].token_name;
55 s = checked_malloc(strlen(token_name) + 10 + 1);
57 if (element != EL_EMPTY)
58 sprintf(s, "%d\t['%s']", element, token_name);
60 sprintf(s, "%d", element);
65 void DumpTile(int x, int y)
70 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
77 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80 if (!IN_LEV_FIELD(x, y))
82 printf("(not in level field)\n");
88 printf(" Feld: %d\t['%s']\n", Feld[x][y],
89 element_info[Feld[x][y]].token_name);
90 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
91 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
92 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
93 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94 printf(" MovPos: %d\n", MovPos[x][y]);
95 printf(" MovDir: %d\n", MovDir[x][y]);
96 printf(" MovDelay: %d\n", MovDelay[x][y]);
97 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
98 printf(" CustomValue: %d\n", CustomValue[x][y]);
99 printf(" GfxElement: %d\n", GfxElement[x][y]);
100 printf(" GfxAction: %d\n", GfxAction[x][y]);
101 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
105 void SetDrawtoField(int mode)
107 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
118 drawto_field = fieldbuffer;
120 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
126 BX2 = SCR_FIELDX - 1;
127 BY2 = SCR_FIELDY - 1;
131 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 if (game_status == GAME_MODE_PLAYING &&
138 level.game_engine_type == GAME_ENGINE_TYPE_EM)
140 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
145 /* blit playfield from scroll buffer to normal back buffer for fading in */
146 BlitScreenToBitmap_EM(backbuffer);
149 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
155 width = gfx.sxsize + 2 * TILEX;
156 height = gfx.sysize + 2 * TILEY;
159 if (force_redraw || setup.direct_draw)
162 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
163 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
165 if (setup.direct_draw)
166 SetDrawtoField(DRAW_BACKBUFFER);
168 for (xx = BX1; xx <= BX2; xx++)
169 for (yy = BY1; yy <= BY2; yy++)
170 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
171 DrawScreenField(xx, yy);
174 if (setup.direct_draw)
175 SetDrawtoField(DRAW_DIRECT);
178 if (setup.soft_scrolling)
180 int fx = FX, fy = FY;
182 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
183 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
185 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
189 BlitBitmap(drawto, window, x, y, width, height, x, y);
195 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
197 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
198 redraw_mask &= ~REDRAW_MAIN;
200 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
201 redraw_mask |= REDRAW_FIELD;
203 if (redraw_mask & REDRAW_FIELD)
204 redraw_mask &= ~REDRAW_TILES;
206 if (redraw_mask == REDRAW_NONE)
209 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
211 static boolean last_frame_skipped = FALSE;
212 boolean skip_even_when_not_scrolling = TRUE;
213 boolean just_scrolling = (ScreenMovDir != 0);
214 boolean verbose = FALSE;
216 if (global.fps_slowdown_factor > 1 &&
217 (FrameCounter % global.fps_slowdown_factor) &&
218 (just_scrolling || skip_even_when_not_scrolling))
220 redraw_mask &= ~REDRAW_MAIN;
222 last_frame_skipped = TRUE;
225 printf("FRAME SKIPPED\n");
229 if (last_frame_skipped)
230 redraw_mask |= REDRAW_FIELD;
232 last_frame_skipped = FALSE;
235 printf("frame not skipped\n");
239 /* synchronize X11 graphics at this point; if we would synchronize the
240 display immediately after the buffer switching (after the XFlush),
241 this could mean that we have to wait for the graphics to complete,
242 although we could go on doing calculations for the next frame */
246 if (redraw_mask & REDRAW_ALL)
248 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
250 redraw_mask = REDRAW_NONE;
253 if (redraw_mask & REDRAW_FIELD)
255 if (game_status != GAME_MODE_PLAYING ||
256 redraw_mask & REDRAW_FROM_BACKBUFFER)
258 BlitBitmap(backbuffer, window,
259 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
263 int fx = FX, fy = FY;
265 if (setup.soft_scrolling)
267 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
268 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
271 if (setup.soft_scrolling ||
272 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
273 ABS(ScreenMovPos) == ScrollStepSize ||
274 redraw_tiles > REDRAWTILES_THRESHOLD)
276 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
280 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
282 (setup.soft_scrolling ?
283 "setup.soft_scrolling" :
284 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
285 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
286 ABS(ScreenGfxPos) == ScrollStepSize ?
287 "ABS(ScreenGfxPos) == ScrollStepSize" :
288 "redraw_tiles > REDRAWTILES_THRESHOLD"));
294 redraw_mask &= ~REDRAW_MAIN;
297 if (redraw_mask & REDRAW_DOORS)
299 if (redraw_mask & REDRAW_DOOR_1)
300 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
302 if (redraw_mask & REDRAW_DOOR_2)
303 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
305 if (redraw_mask & REDRAW_DOOR_3)
306 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
308 redraw_mask &= ~REDRAW_DOORS;
311 if (redraw_mask & REDRAW_MICROLEVEL)
313 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
314 SX, SY + 10 * TILEY);
316 redraw_mask &= ~REDRAW_MICROLEVEL;
319 if (redraw_mask & REDRAW_TILES)
321 for (x = 0; x < SCR_FIELDX; x++)
322 for (y = 0 ; y < SCR_FIELDY; y++)
323 if (redraw[redraw_x1 + x][redraw_y1 + y])
324 BlitBitmap(buffer, window,
325 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
326 SX + x * TILEX, SY + y * TILEY);
329 if (redraw_mask & REDRAW_FPS) /* display frames per second */
334 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
335 if (!global.fps_slowdown)
338 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
339 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
344 for (x = 0; x < MAX_BUF_XSIZE; x++)
345 for (y = 0; y < MAX_BUF_YSIZE; y++)
348 redraw_mask = REDRAW_NONE;
354 long fading_delay = 300;
356 if (setup.fading && (redraw_mask & REDRAW_FIELD))
363 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
366 for (i = 0; i < 2 * FULL_SYSIZE; i++)
368 for (y = 0; y < FULL_SYSIZE; y++)
370 BlitBitmap(backbuffer, window,
371 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
379 for (i = 1; i < FULL_SYSIZE; i+=2)
380 BlitBitmap(backbuffer, window,
381 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
387 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
388 BlitBitmapMasked(backbuffer, window,
389 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
394 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
395 BlitBitmapMasked(backbuffer, window,
396 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
401 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
402 BlitBitmapMasked(backbuffer, window,
403 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
408 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
409 BlitBitmapMasked(backbuffer, window,
410 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
415 redraw_mask &= ~REDRAW_MAIN;
422 void FadeExt(int fade_mask, int fade_mode)
424 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
425 int fade_delay = menu.fade_delay;
426 int post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
427 int x, y, width, height;
429 if (fade_mask & REDRAW_ALL)
436 else if (fade_mask & REDRAW_FIELD)
441 height = FULL_SYSIZE;
444 redraw_mask |= fade_mask;
446 if (!setup.fading || fade_delay == 0)
448 if (fade_mode == FADE_MODE_FADE_OUT)
449 ClearRectangle(backbuffer, x, y, width, height);
456 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay);
458 redraw_mask &= ~fade_mask;
461 void FadeIn(int fade_mask)
463 FadeExt(fade_mask, FADE_MODE_FADE_IN);
466 void FadeOut(int fade_mask)
468 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
471 void FadeCross(int fade_mask)
473 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
476 void FadeCrossSaveBackbuffer()
478 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
481 void SetMainBackgroundImageIfDefined(int graphic)
483 if (graphic_info[graphic].bitmap)
484 SetMainBackgroundImage(graphic);
487 void SetMainBackgroundImage(int graphic)
489 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
490 graphic_info[graphic].bitmap ?
491 graphic_info[graphic].bitmap :
492 graphic_info[IMG_BACKGROUND].bitmap);
495 void SetDoorBackgroundImage(int graphic)
497 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
498 graphic_info[graphic].bitmap ?
499 graphic_info[graphic].bitmap :
500 graphic_info[IMG_BACKGROUND].bitmap);
503 void SetPanelBackground()
505 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
506 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
508 SetDoorBackgroundBitmap(bitmap_db_panel);
511 void DrawBackground(int dst_x, int dst_y, int width, int height)
514 ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
516 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
519 redraw_mask |= REDRAW_FIELD;
524 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
526 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
528 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
529 SetDrawtoField(DRAW_BUFFERED);
532 SetDrawtoField(DRAW_BACKBUFFER);
534 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
536 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
537 SetDrawtoField(DRAW_DIRECT);
541 void MarkTileDirty(int x, int y)
543 int xx = redraw_x1 + x;
544 int yy = redraw_y1 + y;
549 redraw[xx][yy] = TRUE;
550 redraw_mask |= REDRAW_TILES;
553 void SetBorderElement()
557 BorderElement = EL_EMPTY;
559 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
561 for (x = 0; x < lev_fieldx; x++)
563 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
564 BorderElement = EL_STEELWALL;
566 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
572 void SetRandomAnimationValue(int x, int y)
574 gfx.anim_random_frame = GfxRandom[x][y];
577 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
579 /* animation synchronized with global frame counter, not move position */
580 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
581 sync_frame = FrameCounter;
584 if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
590 printf("::: FOO!\n");
594 return getAnimationFrame(graphic_info[graphic].anim_frames,
595 graphic_info[graphic].anim_delay,
596 graphic_info[graphic].anim_mode,
597 graphic_info[graphic].anim_start_frame,
601 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
602 int *x, int *y, boolean get_backside)
604 struct GraphicInfo *g = &graphic_info[graphic];
605 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
606 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
610 if (g->offset_y == 0) /* frames are ordered horizontally */
612 int max_width = g->anim_frames_per_line * g->width;
613 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
615 *x = pos % max_width;
616 *y = src_y % g->height + pos / max_width * g->height;
618 else if (g->offset_x == 0) /* frames are ordered vertically */
620 int max_height = g->anim_frames_per_line * g->height;
621 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
623 *x = src_x % g->width + pos / max_height * g->width;
624 *y = pos % max_height;
626 else /* frames are ordered diagonally */
628 *x = src_x + frame * g->offset_x;
629 *y = src_y + frame * g->offset_y;
633 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
635 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
638 void DrawGraphic(int x, int y, int graphic, int frame)
641 if (!IN_SCR_FIELD(x, y))
643 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
644 printf("DrawGraphic(): This should never happen!\n");
649 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
653 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
659 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
660 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
663 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
666 if (!IN_SCR_FIELD(x, y))
668 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
669 printf("DrawGraphicThruMask(): This should never happen!\n");
674 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
679 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
685 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
687 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
688 dst_x - src_x, dst_y - src_y);
689 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
692 void DrawMiniGraphic(int x, int y, int graphic)
694 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
695 MarkTileDirty(x / 2, y / 2);
698 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
700 struct GraphicInfo *g = &graphic_info[graphic];
702 int mini_starty = g->bitmap->height * 2 / 3;
705 *x = mini_startx + g->src_x / 2;
706 *y = mini_starty + g->src_y / 2;
709 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
714 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
715 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
718 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
719 int graphic, int frame,
720 int cut_mode, int mask_mode)
725 int width = TILEX, height = TILEY;
728 if (dx || dy) /* shifted graphic */
730 if (x < BX1) /* object enters playfield from the left */
737 else if (x > BX2) /* object enters playfield from the right */
743 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
749 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
751 else if (dx) /* general horizontal movement */
752 MarkTileDirty(x + SIGN(dx), y);
754 if (y < BY1) /* object enters playfield from the top */
756 if (cut_mode==CUT_BELOW) /* object completely above top border */
764 else if (y > BY2) /* object enters playfield from the bottom */
770 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
776 else if (dy > 0 && cut_mode == CUT_ABOVE)
778 if (y == BY2) /* object completely above bottom border */
784 MarkTileDirty(x, y + 1);
785 } /* object leaves playfield to the bottom */
786 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
788 else if (dy) /* general vertical movement */
789 MarkTileDirty(x, y + SIGN(dy));
793 if (!IN_SCR_FIELD(x, y))
795 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
796 printf("DrawGraphicShifted(): This should never happen!\n");
801 if (width > 0 && height > 0)
803 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
808 dst_x = FX + x * TILEX + dx;
809 dst_y = FY + y * TILEY + dy;
811 if (mask_mode == USE_MASKING)
813 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
814 dst_x - src_x, dst_y - src_y);
815 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
819 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
826 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
827 int graphic, int frame,
828 int cut_mode, int mask_mode)
833 int width = TILEX, height = TILEY;
836 int x2 = x + SIGN(dx);
837 int y2 = y + SIGN(dy);
838 int anim_frames = graphic_info[graphic].anim_frames;
839 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
840 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
841 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
843 /* re-calculate animation frame for two-tile movement animation */
844 frame = getGraphicAnimationFrame(graphic, sync_frame);
846 /* check if movement start graphic inside screen area and should be drawn */
847 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
849 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
851 dst_x = FX + x1 * TILEX;
852 dst_y = FY + y1 * TILEY;
854 if (mask_mode == USE_MASKING)
856 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
857 dst_x - src_x, dst_y - src_y);
858 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
862 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
865 MarkTileDirty(x1, y1);
868 /* check if movement end graphic inside screen area and should be drawn */
869 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
871 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
873 dst_x = FX + x2 * TILEX;
874 dst_y = FY + y2 * TILEY;
876 if (mask_mode == USE_MASKING)
878 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
879 dst_x - src_x, dst_y - src_y);
880 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
884 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
887 MarkTileDirty(x2, y2);
891 static void DrawGraphicShifted(int x, int y, int dx, int dy,
892 int graphic, int frame,
893 int cut_mode, int mask_mode)
897 DrawGraphic(x, y, graphic, frame);
902 if (graphic_info[graphic].double_movement) /* EM style movement images */
903 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
905 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
908 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
909 int frame, int cut_mode)
911 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
914 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
915 int cut_mode, int mask_mode)
917 int lx = LEVELX(x), ly = LEVELY(y);
921 if (IN_LEV_FIELD(lx, ly))
923 SetRandomAnimationValue(lx, ly);
925 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
926 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
928 /* do not use double (EM style) movement graphic when not moving */
929 if (graphic_info[graphic].double_movement && !dx && !dy)
931 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
932 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
935 else /* border element */
937 graphic = el2img(element);
938 frame = getGraphicAnimationFrame(graphic, -1);
941 if (element == EL_EXPANDABLE_WALL)
943 boolean left_stopped = FALSE, right_stopped = FALSE;
945 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
947 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
948 right_stopped = TRUE;
950 if (left_stopped && right_stopped)
952 else if (left_stopped)
954 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
955 frame = graphic_info[graphic].anim_frames - 1;
957 else if (right_stopped)
959 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
960 frame = graphic_info[graphic].anim_frames - 1;
965 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
966 else if (mask_mode == USE_MASKING)
967 DrawGraphicThruMask(x, y, graphic, frame);
969 DrawGraphic(x, y, graphic, frame);
972 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
973 int cut_mode, int mask_mode)
975 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
976 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
977 cut_mode, mask_mode);
980 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
983 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
986 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
989 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
992 void DrawLevelElementThruMask(int x, int y, int element)
994 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
997 void DrawLevelFieldThruMask(int x, int y)
999 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1002 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1006 int sx = SCREENX(x), sy = SCREENY(y);
1008 int width, height, cx, cy, i;
1009 int crumbled_border_size = graphic_info[graphic].border_size;
1010 static int xy[4][2] =
1018 if (!IN_LEV_FIELD(x, y))
1021 element = TILE_GFX_ELEMENT(x, y);
1023 /* crumble field itself */
1024 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1026 if (!IN_SCR_FIELD(sx, sy))
1029 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1031 for (i = 0; i < 4; i++)
1033 int xx = x + xy[i][0];
1034 int yy = y + xy[i][1];
1036 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1039 /* check if neighbour field is of same type */
1040 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1043 if (i == 1 || i == 2)
1045 width = crumbled_border_size;
1047 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1053 height = crumbled_border_size;
1055 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1058 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1059 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1062 MarkTileDirty(sx, sy);
1064 else /* crumble neighbour fields */
1066 for (i = 0; i < 4; i++)
1068 int xx = x + xy[i][0];
1069 int yy = y + xy[i][1];
1070 int sxx = sx + xy[i][0];
1071 int syy = sy + xy[i][1];
1074 if (!IN_LEV_FIELD(xx, yy) ||
1075 !IN_SCR_FIELD(sxx, syy) ||
1080 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1084 element = TILE_GFX_ELEMENT(xx, yy);
1086 if (!GFX_CRUMBLED(element))
1089 if (!IN_LEV_FIELD(xx, yy) ||
1090 !IN_SCR_FIELD(sxx, syy) ||
1091 !GFX_CRUMBLED(Feld[xx][yy]) ||
1097 graphic = el_act2crm(element, ACTION_DEFAULT);
1099 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1101 crumbled_border_size = graphic_info[graphic].border_size;
1103 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1105 if (i == 1 || i == 2)
1107 width = crumbled_border_size;
1109 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1115 height = crumbled_border_size;
1117 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1120 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1121 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1123 MarkTileDirty(sxx, syy);
1128 void DrawLevelFieldCrumbledSand(int x, int y)
1132 if (!IN_LEV_FIELD(x, y))
1136 /* !!! CHECK THIS !!! */
1139 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1140 GFX_CRUMBLED(GfxElement[x][y]))
1143 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1144 GfxElement[x][y] != EL_UNDEFINED &&
1145 GFX_CRUMBLED(GfxElement[x][y]))
1147 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1154 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1156 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1159 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1162 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1165 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1166 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1167 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1168 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1169 int sx = SCREENX(x), sy = SCREENY(y);
1171 DrawGraphic(sx, sy, graphic1, frame1);
1172 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1175 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1177 int sx = SCREENX(x), sy = SCREENY(y);
1178 static int xy[4][2] =
1187 for (i = 0; i < 4; i++)
1189 int xx = x + xy[i][0];
1190 int yy = y + xy[i][1];
1191 int sxx = sx + xy[i][0];
1192 int syy = sy + xy[i][1];
1194 if (!IN_LEV_FIELD(xx, yy) ||
1195 !IN_SCR_FIELD(sxx, syy) ||
1196 !GFX_CRUMBLED(Feld[xx][yy]) ||
1200 DrawLevelField(xx, yy);
1204 static int getBorderElement(int x, int y)
1208 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1209 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1210 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1211 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1212 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1213 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1214 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1216 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1217 int steel_position = (x == -1 && y == -1 ? 0 :
1218 x == lev_fieldx && y == -1 ? 1 :
1219 x == -1 && y == lev_fieldy ? 2 :
1220 x == lev_fieldx && y == lev_fieldy ? 3 :
1221 x == -1 || x == lev_fieldx ? 4 :
1222 y == -1 || y == lev_fieldy ? 5 : 6);
1224 return border[steel_position][steel_type];
1227 void DrawScreenElement(int x, int y, int element)
1229 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1230 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1233 void DrawLevelElement(int x, int y, int element)
1235 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1236 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1239 void DrawScreenField(int x, int y)
1241 int lx = LEVELX(x), ly = LEVELY(y);
1242 int element, content;
1244 if (!IN_LEV_FIELD(lx, ly))
1246 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1249 element = getBorderElement(lx, ly);
1251 DrawScreenElement(x, y, element);
1255 element = Feld[lx][ly];
1256 content = Store[lx][ly];
1258 if (IS_MOVING(lx, ly))
1260 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1261 boolean cut_mode = NO_CUTTING;
1263 if (element == EL_QUICKSAND_EMPTYING ||
1264 element == EL_MAGIC_WALL_EMPTYING ||
1265 element == EL_BD_MAGIC_WALL_EMPTYING ||
1266 element == EL_AMOEBA_DROPPING)
1267 cut_mode = CUT_ABOVE;
1268 else if (element == EL_QUICKSAND_FILLING ||
1269 element == EL_MAGIC_WALL_FILLING ||
1270 element == EL_BD_MAGIC_WALL_FILLING)
1271 cut_mode = CUT_BELOW;
1273 if (cut_mode == CUT_ABOVE)
1274 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1276 DrawScreenElement(x, y, EL_EMPTY);
1279 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1280 else if (cut_mode == NO_CUTTING)
1281 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1283 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1285 if (content == EL_ACID)
1287 int dir = MovDir[lx][ly];
1288 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1289 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1291 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1294 else if (IS_BLOCKED(lx, ly))
1299 boolean cut_mode = NO_CUTTING;
1300 int element_old, content_old;
1302 Blocked2Moving(lx, ly, &oldx, &oldy);
1305 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1306 MovDir[oldx][oldy] == MV_RIGHT);
1308 element_old = Feld[oldx][oldy];
1309 content_old = Store[oldx][oldy];
1311 if (element_old == EL_QUICKSAND_EMPTYING ||
1312 element_old == EL_MAGIC_WALL_EMPTYING ||
1313 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1314 element_old == EL_AMOEBA_DROPPING)
1315 cut_mode = CUT_ABOVE;
1317 DrawScreenElement(x, y, EL_EMPTY);
1320 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1322 else if (cut_mode == NO_CUTTING)
1323 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1326 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1329 else if (IS_DRAWABLE(element))
1330 DrawScreenElement(x, y, element);
1332 DrawScreenElement(x, y, EL_EMPTY);
1335 void DrawLevelField(int x, int y)
1337 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1338 DrawScreenField(SCREENX(x), SCREENY(y));
1339 else if (IS_MOVING(x, y))
1343 Moving2Blocked(x, y, &newx, &newy);
1344 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1345 DrawScreenField(SCREENX(newx), SCREENY(newy));
1347 else if (IS_BLOCKED(x, y))
1351 Blocked2Moving(x, y, &oldx, &oldy);
1352 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1353 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1357 void DrawMiniElement(int x, int y, int element)
1361 graphic = el2edimg(element);
1362 DrawMiniGraphic(x, y, graphic);
1365 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1367 int x = sx + scroll_x, y = sy + scroll_y;
1369 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1370 DrawMiniElement(sx, sy, EL_EMPTY);
1371 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1372 DrawMiniElement(sx, sy, Feld[x][y]);
1374 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1377 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1378 int x, int y, int xsize, int ysize, int font_nr)
1380 int font_width = getFontWidth(font_nr);
1381 int font_height = getFontHeight(font_nr);
1382 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1385 int dst_x = SX + startx + x * font_width;
1386 int dst_y = SY + starty + y * font_height;
1387 int width = graphic_info[graphic].width;
1388 int height = graphic_info[graphic].height;
1389 int inner_width = MAX(width - 2 * font_width, font_width);
1390 int inner_height = MAX(height - 2 * font_height, font_height);
1391 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1392 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1393 boolean draw_masked = graphic_info[graphic].draw_masked;
1395 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1397 if (src_bitmap == NULL || width < font_width || height < font_height)
1399 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1403 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1404 inner_sx + (x - 1) * font_width % inner_width);
1405 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1406 inner_sy + (y - 1) * font_height % inner_height);
1410 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1411 dst_x - src_x, dst_y - src_y);
1412 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1416 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1420 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1422 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1423 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1424 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1425 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1426 boolean no_delay = (tape.warp_forward);
1427 unsigned long anim_delay = 0;
1428 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1429 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1430 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1431 int font_width = getFontWidth(font_nr);
1432 int font_height = getFontHeight(font_nr);
1433 int max_xsize = level.envelope[envelope_nr].xsize;
1434 int max_ysize = level.envelope[envelope_nr].ysize;
1435 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1436 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1437 int xend = max_xsize;
1438 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1439 int xstep = (xstart < xend ? 1 : 0);
1440 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1443 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1445 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1446 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1447 int sx = (SXSIZE - xsize * font_width) / 2;
1448 int sy = (SYSIZE - ysize * font_height) / 2;
1451 SetDrawtoField(DRAW_BUFFERED);
1453 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1455 SetDrawtoField(DRAW_BACKBUFFER);
1457 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1458 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1460 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1461 level.envelope[envelope_nr].text, font_nr, max_xsize,
1462 xsize - 2, ysize - 2, mask_mode);
1464 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1467 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1471 void ShowEnvelope(int envelope_nr)
1473 int element = EL_ENVELOPE_1 + envelope_nr;
1474 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1475 int sound_opening = element_info[element].sound[ACTION_OPENING];
1476 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1477 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1478 boolean no_delay = (tape.warp_forward);
1479 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1480 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1481 int anim_mode = graphic_info[graphic].anim_mode;
1482 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1483 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1485 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1487 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1489 if (anim_mode == ANIM_DEFAULT)
1490 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1492 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1495 Delay(wait_delay_value);
1497 WaitForEventToContinue();
1499 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1501 if (anim_mode != ANIM_NONE)
1502 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1504 if (anim_mode == ANIM_DEFAULT)
1505 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1507 game.envelope_active = FALSE;
1509 SetDrawtoField(DRAW_BUFFERED);
1511 redraw_mask |= REDRAW_FIELD;
1515 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1520 int width_mult, width_div;
1521 int height_mult, height_div;
1529 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1530 5 - log_2(tilesize));
1531 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1532 int width_mult = offset_calc[offset_calc_pos].width_mult;
1533 int width_div = offset_calc[offset_calc_pos].width_div;
1534 int height_mult = offset_calc[offset_calc_pos].height_mult;
1535 int height_div = offset_calc[offset_calc_pos].height_div;
1536 int mini_startx = src_bitmap->width * width_mult / width_div;
1537 int mini_starty = src_bitmap->height * height_mult / height_div;
1538 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1539 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1541 *bitmap = src_bitmap;
1546 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1550 int graphic = el2preimg(element);
1552 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1553 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1560 SetDrawBackgroundMask(REDRAW_NONE);
1563 for (x = BX1; x <= BX2; x++)
1564 for (y = BY1; y <= BY2; y++)
1565 DrawScreenField(x, y);
1567 redraw_mask |= REDRAW_FIELD;
1570 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1574 for (x = 0; x < size_x; x++)
1575 for (y = 0; y < size_y; y++)
1576 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1578 redraw_mask |= REDRAW_FIELD;
1581 static void DrawPreviewLevelExt(int from_x, int from_y)
1583 boolean show_level_border = (BorderElement != EL_EMPTY);
1584 int dst_x = preview.x;
1585 int dst_y = preview.y;
1586 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1587 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1588 int tile_size = preview.tile_size;
1589 int preview_width = preview.xsize * tile_size;
1590 int preview_height = preview.ysize * tile_size;
1591 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1592 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1595 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1597 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1598 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1600 for (x = 0; x < real_preview_xsize; x++)
1602 for (y = 0; y < real_preview_ysize; y++)
1604 int lx = from_x + x + (show_level_border ? -1 : 0);
1605 int ly = from_y + y + (show_level_border ? -1 : 0);
1606 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1607 getBorderElement(lx, ly));
1609 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1610 element, tile_size);
1614 redraw_mask |= REDRAW_MICROLEVEL;
1617 #define MICROLABEL_EMPTY 0
1618 #define MICROLABEL_LEVEL_NAME 1
1619 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1620 #define MICROLABEL_LEVEL_AUTHOR 3
1621 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1622 #define MICROLABEL_IMPORTED_FROM 5
1623 #define MICROLABEL_IMPORTED_BY_HEAD 6
1624 #define MICROLABEL_IMPORTED_BY 7
1626 static void DrawPreviewLevelLabelExt(int mode)
1628 char label_text[MAX_OUTPUT_LINESIZE + 1];
1629 int max_len_label_text;
1630 int font_nr = FONT_TEXT_2;
1633 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1634 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1635 mode == MICROLABEL_IMPORTED_BY_HEAD)
1636 font_nr = FONT_TEXT_3;
1638 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1640 for (i = 0; i < max_len_label_text; i++)
1641 label_text[i] = ' ';
1642 label_text[max_len_label_text] = '\0';
1644 if (strlen(label_text) > 0)
1646 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1647 int lypos = MICROLABEL2_YPOS;
1649 DrawText(lxpos, lypos, label_text, font_nr);
1653 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1654 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1655 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1656 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1657 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1658 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1659 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1660 max_len_label_text);
1661 label_text[max_len_label_text] = '\0';
1663 if (strlen(label_text) > 0)
1665 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1666 int lypos = MICROLABEL2_YPOS;
1668 DrawText(lxpos, lypos, label_text, font_nr);
1671 redraw_mask |= REDRAW_MICROLEVEL;
1674 void DrawPreviewLevel(boolean restart)
1676 static unsigned long scroll_delay = 0;
1677 static unsigned long label_delay = 0;
1678 static int from_x, from_y, scroll_direction;
1679 static int label_state, label_counter;
1680 unsigned long scroll_delay_value = preview.step_delay;
1681 boolean show_level_border = (BorderElement != EL_EMPTY);
1682 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1683 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1684 int last_game_status = game_status; /* save current game status */
1686 /* force PREVIEW font on preview level */
1687 game_status = GAME_MODE_PSEUDO_PREVIEW;
1691 from_x = from_y = 0;
1692 scroll_direction = MV_RIGHT;
1696 DrawPreviewLevelExt(from_x, from_y);
1697 DrawPreviewLevelLabelExt(label_state);
1699 /* initialize delay counters */
1700 DelayReached(&scroll_delay, 0);
1701 DelayReached(&label_delay, 0);
1703 if (leveldir_current->name)
1705 char label_text[MAX_OUTPUT_LINESIZE + 1];
1706 int font_nr = FONT_TEXT_1;
1707 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1710 strncpy(label_text, leveldir_current->name, max_len_label_text);
1711 label_text[max_len_label_text] = '\0';
1713 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1714 lypos = SY + MICROLABEL1_YPOS;
1716 DrawText(lxpos, lypos, label_text, font_nr);
1719 game_status = last_game_status; /* restore current game status */
1724 /* scroll preview level, if needed */
1725 if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1726 DelayReached(&scroll_delay, scroll_delay_value))
1728 switch (scroll_direction)
1733 from_x -= preview.step_offset;
1734 from_x = (from_x < 0 ? 0 : from_x);
1737 scroll_direction = MV_UP;
1741 if (from_x < level_xsize - preview.xsize)
1743 from_x += preview.step_offset;
1744 from_x = (from_x > level_xsize - preview.xsize ?
1745 level_xsize - preview.xsize : from_x);
1748 scroll_direction = MV_DOWN;
1754 from_y -= preview.step_offset;
1755 from_y = (from_y < 0 ? 0 : from_y);
1758 scroll_direction = MV_RIGHT;
1762 if (from_y < level_ysize - preview.ysize)
1764 from_y += preview.step_offset;
1765 from_y = (from_y > level_ysize - preview.ysize ?
1766 level_ysize - preview.ysize : from_y);
1769 scroll_direction = MV_LEFT;
1776 DrawPreviewLevelExt(from_x, from_y);
1779 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1780 /* redraw micro level label, if needed */
1781 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1782 !strEqual(level.author, ANONYMOUS_NAME) &&
1783 !strEqual(level.author, leveldir_current->name) &&
1784 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1786 int max_label_counter = 23;
1788 if (leveldir_current->imported_from != NULL &&
1789 strlen(leveldir_current->imported_from) > 0)
1790 max_label_counter += 14;
1791 if (leveldir_current->imported_by != NULL &&
1792 strlen(leveldir_current->imported_by) > 0)
1793 max_label_counter += 14;
1795 label_counter = (label_counter + 1) % max_label_counter;
1796 label_state = (label_counter >= 0 && label_counter <= 7 ?
1797 MICROLABEL_LEVEL_NAME :
1798 label_counter >= 9 && label_counter <= 12 ?
1799 MICROLABEL_LEVEL_AUTHOR_HEAD :
1800 label_counter >= 14 && label_counter <= 21 ?
1801 MICROLABEL_LEVEL_AUTHOR :
1802 label_counter >= 23 && label_counter <= 26 ?
1803 MICROLABEL_IMPORTED_FROM_HEAD :
1804 label_counter >= 28 && label_counter <= 35 ?
1805 MICROLABEL_IMPORTED_FROM :
1806 label_counter >= 37 && label_counter <= 40 ?
1807 MICROLABEL_IMPORTED_BY_HEAD :
1808 label_counter >= 42 && label_counter <= 49 ?
1809 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1811 if (leveldir_current->imported_from == NULL &&
1812 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1813 label_state == MICROLABEL_IMPORTED_FROM))
1814 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1815 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1817 DrawPreviewLevelLabelExt(label_state);
1820 game_status = last_game_status; /* restore current game status */
1823 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1824 int graphic, int sync_frame, int mask_mode)
1826 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1828 if (mask_mode == USE_MASKING)
1829 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1831 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1834 inline void DrawGraphicAnimation(int x, int y, int graphic)
1836 int lx = LEVELX(x), ly = LEVELY(y);
1838 if (!IN_SCR_FIELD(x, y))
1841 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1842 graphic, GfxFrame[lx][ly], NO_MASKING);
1843 MarkTileDirty(x, y);
1846 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1848 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1851 void DrawLevelElementAnimation(int x, int y, int element)
1853 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1855 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1858 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1860 int sx = SCREENX(x), sy = SCREENY(y);
1862 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1865 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1868 DrawGraphicAnimation(sx, sy, graphic);
1871 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1872 DrawLevelFieldCrumbledSand(x, y);
1874 if (GFX_CRUMBLED(Feld[x][y]))
1875 DrawLevelFieldCrumbledSand(x, y);
1879 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1881 int sx = SCREENX(x), sy = SCREENY(y);
1884 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1887 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1889 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1892 DrawGraphicAnimation(sx, sy, graphic);
1894 if (GFX_CRUMBLED(element))
1895 DrawLevelFieldCrumbledSand(x, y);
1898 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1900 if (player->use_murphy)
1902 /* this works only because currently only one player can be "murphy" ... */
1903 static int last_horizontal_dir = MV_LEFT;
1904 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1906 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1907 last_horizontal_dir = move_dir;
1909 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1911 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1913 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1919 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1922 static boolean equalGraphics(int graphic1, int graphic2)
1924 struct GraphicInfo *g1 = &graphic_info[graphic1];
1925 struct GraphicInfo *g2 = &graphic_info[graphic2];
1927 return (g1->bitmap == g2->bitmap &&
1928 g1->src_x == g2->src_x &&
1929 g1->src_y == g2->src_y &&
1930 g1->anim_frames == g2->anim_frames &&
1931 g1->anim_delay == g2->anim_delay &&
1932 g1->anim_mode == g2->anim_mode);
1935 void DrawAllPlayers()
1939 for (i = 0; i < MAX_PLAYERS; i++)
1940 if (stored_player[i].active)
1941 DrawPlayer(&stored_player[i]);
1944 void DrawPlayerField(int x, int y)
1946 if (!IS_PLAYER(x, y))
1949 DrawPlayer(PLAYERINFO(x, y));
1952 void DrawPlayer(struct PlayerInfo *player)
1954 int jx = player->jx;
1955 int jy = player->jy;
1956 int move_dir = player->MovDir;
1957 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1958 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1959 int last_jx = (player->is_moving ? jx - dx : jx);
1960 int last_jy = (player->is_moving ? jy - dy : jy);
1961 int next_jx = jx + dx;
1962 int next_jy = jy + dy;
1963 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1964 boolean player_is_opaque = FALSE;
1965 int sx = SCREENX(jx), sy = SCREENY(jy);
1966 int sxx = 0, syy = 0;
1967 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1969 int action = ACTION_DEFAULT;
1970 int last_player_graphic = getPlayerGraphic(player, move_dir);
1971 int last_player_frame = player->Frame;
1975 /* GfxElement[][] is set to the element the player is digging or collecting;
1976 remove also for off-screen player if the player is not moving anymore */
1977 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1978 GfxElement[jx][jy] = EL_UNDEFINED;
1981 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1985 if (!IN_LEV_FIELD(jx, jy))
1987 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1988 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1989 printf("DrawPlayerField(): This should never happen!\n");
1994 if (element == EL_EXPLOSION)
1997 action = (player->is_pushing ? ACTION_PUSHING :
1998 player->is_digging ? ACTION_DIGGING :
1999 player->is_collecting ? ACTION_COLLECTING :
2000 player->is_moving ? ACTION_MOVING :
2001 player->is_snapping ? ACTION_SNAPPING :
2002 player->is_dropping ? ACTION_DROPPING :
2003 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2006 if (player->is_waiting)
2007 move_dir = player->dir_waiting;
2010 InitPlayerGfxAnimation(player, action, move_dir);
2012 /* ----------------------------------------------------------------------- */
2013 /* draw things in the field the player is leaving, if needed */
2014 /* ----------------------------------------------------------------------- */
2016 if (player->is_moving)
2018 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2020 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2022 if (last_element == EL_DYNAMITE_ACTIVE ||
2023 last_element == EL_EM_DYNAMITE_ACTIVE ||
2024 last_element == EL_SP_DISK_RED_ACTIVE)
2025 DrawDynamite(last_jx, last_jy);
2027 DrawLevelFieldThruMask(last_jx, last_jy);
2029 else if (last_element == EL_DYNAMITE_ACTIVE ||
2030 last_element == EL_EM_DYNAMITE_ACTIVE ||
2031 last_element == EL_SP_DISK_RED_ACTIVE)
2032 DrawDynamite(last_jx, last_jy);
2034 /* !!! this is not enough to prevent flickering of players which are
2035 moving next to each others without a free tile between them -- this
2036 can only be solved by drawing all players layer by layer (first the
2037 background, then the foreground etc.) !!! => TODO */
2038 else if (!IS_PLAYER(last_jx, last_jy))
2039 DrawLevelField(last_jx, last_jy);
2042 DrawLevelField(last_jx, last_jy);
2045 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2046 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2049 if (!IN_SCR_FIELD(sx, sy))
2052 if (setup.direct_draw)
2053 SetDrawtoField(DRAW_BUFFERED);
2055 /* ----------------------------------------------------------------------- */
2056 /* draw things behind the player, if needed */
2057 /* ----------------------------------------------------------------------- */
2060 DrawLevelElement(jx, jy, Back[jx][jy]);
2061 else if (IS_ACTIVE_BOMB(element))
2062 DrawLevelElement(jx, jy, EL_EMPTY);
2065 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2067 int old_element = GfxElement[jx][jy];
2068 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2069 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2071 if (GFX_CRUMBLED(old_element))
2072 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2074 DrawGraphic(sx, sy, old_graphic, frame);
2076 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2077 player_is_opaque = TRUE;
2081 GfxElement[jx][jy] = EL_UNDEFINED;
2083 /* make sure that pushed elements are drawn with correct frame rate */
2085 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2087 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2088 GfxFrame[jx][jy] = player->StepFrame;
2090 if (player->is_pushing && player->is_moving)
2091 GfxFrame[jx][jy] = player->StepFrame;
2094 DrawLevelField(jx, jy);
2098 /* ----------------------------------------------------------------------- */
2099 /* draw player himself */
2100 /* ----------------------------------------------------------------------- */
2102 graphic = getPlayerGraphic(player, move_dir);
2104 /* in the case of changed player action or direction, prevent the current
2105 animation frame from being restarted for identical animations */
2106 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2107 player->Frame = last_player_frame;
2109 frame = getGraphicAnimationFrame(graphic, player->Frame);
2113 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2114 sxx = player->GfxPos;
2116 syy = player->GfxPos;
2119 if (!setup.soft_scrolling && ScreenMovPos)
2122 if (player_is_opaque)
2123 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2125 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2127 if (SHIELD_ON(player))
2129 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2130 IMG_SHIELD_NORMAL_ACTIVE);
2131 int frame = getGraphicAnimationFrame(graphic, -1);
2133 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2136 /* ----------------------------------------------------------------------- */
2137 /* draw things the player is pushing, if needed */
2138 /* ----------------------------------------------------------------------- */
2141 printf("::: %d, %d [%d, %d] [%d]\n",
2142 player->is_pushing, player_is_moving, player->GfxAction,
2143 player->is_moving, player_is_moving);
2147 if (player->is_pushing && player->is_moving)
2149 int px = SCREENX(jx), py = SCREENY(jy);
2150 int pxx = (TILEX - ABS(sxx)) * dx;
2151 int pyy = (TILEY - ABS(syy)) * dy;
2152 int gfx_frame = GfxFrame[jx][jy];
2158 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2160 element = Feld[next_jx][next_jy];
2161 gfx_frame = GfxFrame[next_jx][next_jy];
2164 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2167 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2168 frame = getGraphicAnimationFrame(graphic, sync_frame);
2170 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2173 /* draw background element under pushed element (like the Sokoban field) */
2174 if (Back[next_jx][next_jy])
2175 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2177 /* masked drawing is needed for EMC style (double) movement graphics */
2178 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2182 /* ----------------------------------------------------------------------- */
2183 /* draw things in front of player (active dynamite or dynabombs) */
2184 /* ----------------------------------------------------------------------- */
2186 if (IS_ACTIVE_BOMB(element))
2188 graphic = el2img(element);
2189 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2191 if (game.emulation == EMU_SUPAPLEX)
2192 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2194 DrawGraphicThruMask(sx, sy, graphic, frame);
2197 if (player_is_moving && last_element == EL_EXPLOSION)
2199 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2200 GfxElement[last_jx][last_jy] : EL_EMPTY);
2201 int graphic = el_act2img(element, ACTION_EXPLODING);
2202 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2203 int phase = ExplodePhase[last_jx][last_jy] - 1;
2204 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2207 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2210 /* ----------------------------------------------------------------------- */
2211 /* draw elements the player is just walking/passing through/under */
2212 /* ----------------------------------------------------------------------- */
2214 if (player_is_moving)
2216 /* handle the field the player is leaving ... */
2217 if (IS_ACCESSIBLE_INSIDE(last_element))
2218 DrawLevelField(last_jx, last_jy);
2219 else if (IS_ACCESSIBLE_UNDER(last_element))
2220 DrawLevelFieldThruMask(last_jx, last_jy);
2223 /* do not redraw accessible elements if the player is just pushing them */
2224 if (!player_is_moving || !player->is_pushing)
2226 /* ... and the field the player is entering */
2227 if (IS_ACCESSIBLE_INSIDE(element))
2228 DrawLevelField(jx, jy);
2229 else if (IS_ACCESSIBLE_UNDER(element))
2230 DrawLevelFieldThruMask(jx, jy);
2233 if (setup.direct_draw)
2235 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2236 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2237 int x_size = TILEX * (1 + ABS(jx - last_jx));
2238 int y_size = TILEY * (1 + ABS(jy - last_jy));
2240 BlitBitmap(drawto_field, window,
2241 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2242 SetDrawtoField(DRAW_DIRECT);
2245 MarkTileDirty(sx, sy);
2248 /* ------------------------------------------------------------------------- */
2250 void WaitForEventToContinue()
2252 boolean still_wait = TRUE;
2254 /* simulate releasing mouse button over last gadget, if still pressed */
2256 HandleGadgets(-1, -1, 0);
2258 button_status = MB_RELEASED;
2270 case EVENT_BUTTONPRESS:
2271 case EVENT_KEYPRESS:
2275 case EVENT_KEYRELEASE:
2276 ClearPlayerAction();
2280 HandleOtherEvents(&event);
2284 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2291 /* don't eat all CPU time */
2296 #define MAX_REQUEST_LINES 13
2297 #define MAX_REQUEST_LINE_FONT1_LEN 7
2298 #define MAX_REQUEST_LINE_FONT2_LEN 10
2300 boolean Request(char *text, unsigned int req_state)
2302 int mx, my, ty, result = -1;
2303 unsigned int old_door_state;
2304 int last_game_status = game_status; /* save current game status */
2305 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2306 int font_nr = FONT_TEXT_2;
2307 int max_word_len = 0;
2310 for (text_ptr = text; *text_ptr; text_ptr++)
2312 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2314 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2316 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2317 font_nr = FONT_LEVEL_NUMBER;
2323 if (game_status == GAME_MODE_PLAYING &&
2324 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2325 BlitScreenToBitmap_EM(backbuffer);
2327 /* disable deactivated drawing when quick-loading level tape recording */
2328 if (tape.playing && tape.deactivate_display)
2329 TapeDeactivateDisplayOff(TRUE);
2331 SetMouseCursor(CURSOR_DEFAULT);
2333 #if defined(NETWORK_AVALIABLE)
2334 /* pause network game while waiting for request to answer */
2335 if (options.network &&
2336 game_status == GAME_MODE_PLAYING &&
2337 req_state & REQUEST_WAIT_FOR_INPUT)
2338 SendToServer_PausePlaying();
2341 old_door_state = GetDoorState();
2343 /* simulate releasing mouse button over last gadget, if still pressed */
2345 HandleGadgets(-1, -1, 0);
2349 if (old_door_state & DOOR_OPEN_1)
2351 CloseDoor(DOOR_CLOSE_1);
2353 /* save old door content */
2354 BlitBitmap(bitmap_db_door, bitmap_db_door,
2355 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2356 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2360 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2363 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2365 /* clear door drawing field */
2366 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2368 /* force DOOR font on preview level */
2369 game_status = GAME_MODE_PSEUDO_DOOR;
2371 /* write text for request */
2372 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2374 char text_line[max_request_line_len + 1];
2380 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2383 if (!tc || tc == ' ')
2394 strncpy(text_line, text, tl);
2397 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2398 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2399 text_line, font_nr);
2401 text += tl + (tc == ' ' ? 1 : 0);
2404 game_status = last_game_status; /* restore current game status */
2406 if (req_state & REQ_ASK)
2408 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2409 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2411 else if (req_state & REQ_CONFIRM)
2413 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2415 else if (req_state & REQ_PLAYER)
2417 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2418 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2419 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2420 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2423 /* copy request gadgets to door backbuffer */
2424 BlitBitmap(drawto, bitmap_db_door,
2425 DX, DY, DXSIZE, DYSIZE,
2426 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2428 OpenDoor(DOOR_OPEN_1);
2430 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2432 if (game_status == GAME_MODE_PLAYING)
2434 SetPanelBackground();
2435 SetDrawBackgroundMask(REDRAW_DOOR_1);
2439 SetDrawBackgroundMask(REDRAW_FIELD);
2445 if (game_status != GAME_MODE_MAIN)
2448 button_status = MB_RELEASED;
2450 request_gadget_id = -1;
2452 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2464 case EVENT_BUTTONPRESS:
2465 case EVENT_BUTTONRELEASE:
2466 case EVENT_MOTIONNOTIFY:
2468 if (event.type == EVENT_MOTIONNOTIFY)
2470 if (!PointerInWindow(window))
2471 continue; /* window and pointer are on different screens */
2476 motion_status = TRUE;
2477 mx = ((MotionEvent *) &event)->x;
2478 my = ((MotionEvent *) &event)->y;
2482 motion_status = FALSE;
2483 mx = ((ButtonEvent *) &event)->x;
2484 my = ((ButtonEvent *) &event)->y;
2485 if (event.type == EVENT_BUTTONPRESS)
2486 button_status = ((ButtonEvent *) &event)->button;
2488 button_status = MB_RELEASED;
2491 /* this sets 'request_gadget_id' */
2492 HandleGadgets(mx, my, button_status);
2494 switch(request_gadget_id)
2496 case TOOL_CTRL_ID_YES:
2499 case TOOL_CTRL_ID_NO:
2502 case TOOL_CTRL_ID_CONFIRM:
2503 result = TRUE | FALSE;
2506 case TOOL_CTRL_ID_PLAYER_1:
2509 case TOOL_CTRL_ID_PLAYER_2:
2512 case TOOL_CTRL_ID_PLAYER_3:
2515 case TOOL_CTRL_ID_PLAYER_4:
2526 case EVENT_KEYPRESS:
2527 switch(GetEventKey((KeyEvent *)&event, TRUE))
2540 if (req_state & REQ_PLAYER)
2544 case EVENT_KEYRELEASE:
2545 ClearPlayerAction();
2549 HandleOtherEvents(&event);
2553 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2555 int joy = AnyJoystick();
2557 if (joy & JOY_BUTTON_1)
2559 else if (joy & JOY_BUTTON_2)
2565 /* don't eat all CPU time */
2569 if (game_status != GAME_MODE_MAIN)
2574 if (!(req_state & REQ_STAY_OPEN))
2576 CloseDoor(DOOR_CLOSE_1);
2578 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2579 (req_state & REQ_REOPEN))
2580 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2585 if (game_status == GAME_MODE_PLAYING)
2587 SetPanelBackground();
2588 SetDrawBackgroundMask(REDRAW_DOOR_1);
2592 SetDrawBackgroundMask(REDRAW_FIELD);
2595 #if defined(NETWORK_AVALIABLE)
2596 /* continue network game after request */
2597 if (options.network &&
2598 game_status == GAME_MODE_PLAYING &&
2599 req_state & REQUEST_WAIT_FOR_INPUT)
2600 SendToServer_ContinuePlaying();
2603 /* restore deactivated drawing when quick-loading level tape recording */
2604 if (tape.playing && tape.deactivate_display)
2605 TapeDeactivateDisplayOn();
2610 unsigned int OpenDoor(unsigned int door_state)
2612 if (door_state & DOOR_COPY_BACK)
2614 if (door_state & DOOR_OPEN_1)
2615 BlitBitmap(bitmap_db_door, bitmap_db_door,
2616 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2617 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2619 if (door_state & DOOR_OPEN_2)
2620 BlitBitmap(bitmap_db_door, bitmap_db_door,
2621 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2622 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2624 door_state &= ~DOOR_COPY_BACK;
2627 return MoveDoor(door_state);
2630 unsigned int CloseDoor(unsigned int door_state)
2632 unsigned int old_door_state = GetDoorState();
2634 if (!(door_state & DOOR_NO_COPY_BACK))
2636 if (old_door_state & DOOR_OPEN_1)
2637 BlitBitmap(backbuffer, bitmap_db_door,
2638 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2640 if (old_door_state & DOOR_OPEN_2)
2641 BlitBitmap(backbuffer, bitmap_db_door,
2642 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2644 door_state &= ~DOOR_NO_COPY_BACK;
2647 return MoveDoor(door_state);
2650 unsigned int GetDoorState()
2652 return MoveDoor(DOOR_GET_STATE);
2655 unsigned int SetDoorState(unsigned int door_state)
2657 return MoveDoor(door_state | DOOR_SET_STATE);
2660 unsigned int MoveDoor(unsigned int door_state)
2662 static int door1 = DOOR_OPEN_1;
2663 static int door2 = DOOR_CLOSE_2;
2664 unsigned long door_delay = 0;
2665 unsigned long door_delay_value;
2668 if (door_1.width < 0 || door_1.width > DXSIZE)
2669 door_1.width = DXSIZE;
2670 if (door_1.height < 0 || door_1.height > DYSIZE)
2671 door_1.height = DYSIZE;
2672 if (door_2.width < 0 || door_2.width > VXSIZE)
2673 door_2.width = VXSIZE;
2674 if (door_2.height < 0 || door_2.height > VYSIZE)
2675 door_2.height = VYSIZE;
2677 if (door_state == DOOR_GET_STATE)
2678 return (door1 | door2);
2680 if (door_state & DOOR_SET_STATE)
2682 if (door_state & DOOR_ACTION_1)
2683 door1 = door_state & DOOR_ACTION_1;
2684 if (door_state & DOOR_ACTION_2)
2685 door2 = door_state & DOOR_ACTION_2;
2687 return (door1 | door2);
2690 if (!(door_state & DOOR_FORCE_REDRAW))
2692 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2693 door_state &= ~DOOR_OPEN_1;
2694 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2695 door_state &= ~DOOR_CLOSE_1;
2696 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2697 door_state &= ~DOOR_OPEN_2;
2698 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2699 door_state &= ~DOOR_CLOSE_2;
2702 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2705 if (setup.quick_doors)
2707 stepsize = 20; /* must be choosen to always draw last frame */
2708 door_delay_value = 0;
2711 if (global.autoplay_leveldir)
2713 door_state |= DOOR_NO_DELAY;
2714 door_state &= ~DOOR_CLOSE_ALL;
2717 if (door_state & DOOR_ACTION)
2719 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2720 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2721 boolean door_1_done = (!handle_door_1);
2722 boolean door_2_done = (!handle_door_2);
2723 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2724 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2725 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2726 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2727 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2728 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2729 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2730 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2731 int door_skip = max_door_size - door_size;
2733 int end = door_size;
2735 int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
2739 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2741 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2745 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2747 /* opening door sound has priority over simultaneously closing door */
2748 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2749 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2750 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2751 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2754 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2757 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2758 GC gc = bitmap->stored_clip_gc;
2760 if (door_state & DOOR_ACTION_1)
2762 int a = MIN(x * door_1.step_offset, end);
2763 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2764 int i = p + door_skip;
2766 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2768 BlitBitmap(bitmap_db_door, drawto,
2769 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2770 DXSIZE, DYSIZE, DX, DY);
2774 BlitBitmap(bitmap_db_door, drawto,
2775 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2776 DXSIZE, DYSIZE - p / 2, DX, DY);
2778 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2781 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2783 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2784 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2785 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2786 int dst2_x = DX, dst2_y = DY;
2787 int width = i, height = DYSIZE;
2789 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2790 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2793 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2794 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2797 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2799 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2800 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2801 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2802 int dst2_x = DX, dst2_y = DY;
2803 int width = DXSIZE, height = i;
2805 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2806 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2809 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2810 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2813 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2815 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2817 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2818 BlitBitmapMasked(bitmap, drawto,
2819 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2820 DX + DXSIZE - i, DY + j);
2821 BlitBitmapMasked(bitmap, drawto,
2822 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2823 DX + DXSIZE - i, DY + 140 + j);
2824 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2825 DY - (DOOR_GFX_PAGEY1 + j));
2826 BlitBitmapMasked(bitmap, drawto,
2827 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2829 BlitBitmapMasked(bitmap, drawto,
2830 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2833 BlitBitmapMasked(bitmap, drawto,
2834 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2836 BlitBitmapMasked(bitmap, drawto,
2837 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2839 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2840 BlitBitmapMasked(bitmap, drawto,
2841 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2842 DX + DXSIZE - i, DY + 77 + j);
2843 BlitBitmapMasked(bitmap, drawto,
2844 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2845 DX + DXSIZE - i, DY + 203 + j);
2848 redraw_mask |= REDRAW_DOOR_1;
2849 door_1_done = (a == end);
2852 if (door_state & DOOR_ACTION_2)
2855 int a = MIN(x * door_2.step_offset, door_size);
2856 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2857 int i = p + door_skip;
2859 int a = MIN(x * door_2.step_offset, door_size_2);
2860 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2861 int i = p + door_skip;
2864 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2866 BlitBitmap(bitmap_db_door, drawto,
2867 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2868 VXSIZE, VYSIZE, VX, VY);
2870 else if (x <= VYSIZE)
2872 BlitBitmap(bitmap_db_door, drawto,
2873 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2874 VXSIZE, VYSIZE - p / 2, VX, VY);
2876 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2879 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2881 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2882 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2883 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2884 int dst2_x = VX, dst2_y = VY;
2885 int width = i, height = VYSIZE;
2887 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2888 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2891 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2892 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2895 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2897 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2898 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2899 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2900 int dst2_x = VX, dst2_y = VY;
2901 int width = VXSIZE, height = i;
2903 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2904 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2907 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2908 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2911 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2913 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2915 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2916 BlitBitmapMasked(bitmap, drawto,
2917 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2918 VX + VXSIZE - i, VY + j);
2919 SetClipOrigin(bitmap, gc,
2920 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2921 BlitBitmapMasked(bitmap, drawto,
2922 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2925 BlitBitmapMasked(bitmap, drawto,
2926 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2927 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2928 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2929 BlitBitmapMasked(bitmap, drawto,
2930 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2932 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2935 redraw_mask |= REDRAW_DOOR_2;
2936 door_2_done = (a == VXSIZE);
2939 if (!(door_state & DOOR_NO_DELAY))
2943 if (game_status == GAME_MODE_MAIN)
2946 WaitUntilDelayReached(&door_delay, door_delay_value);
2951 if (door_state & DOOR_ACTION_1)
2952 door1 = door_state & DOOR_ACTION_1;
2953 if (door_state & DOOR_ACTION_2)
2954 door2 = door_state & DOOR_ACTION_2;
2956 return (door1 | door2);
2959 void DrawSpecialEditorDoor()
2961 /* draw bigger toolbox window */
2962 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2963 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2965 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2966 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2969 redraw_mask |= REDRAW_ALL;
2972 void UndrawSpecialEditorDoor()
2974 /* draw normal tape recorder window */
2975 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2976 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2979 redraw_mask |= REDRAW_ALL;
2983 /* ---------- new tool button stuff ---------------------------------------- */
2985 /* graphic position values for tool buttons */
2986 #define TOOL_BUTTON_YES_XPOS 2
2987 #define TOOL_BUTTON_YES_YPOS 250
2988 #define TOOL_BUTTON_YES_GFX_YPOS 0
2989 #define TOOL_BUTTON_YES_XSIZE 46
2990 #define TOOL_BUTTON_YES_YSIZE 28
2991 #define TOOL_BUTTON_NO_XPOS 52
2992 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2993 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2994 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2995 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2996 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2997 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2998 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2999 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3000 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3001 #define TOOL_BUTTON_PLAYER_XSIZE 30
3002 #define TOOL_BUTTON_PLAYER_YSIZE 30
3003 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3004 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3005 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3006 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3007 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3008 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3009 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3010 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3011 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3012 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3013 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3014 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3015 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3016 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3017 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3018 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3019 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3020 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3021 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3022 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3031 } toolbutton_info[NUM_TOOL_BUTTONS] =
3034 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3035 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3036 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3041 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3042 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3043 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3048 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3049 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3050 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3051 TOOL_CTRL_ID_CONFIRM,
3055 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3056 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3057 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3058 TOOL_CTRL_ID_PLAYER_1,
3062 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3063 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3064 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3065 TOOL_CTRL_ID_PLAYER_2,
3069 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3070 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3071 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3072 TOOL_CTRL_ID_PLAYER_3,
3076 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3077 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3078 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3079 TOOL_CTRL_ID_PLAYER_4,
3084 void CreateToolButtons()
3088 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3090 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3091 Bitmap *deco_bitmap = None;
3092 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3093 struct GadgetInfo *gi;
3094 unsigned long event_mask;
3095 int gd_xoffset, gd_yoffset;
3096 int gd_x1, gd_x2, gd_y;
3099 event_mask = GD_EVENT_RELEASED;
3101 gd_xoffset = toolbutton_info[i].xpos;
3102 gd_yoffset = toolbutton_info[i].ypos;
3103 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3104 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3105 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3107 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3109 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3111 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3112 &deco_bitmap, &deco_x, &deco_y);
3113 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3114 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3117 gi = CreateGadget(GDI_CUSTOM_ID, id,
3118 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3119 GDI_X, DX + toolbutton_info[i].x,
3120 GDI_Y, DY + toolbutton_info[i].y,
3121 GDI_WIDTH, toolbutton_info[i].width,
3122 GDI_HEIGHT, toolbutton_info[i].height,
3123 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3124 GDI_STATE, GD_BUTTON_UNPRESSED,
3125 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3126 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3127 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3128 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3129 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3130 GDI_DECORATION_SHIFTING, 1, 1,
3131 GDI_EVENT_MASK, event_mask,
3132 GDI_CALLBACK_ACTION, HandleToolButtons,
3136 Error(ERR_EXIT, "cannot create gadget");
3138 tool_gadget[id] = gi;
3142 void FreeToolButtons()
3146 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3147 FreeGadget(tool_gadget[i]);
3150 static void UnmapToolButtons()
3154 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3155 UnmapGadget(tool_gadget[i]);
3158 static void HandleToolButtons(struct GadgetInfo *gi)
3160 request_gadget_id = gi->custom_id;
3163 static struct Mapping_EM_to_RND_object
3166 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3167 boolean is_backside; /* backside of moving element */
3173 em_object_mapping_list[] =
3176 Xblank, TRUE, FALSE,
3180 Yacid_splash_eB, FALSE, FALSE,
3181 EL_ACID_SPLASH_RIGHT, -1, -1
3184 Yacid_splash_wB, FALSE, FALSE,
3185 EL_ACID_SPLASH_LEFT, -1, -1
3188 #ifdef EM_ENGINE_BAD_ROLL
3190 Xstone_force_e, FALSE, FALSE,
3191 EL_ROCK, -1, MV_BIT_RIGHT
3194 Xstone_force_w, FALSE, FALSE,
3195 EL_ROCK, -1, MV_BIT_LEFT
3198 Xnut_force_e, FALSE, FALSE,
3199 EL_NUT, -1, MV_BIT_RIGHT
3202 Xnut_force_w, FALSE, FALSE,
3203 EL_NUT, -1, MV_BIT_LEFT
3206 Xspring_force_e, FALSE, FALSE,
3207 EL_SPRING, -1, MV_BIT_RIGHT
3210 Xspring_force_w, FALSE, FALSE,
3211 EL_SPRING, -1, MV_BIT_LEFT
3214 Xemerald_force_e, FALSE, FALSE,
3215 EL_EMERALD, -1, MV_BIT_RIGHT
3218 Xemerald_force_w, FALSE, FALSE,
3219 EL_EMERALD, -1, MV_BIT_LEFT
3222 Xdiamond_force_e, FALSE, FALSE,
3223 EL_DIAMOND, -1, MV_BIT_RIGHT
3226 Xdiamond_force_w, FALSE, FALSE,
3227 EL_DIAMOND, -1, MV_BIT_LEFT
3230 Xbomb_force_e, FALSE, FALSE,
3231 EL_BOMB, -1, MV_BIT_RIGHT
3234 Xbomb_force_w, FALSE, FALSE,
3235 EL_BOMB, -1, MV_BIT_LEFT
3237 #endif /* EM_ENGINE_BAD_ROLL */
3240 Xstone, TRUE, FALSE,
3244 Xstone_pause, FALSE, FALSE,
3248 Xstone_fall, FALSE, FALSE,
3252 Ystone_s, FALSE, FALSE,
3253 EL_ROCK, ACTION_FALLING, -1
3256 Ystone_sB, FALSE, TRUE,
3257 EL_ROCK, ACTION_FALLING, -1
3260 Ystone_e, FALSE, FALSE,
3261 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3264 Ystone_eB, FALSE, TRUE,
3265 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3268 Ystone_w, FALSE, FALSE,
3269 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3272 Ystone_wB, FALSE, TRUE,
3273 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3280 Xnut_pause, FALSE, FALSE,
3284 Xnut_fall, FALSE, FALSE,
3288 Ynut_s, FALSE, FALSE,
3289 EL_NUT, ACTION_FALLING, -1
3292 Ynut_sB, FALSE, TRUE,
3293 EL_NUT, ACTION_FALLING, -1
3296 Ynut_e, FALSE, FALSE,
3297 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3300 Ynut_eB, FALSE, TRUE,
3301 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3304 Ynut_w, FALSE, FALSE,
3305 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3308 Ynut_wB, FALSE, TRUE,
3309 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3312 Xbug_n, TRUE, FALSE,
3316 Xbug_e, TRUE, FALSE,
3317 EL_BUG_RIGHT, -1, -1
3320 Xbug_s, TRUE, FALSE,
3324 Xbug_w, TRUE, FALSE,
3328 Xbug_gon, FALSE, FALSE,
3332 Xbug_goe, FALSE, FALSE,
3333 EL_BUG_RIGHT, -1, -1
3336 Xbug_gos, FALSE, FALSE,
3340 Xbug_gow, FALSE, FALSE,
3344 Ybug_n, FALSE, FALSE,
3345 EL_BUG, ACTION_MOVING, MV_BIT_UP
3348 Ybug_nB, FALSE, TRUE,
3349 EL_BUG, ACTION_MOVING, MV_BIT_UP
3352 Ybug_e, FALSE, FALSE,
3353 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3356 Ybug_eB, FALSE, TRUE,
3357 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3360 Ybug_s, FALSE, FALSE,
3361 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3364 Ybug_sB, FALSE, TRUE,
3365 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3368 Ybug_w, FALSE, FALSE,
3369 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3372 Ybug_wB, FALSE, TRUE,
3373 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3376 Ybug_w_n, FALSE, FALSE,
3377 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3380 Ybug_n_e, FALSE, FALSE,
3381 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3384 Ybug_e_s, FALSE, FALSE,
3385 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3388 Ybug_s_w, FALSE, FALSE,
3389 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3392 Ybug_e_n, FALSE, FALSE,
3393 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3396 Ybug_s_e, FALSE, FALSE,
3397 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3400 Ybug_w_s, FALSE, FALSE,
3401 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3404 Ybug_n_w, FALSE, FALSE,
3405 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3408 Ybug_stone, FALSE, FALSE,
3409 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3412 Ybug_spring, FALSE, FALSE,
3413 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3416 Xtank_n, TRUE, FALSE,
3417 EL_SPACESHIP_UP, -1, -1
3420 Xtank_e, TRUE, FALSE,
3421 EL_SPACESHIP_RIGHT, -1, -1
3424 Xtank_s, TRUE, FALSE,
3425 EL_SPACESHIP_DOWN, -1, -1
3428 Xtank_w, TRUE, FALSE,
3429 EL_SPACESHIP_LEFT, -1, -1
3432 Xtank_gon, FALSE, FALSE,
3433 EL_SPACESHIP_UP, -1, -1
3436 Xtank_goe, FALSE, FALSE,
3437 EL_SPACESHIP_RIGHT, -1, -1
3440 Xtank_gos, FALSE, FALSE,
3441 EL_SPACESHIP_DOWN, -1, -1
3444 Xtank_gow, FALSE, FALSE,
3445 EL_SPACESHIP_LEFT, -1, -1
3448 Ytank_n, FALSE, FALSE,
3449 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3452 Ytank_nB, FALSE, TRUE,
3453 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3456 Ytank_e, FALSE, FALSE,
3457 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3460 Ytank_eB, FALSE, TRUE,
3461 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3464 Ytank_s, FALSE, FALSE,
3465 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3468 Ytank_sB, FALSE, TRUE,
3469 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3472 Ytank_w, FALSE, FALSE,
3473 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3476 Ytank_wB, FALSE, TRUE,
3477 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3480 Ytank_w_n, FALSE, FALSE,
3481 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3484 Ytank_n_e, FALSE, FALSE,
3485 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3488 Ytank_e_s, FALSE, FALSE,
3489 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3492 Ytank_s_w, FALSE, FALSE,
3493 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3496 Ytank_e_n, FALSE, FALSE,
3497 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3500 Ytank_s_e, FALSE, FALSE,
3501 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3504 Ytank_w_s, FALSE, FALSE,
3505 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3508 Ytank_n_w, FALSE, FALSE,
3509 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3512 Ytank_stone, FALSE, FALSE,
3513 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3516 Ytank_spring, FALSE, FALSE,
3517 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3520 Xandroid, TRUE, FALSE,
3521 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3524 Xandroid_1_n, FALSE, FALSE,
3525 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3528 Xandroid_2_n, FALSE, FALSE,
3529 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3532 Xandroid_1_e, FALSE, FALSE,
3533 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3536 Xandroid_2_e, FALSE, FALSE,
3537 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3540 Xandroid_1_w, FALSE, FALSE,
3541 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3544 Xandroid_2_w, FALSE, FALSE,
3545 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3548 Xandroid_1_s, FALSE, FALSE,
3549 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3552 Xandroid_2_s, FALSE, FALSE,
3553 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3556 Yandroid_n, FALSE, FALSE,
3557 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3560 Yandroid_nB, FALSE, TRUE,
3561 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3564 Yandroid_ne, FALSE, FALSE,
3565 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3568 Yandroid_neB, FALSE, TRUE,
3569 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3572 Yandroid_e, FALSE, FALSE,
3573 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3576 Yandroid_eB, FALSE, TRUE,
3577 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3580 Yandroid_se, FALSE, FALSE,
3581 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3584 Yandroid_seB, FALSE, TRUE,
3585 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3588 Yandroid_s, FALSE, FALSE,
3589 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3592 Yandroid_sB, FALSE, TRUE,
3593 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3596 Yandroid_sw, FALSE, FALSE,
3597 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3600 Yandroid_swB, FALSE, TRUE,
3601 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3604 Yandroid_w, FALSE, FALSE,
3605 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3608 Yandroid_wB, FALSE, TRUE,
3609 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3612 Yandroid_nw, FALSE, FALSE,
3613 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3616 Yandroid_nwB, FALSE, TRUE,
3617 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3620 Xspring, TRUE, FALSE,
3624 Xspring_pause, FALSE, FALSE,
3628 Xspring_e, FALSE, FALSE,
3632 Xspring_w, FALSE, FALSE,
3636 Xspring_fall, FALSE, FALSE,
3640 Yspring_s, FALSE, FALSE,
3641 EL_SPRING, ACTION_FALLING, -1
3644 Yspring_sB, FALSE, TRUE,
3645 EL_SPRING, ACTION_FALLING, -1
3648 Yspring_e, FALSE, FALSE,
3649 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3652 Yspring_eB, FALSE, TRUE,
3653 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3656 Yspring_w, FALSE, FALSE,
3657 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3660 Yspring_wB, FALSE, TRUE,
3661 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3664 Yspring_kill_e, FALSE, FALSE,
3665 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3668 Yspring_kill_eB, FALSE, TRUE,
3669 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3672 Yspring_kill_w, FALSE, FALSE,
3673 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3676 Yspring_kill_wB, FALSE, TRUE,
3677 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3680 Xeater_n, TRUE, FALSE,
3681 EL_YAMYAM_UP, -1, -1
3684 Xeater_e, TRUE, FALSE,
3685 EL_YAMYAM_RIGHT, -1, -1
3688 Xeater_w, TRUE, FALSE,
3689 EL_YAMYAM_LEFT, -1, -1
3692 Xeater_s, TRUE, FALSE,
3693 EL_YAMYAM_DOWN, -1, -1
3696 Yeater_n, FALSE, FALSE,
3697 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3700 Yeater_nB, FALSE, TRUE,
3701 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3704 Yeater_e, FALSE, FALSE,
3705 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3708 Yeater_eB, FALSE, TRUE,
3709 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3712 Yeater_s, FALSE, FALSE,
3713 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3716 Yeater_sB, FALSE, TRUE,
3717 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3720 Yeater_w, FALSE, FALSE,
3721 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3724 Yeater_wB, FALSE, TRUE,
3725 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3728 Yeater_stone, FALSE, FALSE,
3729 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3732 Yeater_spring, FALSE, FALSE,
3733 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3736 Xalien, TRUE, FALSE,
3740 Xalien_pause, FALSE, FALSE,
3744 Yalien_n, FALSE, FALSE,
3745 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3748 Yalien_nB, FALSE, TRUE,
3749 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3752 Yalien_e, FALSE, FALSE,
3753 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3756 Yalien_eB, FALSE, TRUE,
3757 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3760 Yalien_s, FALSE, FALSE,
3761 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3764 Yalien_sB, FALSE, TRUE,
3765 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3768 Yalien_w, FALSE, FALSE,
3769 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3772 Yalien_wB, FALSE, TRUE,
3773 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3776 Yalien_stone, FALSE, FALSE,
3777 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3780 Yalien_spring, FALSE, FALSE,
3781 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3784 Xemerald, TRUE, FALSE,
3788 Xemerald_pause, FALSE, FALSE,
3792 Xemerald_fall, FALSE, FALSE,
3796 Xemerald_shine, FALSE, FALSE,
3797 EL_EMERALD, ACTION_TWINKLING, -1
3800 Yemerald_s, FALSE, FALSE,
3801 EL_EMERALD, ACTION_FALLING, -1
3804 Yemerald_sB, FALSE, TRUE,
3805 EL_EMERALD, ACTION_FALLING, -1
3808 Yemerald_e, FALSE, FALSE,
3809 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3812 Yemerald_eB, FALSE, TRUE,
3813 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3816 Yemerald_w, FALSE, FALSE,
3817 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3820 Yemerald_wB, FALSE, TRUE,
3821 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3824 Yemerald_eat, FALSE, FALSE,
3825 EL_EMERALD, ACTION_COLLECTING, -1
3828 Yemerald_stone, FALSE, FALSE,
3829 EL_NUT, ACTION_BREAKING, -1
3832 Xdiamond, TRUE, FALSE,
3836 Xdiamond_pause, FALSE, FALSE,
3840 Xdiamond_fall, FALSE, FALSE,
3844 Xdiamond_shine, FALSE, FALSE,
3845 EL_DIAMOND, ACTION_TWINKLING, -1
3848 Ydiamond_s, FALSE, FALSE,
3849 EL_DIAMOND, ACTION_FALLING, -1
3852 Ydiamond_sB, FALSE, TRUE,
3853 EL_DIAMOND, ACTION_FALLING, -1
3856 Ydiamond_e, FALSE, FALSE,
3857 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3860 Ydiamond_eB, FALSE, TRUE,
3861 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3864 Ydiamond_w, FALSE, FALSE,
3865 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3868 Ydiamond_wB, FALSE, TRUE,
3869 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3872 Ydiamond_eat, FALSE, FALSE,
3873 EL_DIAMOND, ACTION_COLLECTING, -1
3876 Ydiamond_stone, FALSE, FALSE,
3877 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3880 Xdrip_fall, TRUE, FALSE,
3881 EL_AMOEBA_DROP, -1, -1
3884 Xdrip_stretch, FALSE, FALSE,
3885 EL_AMOEBA_DROP, ACTION_FALLING, -1
3888 Xdrip_stretchB, FALSE, TRUE,
3889 EL_AMOEBA_DROP, ACTION_FALLING, -1
3892 Xdrip_eat, FALSE, FALSE,
3893 EL_AMOEBA_DROP, ACTION_GROWING, -1
3896 Ydrip_s1, FALSE, FALSE,
3897 EL_AMOEBA_DROP, ACTION_FALLING, -1
3900 Ydrip_s1B, FALSE, TRUE,
3901 EL_AMOEBA_DROP, ACTION_FALLING, -1
3904 Ydrip_s2, FALSE, FALSE,
3905 EL_AMOEBA_DROP, ACTION_FALLING, -1
3908 Ydrip_s2B, FALSE, TRUE,
3909 EL_AMOEBA_DROP, ACTION_FALLING, -1
3916 Xbomb_pause, FALSE, FALSE,
3920 Xbomb_fall, FALSE, FALSE,
3924 Ybomb_s, FALSE, FALSE,
3925 EL_BOMB, ACTION_FALLING, -1
3928 Ybomb_sB, FALSE, TRUE,
3929 EL_BOMB, ACTION_FALLING, -1
3932 Ybomb_e, FALSE, FALSE,
3933 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3936 Ybomb_eB, FALSE, TRUE,
3937 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3940 Ybomb_w, FALSE, FALSE,
3941 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3944 Ybomb_wB, FALSE, TRUE,
3945 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3948 Ybomb_eat, FALSE, FALSE,
3949 EL_BOMB, ACTION_ACTIVATING, -1
3952 Xballoon, TRUE, FALSE,
3956 Yballoon_n, FALSE, FALSE,
3957 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3960 Yballoon_nB, FALSE, TRUE,
3961 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3964 Yballoon_e, FALSE, FALSE,
3965 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3968 Yballoon_eB, FALSE, TRUE,
3969 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3972 Yballoon_s, FALSE, FALSE,
3973 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3976 Yballoon_sB, FALSE, TRUE,
3977 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3980 Yballoon_w, FALSE, FALSE,
3981 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3984 Yballoon_wB, FALSE, TRUE,
3985 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3988 Xgrass, TRUE, FALSE,
3989 EL_EMC_GRASS, -1, -1
3992 Ygrass_nB, FALSE, FALSE,
3993 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3996 Ygrass_eB, FALSE, FALSE,
3997 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4000 Ygrass_sB, FALSE, FALSE,
4001 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4004 Ygrass_wB, FALSE, FALSE,
4005 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4012 Ydirt_nB, FALSE, FALSE,
4013 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4016 Ydirt_eB, FALSE, FALSE,
4017 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4020 Ydirt_sB, FALSE, FALSE,
4021 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4024 Ydirt_wB, FALSE, FALSE,
4025 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4028 Xacid_ne, TRUE, FALSE,
4029 EL_ACID_POOL_TOPRIGHT, -1, -1
4032 Xacid_se, TRUE, FALSE,
4033 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4036 Xacid_s, TRUE, FALSE,
4037 EL_ACID_POOL_BOTTOM, -1, -1
4040 Xacid_sw, TRUE, FALSE,
4041 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4044 Xacid_nw, TRUE, FALSE,
4045 EL_ACID_POOL_TOPLEFT, -1, -1
4048 Xacid_1, TRUE, FALSE,
4052 Xacid_2, FALSE, FALSE,
4056 Xacid_3, FALSE, FALSE,
4060 Xacid_4, FALSE, FALSE,
4064 Xacid_5, FALSE, FALSE,
4068 Xacid_6, FALSE, FALSE,
4072 Xacid_7, FALSE, FALSE,
4076 Xacid_8, FALSE, FALSE,
4080 Xball_1, TRUE, FALSE,
4081 EL_EMC_MAGIC_BALL, -1, -1
4084 Xball_1B, FALSE, FALSE,
4085 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4088 Xball_2, FALSE, FALSE,
4089 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4092 Xball_2B, FALSE, FALSE,
4093 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4096 Yball_eat, FALSE, FALSE,
4097 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4100 Ykey_1_eat, FALSE, FALSE,
4101 EL_EM_KEY_1, ACTION_COLLECTING, -1
4104 Ykey_2_eat, FALSE, FALSE,
4105 EL_EM_KEY_2, ACTION_COLLECTING, -1
4108 Ykey_3_eat, FALSE, FALSE,
4109 EL_EM_KEY_3, ACTION_COLLECTING, -1
4112 Ykey_4_eat, FALSE, FALSE,
4113 EL_EM_KEY_4, ACTION_COLLECTING, -1
4116 Ykey_5_eat, FALSE, FALSE,
4117 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4120 Ykey_6_eat, FALSE, FALSE,
4121 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4124 Ykey_7_eat, FALSE, FALSE,
4125 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4128 Ykey_8_eat, FALSE, FALSE,
4129 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4132 Ylenses_eat, FALSE, FALSE,
4133 EL_EMC_LENSES, ACTION_COLLECTING, -1
4136 Ymagnify_eat, FALSE, FALSE,
4137 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4140 Ygrass_eat, FALSE, FALSE,
4141 EL_EMC_GRASS, ACTION_SNAPPING, -1
4144 Ydirt_eat, FALSE, FALSE,
4145 EL_SAND, ACTION_SNAPPING, -1
4148 Xgrow_ns, TRUE, FALSE,
4149 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4152 Ygrow_ns_eat, FALSE, FALSE,
4153 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4156 Xgrow_ew, TRUE, FALSE,
4157 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4160 Ygrow_ew_eat, FALSE, FALSE,
4161 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4164 Xwonderwall, TRUE, FALSE,
4165 EL_MAGIC_WALL, -1, -1
4168 XwonderwallB, FALSE, FALSE,
4169 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4172 Xamoeba_1, TRUE, FALSE,
4173 EL_AMOEBA_DRY, ACTION_OTHER, -1
4176 Xamoeba_2, FALSE, FALSE,
4177 EL_AMOEBA_DRY, ACTION_OTHER, -1
4180 Xamoeba_3, FALSE, FALSE,
4181 EL_AMOEBA_DRY, ACTION_OTHER, -1
4184 Xamoeba_4, FALSE, FALSE,
4185 EL_AMOEBA_DRY, ACTION_OTHER, -1
4188 Xamoeba_5, TRUE, FALSE,
4189 EL_AMOEBA_WET, ACTION_OTHER, -1
4192 Xamoeba_6, FALSE, FALSE,
4193 EL_AMOEBA_WET, ACTION_OTHER, -1
4196 Xamoeba_7, FALSE, FALSE,
4197 EL_AMOEBA_WET, ACTION_OTHER, -1
4200 Xamoeba_8, FALSE, FALSE,
4201 EL_AMOEBA_WET, ACTION_OTHER, -1
4204 Xdoor_1, TRUE, FALSE,
4205 EL_EM_GATE_1, -1, -1
4208 Xdoor_2, TRUE, FALSE,
4209 EL_EM_GATE_2, -1, -1
4212 Xdoor_3, TRUE, FALSE,
4213 EL_EM_GATE_3, -1, -1
4216 Xdoor_4, TRUE, FALSE,
4217 EL_EM_GATE_4, -1, -1
4220 Xdoor_5, TRUE, FALSE,
4221 EL_EMC_GATE_5, -1, -1
4224 Xdoor_6, TRUE, FALSE,
4225 EL_EMC_GATE_6, -1, -1
4228 Xdoor_7, TRUE, FALSE,
4229 EL_EMC_GATE_7, -1, -1
4232 Xdoor_8, TRUE, FALSE,
4233 EL_EMC_GATE_8, -1, -1
4236 Xkey_1, TRUE, FALSE,
4240 Xkey_2, TRUE, FALSE,
4244 Xkey_3, TRUE, FALSE,
4248 Xkey_4, TRUE, FALSE,
4252 Xkey_5, TRUE, FALSE,
4253 EL_EMC_KEY_5, -1, -1
4256 Xkey_6, TRUE, FALSE,
4257 EL_EMC_KEY_6, -1, -1
4260 Xkey_7, TRUE, FALSE,
4261 EL_EMC_KEY_7, -1, -1
4264 Xkey_8, TRUE, FALSE,
4265 EL_EMC_KEY_8, -1, -1
4268 Xwind_n, TRUE, FALSE,
4269 EL_BALLOON_SWITCH_UP, -1, -1
4272 Xwind_e, TRUE, FALSE,
4273 EL_BALLOON_SWITCH_RIGHT, -1, -1
4276 Xwind_s, TRUE, FALSE,
4277 EL_BALLOON_SWITCH_DOWN, -1, -1
4280 Xwind_w, TRUE, FALSE,
4281 EL_BALLOON_SWITCH_LEFT, -1, -1
4284 Xwind_nesw, TRUE, FALSE,
4285 EL_BALLOON_SWITCH_ANY, -1, -1
4288 Xwind_stop, TRUE, FALSE,
4289 EL_BALLOON_SWITCH_NONE, -1, -1
4293 EL_EXIT_CLOSED, -1, -1
4296 Xexit_1, TRUE, FALSE,
4297 EL_EXIT_OPEN, -1, -1
4300 Xexit_2, FALSE, FALSE,
4301 EL_EXIT_OPEN, -1, -1
4304 Xexit_3, FALSE, FALSE,
4305 EL_EXIT_OPEN, -1, -1
4308 Xdynamite, TRUE, FALSE,
4309 EL_EM_DYNAMITE, -1, -1
4312 Ydynamite_eat, FALSE, FALSE,
4313 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4316 Xdynamite_1, TRUE, FALSE,
4317 EL_EM_DYNAMITE_ACTIVE, -1, -1
4320 Xdynamite_2, FALSE, FALSE,
4321 EL_EM_DYNAMITE_ACTIVE, -1, -1
4324 Xdynamite_3, FALSE, FALSE,
4325 EL_EM_DYNAMITE_ACTIVE, -1, -1
4328 Xdynamite_4, FALSE, FALSE,
4329 EL_EM_DYNAMITE_ACTIVE, -1, -1
4332 Xbumper, TRUE, FALSE,
4333 EL_EMC_SPRING_BUMPER, -1, -1
4336 XbumperB, FALSE, FALSE,
4337 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4340 Xwheel, TRUE, FALSE,
4341 EL_ROBOT_WHEEL, -1, -1
4344 XwheelB, FALSE, FALSE,
4345 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4348 Xswitch, TRUE, FALSE,
4349 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4352 XswitchB, FALSE, FALSE,
4353 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4357 EL_QUICKSAND_EMPTY, -1, -1
4360 Xsand_stone, TRUE, FALSE,
4361 EL_QUICKSAND_FULL, -1, -1
4364 Xsand_stonein_1, FALSE, TRUE,
4365 EL_ROCK, ACTION_FILLING, -1
4368 Xsand_stonein_2, FALSE, TRUE,
4369 EL_ROCK, ACTION_FILLING, -1
4372 Xsand_stonein_3, FALSE, TRUE,
4373 EL_ROCK, ACTION_FILLING, -1
4376 Xsand_stonein_4, FALSE, TRUE,
4377 EL_ROCK, ACTION_FILLING, -1
4380 Xsand_stonesand_1, FALSE, FALSE,
4381 EL_QUICKSAND_FULL, -1, -1
4384 Xsand_stonesand_2, FALSE, FALSE,
4385 EL_QUICKSAND_FULL, -1, -1
4388 Xsand_stonesand_3, FALSE, FALSE,
4389 EL_QUICKSAND_FULL, -1, -1
4392 Xsand_stonesand_4, FALSE, FALSE,
4393 EL_QUICKSAND_FULL, -1, -1
4396 Xsand_stoneout_1, FALSE, FALSE,
4397 EL_ROCK, ACTION_EMPTYING, -1
4400 Xsand_stoneout_2, FALSE, FALSE,
4401 EL_ROCK, ACTION_EMPTYING, -1
4404 Xsand_sandstone_1, FALSE, FALSE,
4405 EL_QUICKSAND_FULL, -1, -1
4408 Xsand_sandstone_2, FALSE, FALSE,
4409 EL_QUICKSAND_FULL, -1, -1
4412 Xsand_sandstone_3, FALSE, FALSE,
4413 EL_QUICKSAND_FULL, -1, -1
4416 Xsand_sandstone_4, FALSE, FALSE,
4417 EL_QUICKSAND_FULL, -1, -1
4420 Xplant, TRUE, FALSE,
4421 EL_EMC_PLANT, -1, -1
4424 Yplant, FALSE, FALSE,
4425 EL_EMC_PLANT, -1, -1
4428 Xlenses, TRUE, FALSE,
4429 EL_EMC_LENSES, -1, -1
4432 Xmagnify, TRUE, FALSE,
4433 EL_EMC_MAGNIFIER, -1, -1
4436 Xdripper, TRUE, FALSE,
4437 EL_EMC_DRIPPER, -1, -1
4440 XdripperB, FALSE, FALSE,
4441 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4444 Xfake_blank, TRUE, FALSE,
4445 EL_INVISIBLE_WALL, -1, -1
4448 Xfake_blankB, FALSE, FALSE,
4449 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4452 Xfake_grass, TRUE, FALSE,
4453 EL_EMC_FAKE_GRASS, -1, -1
4456 Xfake_grassB, FALSE, FALSE,
4457 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4460 Xfake_door_1, TRUE, FALSE,
4461 EL_EM_GATE_1_GRAY, -1, -1
4464 Xfake_door_2, TRUE, FALSE,
4465 EL_EM_GATE_2_GRAY, -1, -1
4468 Xfake_door_3, TRUE, FALSE,
4469 EL_EM_GATE_3_GRAY, -1, -1
4472 Xfake_door_4, TRUE, FALSE,
4473 EL_EM_GATE_4_GRAY, -1, -1
4476 Xfake_door_5, TRUE, FALSE,
4477 EL_EMC_GATE_5_GRAY, -1, -1
4480 Xfake_door_6, TRUE, FALSE,
4481 EL_EMC_GATE_6_GRAY, -1, -1
4484 Xfake_door_7, TRUE, FALSE,
4485 EL_EMC_GATE_7_GRAY, -1, -1
4488 Xfake_door_8, TRUE, FALSE,
4489 EL_EMC_GATE_8_GRAY, -1, -1
4492 Xfake_acid_1, TRUE, FALSE,
4493 EL_EMC_FAKE_ACID, -1, -1
4496 Xfake_acid_2, FALSE, FALSE,
4497 EL_EMC_FAKE_ACID, -1, -1
4500 Xfake_acid_3, FALSE, FALSE,
4501 EL_EMC_FAKE_ACID, -1, -1
4504 Xfake_acid_4, FALSE, FALSE,
4505 EL_EMC_FAKE_ACID, -1, -1
4508 Xfake_acid_5, FALSE, FALSE,
4509 EL_EMC_FAKE_ACID, -1, -1
4512 Xfake_acid_6, FALSE, FALSE,
4513 EL_EMC_FAKE_ACID, -1, -1
4516 Xfake_acid_7, FALSE, FALSE,
4517 EL_EMC_FAKE_ACID, -1, -1
4520 Xfake_acid_8, FALSE, FALSE,
4521 EL_EMC_FAKE_ACID, -1, -1
4524 Xsteel_1, TRUE, FALSE,
4525 EL_STEELWALL, -1, -1
4528 Xsteel_2, TRUE, FALSE,
4529 EL_EMC_STEELWALL_2, -1, -1
4532 Xsteel_3, TRUE, FALSE,
4533 EL_EMC_STEELWALL_3, -1, -1
4536 Xsteel_4, TRUE, FALSE,
4537 EL_EMC_STEELWALL_4, -1, -1
4540 Xwall_1, TRUE, FALSE,
4544 Xwall_2, TRUE, FALSE,
4545 EL_EMC_WALL_14, -1, -1
4548 Xwall_3, TRUE, FALSE,
4549 EL_EMC_WALL_15, -1, -1
4552 Xwall_4, TRUE, FALSE,
4553 EL_EMC_WALL_16, -1, -1
4556 Xround_wall_1, TRUE, FALSE,
4557 EL_WALL_SLIPPERY, -1, -1
4560 Xround_wall_2, TRUE, FALSE,
4561 EL_EMC_WALL_SLIPPERY_2, -1, -1
4564 Xround_wall_3, TRUE, FALSE,
4565 EL_EMC_WALL_SLIPPERY_3, -1, -1
4568 Xround_wall_4, TRUE, FALSE,
4569 EL_EMC_WALL_SLIPPERY_4, -1, -1
4572 Xdecor_1, TRUE, FALSE,
4573 EL_EMC_WALL_8, -1, -1
4576 Xdecor_2, TRUE, FALSE,
4577 EL_EMC_WALL_6, -1, -1
4580 Xdecor_3, TRUE, FALSE,
4581 EL_EMC_WALL_4, -1, -1
4584 Xdecor_4, TRUE, FALSE,
4585 EL_EMC_WALL_7, -1, -1
4588 Xdecor_5, TRUE, FALSE,
4589 EL_EMC_WALL_5, -1, -1
4592 Xdecor_6, TRUE, FALSE,
4593 EL_EMC_WALL_9, -1, -1
4596 Xdecor_7, TRUE, FALSE,
4597 EL_EMC_WALL_10, -1, -1
4600 Xdecor_8, TRUE, FALSE,
4601 EL_EMC_WALL_1, -1, -1
4604 Xdecor_9, TRUE, FALSE,
4605 EL_EMC_WALL_2, -1, -1
4608 Xdecor_10, TRUE, FALSE,
4609 EL_EMC_WALL_3, -1, -1
4612 Xdecor_11, TRUE, FALSE,
4613 EL_EMC_WALL_11, -1, -1
4616 Xdecor_12, TRUE, FALSE,
4617 EL_EMC_WALL_12, -1, -1
4620 Xalpha_0, TRUE, FALSE,
4621 EL_CHAR('0'), -1, -1
4624 Xalpha_1, TRUE, FALSE,
4625 EL_CHAR('1'), -1, -1
4628 Xalpha_2, TRUE, FALSE,
4629 EL_CHAR('2'), -1, -1
4632 Xalpha_3, TRUE, FALSE,
4633 EL_CHAR('3'), -1, -1
4636 Xalpha_4, TRUE, FALSE,
4637 EL_CHAR('4'), -1, -1
4640 Xalpha_5, TRUE, FALSE,
4641 EL_CHAR('5'), -1, -1
4644 Xalpha_6, TRUE, FALSE,
4645 EL_CHAR('6'), -1, -1
4648 Xalpha_7, TRUE, FALSE,
4649 EL_CHAR('7'), -1, -1
4652 Xalpha_8, TRUE, FALSE,
4653 EL_CHAR('8'), -1, -1
4656 Xalpha_9, TRUE, FALSE,
4657 EL_CHAR('9'), -1, -1
4660 Xalpha_excla, TRUE, FALSE,
4661 EL_CHAR('!'), -1, -1
4664 Xalpha_quote, TRUE, FALSE,
4665 EL_CHAR('"'), -1, -1
4668 Xalpha_comma, TRUE, FALSE,
4669 EL_CHAR(','), -1, -1
4672 Xalpha_minus, TRUE, FALSE,
4673 EL_CHAR('-'), -1, -1
4676 Xalpha_perio, TRUE, FALSE,
4677 EL_CHAR('.'), -1, -1
4680 Xalpha_colon, TRUE, FALSE,
4681 EL_CHAR(':'), -1, -1
4684 Xalpha_quest, TRUE, FALSE,
4685 EL_CHAR('?'), -1, -1
4688 Xalpha_a, TRUE, FALSE,
4689 EL_CHAR('A'), -1, -1
4692 Xalpha_b, TRUE, FALSE,
4693 EL_CHAR('B'), -1, -1
4696 Xalpha_c, TRUE, FALSE,
4697 EL_CHAR('C'), -1, -1
4700 Xalpha_d, TRUE, FALSE,
4701 EL_CHAR('D'), -1, -1
4704 Xalpha_e, TRUE, FALSE,
4705 EL_CHAR('E'), -1, -1
4708 Xalpha_f, TRUE, FALSE,
4709 EL_CHAR('F'), -1, -1
4712 Xalpha_g, TRUE, FALSE,
4713 EL_CHAR('G'), -1, -1
4716 Xalpha_h, TRUE, FALSE,
4717 EL_CHAR('H'), -1, -1
4720 Xalpha_i, TRUE, FALSE,
4721 EL_CHAR('I'), -1, -1
4724 Xalpha_j, TRUE, FALSE,
4725 EL_CHAR('J'), -1, -1
4728 Xalpha_k, TRUE, FALSE,
4729 EL_CHAR('K'), -1, -1
4732 Xalpha_l, TRUE, FALSE,
4733 EL_CHAR('L'), -1, -1
4736 Xalpha_m, TRUE, FALSE,
4737 EL_CHAR('M'), -1, -1
4740 Xalpha_n, TRUE, FALSE,
4741 EL_CHAR('N'), -1, -1
4744 Xalpha_o, TRUE, FALSE,
4745 EL_CHAR('O'), -1, -1
4748 Xalpha_p, TRUE, FALSE,
4749 EL_CHAR('P'), -1, -1
4752 Xalpha_q, TRUE, FALSE,
4753 EL_CHAR('Q'), -1, -1
4756 Xalpha_r, TRUE, FALSE,
4757 EL_CHAR('R'), -1, -1
4760 Xalpha_s, TRUE, FALSE,
4761 EL_CHAR('S'), -1, -1
4764 Xalpha_t, TRUE, FALSE,
4765 EL_CHAR('T'), -1, -1
4768 Xalpha_u, TRUE, FALSE,
4769 EL_CHAR('U'), -1, -1
4772 Xalpha_v, TRUE, FALSE,
4773 EL_CHAR('V'), -1, -1
4776 Xalpha_w, TRUE, FALSE,
4777 EL_CHAR('W'), -1, -1
4780 Xalpha_x, TRUE, FALSE,
4781 EL_CHAR('X'), -1, -1
4784 Xalpha_y, TRUE, FALSE,
4785 EL_CHAR('Y'), -1, -1
4788 Xalpha_z, TRUE, FALSE,
4789 EL_CHAR('Z'), -1, -1
4792 Xalpha_arrow_e, TRUE, FALSE,
4793 EL_CHAR('>'), -1, -1
4796 Xalpha_arrow_w, TRUE, FALSE,
4797 EL_CHAR('<'), -1, -1
4800 Xalpha_copyr, TRUE, FALSE,
4801 EL_CHAR('©'), -1, -1
4805 Xboom_bug, FALSE, FALSE,
4806 EL_BUG, ACTION_EXPLODING, -1
4809 Xboom_bomb, FALSE, FALSE,
4810 EL_BOMB, ACTION_EXPLODING, -1
4813 Xboom_android, FALSE, FALSE,
4814 EL_EMC_ANDROID, ACTION_OTHER, -1
4817 Xboom_1, FALSE, FALSE,
4818 EL_DEFAULT, ACTION_EXPLODING, -1
4821 Xboom_2, FALSE, FALSE,
4822 EL_DEFAULT, ACTION_EXPLODING, -1
4825 Znormal, FALSE, FALSE,
4829 Zdynamite, FALSE, FALSE,
4833 Zplayer, FALSE, FALSE,
4837 ZBORDER, FALSE, FALSE,
4847 static struct Mapping_EM_to_RND_player
4856 em_player_mapping_list[] =
4860 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4864 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4868 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4872 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4876 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4880 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4884 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4888 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4892 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4896 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4900 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4904 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4908 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4912 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4916 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4920 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4924 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4928 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4932 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4936 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4940 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4944 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4948 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4952 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4956 EL_PLAYER_1, ACTION_DEFAULT, -1,
4960 EL_PLAYER_2, ACTION_DEFAULT, -1,
4964 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4968 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4972 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4976 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4980 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4984 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4988 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4992 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4996 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5000 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5004 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5008 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5012 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5016 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5020 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5024 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5028 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5032 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5036 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5040 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5044 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5048 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5052 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5056 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5060 EL_PLAYER_3, ACTION_DEFAULT, -1,
5064 EL_PLAYER_4, ACTION_DEFAULT, -1,
5073 int map_element_RND_to_EM(int element_rnd)
5075 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5076 static boolean mapping_initialized = FALSE;
5078 if (!mapping_initialized)
5082 /* return "Xalpha_quest" for all undefined elements in mapping array */
5083 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5084 mapping_RND_to_EM[i] = Xalpha_quest;
5086 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5087 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5088 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5089 em_object_mapping_list[i].element_em;
5091 mapping_initialized = TRUE;
5094 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5095 return mapping_RND_to_EM[element_rnd];
5097 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5102 int map_element_EM_to_RND(int element_em)
5104 static unsigned short mapping_EM_to_RND[TILE_MAX];
5105 static boolean mapping_initialized = FALSE;
5107 if (!mapping_initialized)
5111 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5112 for (i = 0; i < TILE_MAX; i++)
5113 mapping_EM_to_RND[i] = EL_UNKNOWN;
5115 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5116 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5117 em_object_mapping_list[i].element_rnd;
5119 mapping_initialized = TRUE;
5122 if (element_em >= 0 && element_em < TILE_MAX)
5123 return mapping_EM_to_RND[element_em];
5125 Error(ERR_WARN, "invalid EM level element %d", element_em);
5130 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5132 struct LevelInfo_EM *level_em = level->native_em_level;
5133 struct LEVEL *lev = level_em->lev;
5136 for (i = 0; i < TILE_MAX; i++)
5137 lev->android_array[i] = Xblank;
5139 for (i = 0; i < level->num_android_clone_elements; i++)
5141 int element_rnd = level->android_clone_element[i];
5142 int element_em = map_element_RND_to_EM(element_rnd);
5144 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5145 if (em_object_mapping_list[j].element_rnd == element_rnd)
5146 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5150 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5152 struct LevelInfo_EM *level_em = level->native_em_level;
5153 struct LEVEL *lev = level_em->lev;
5156 level->num_android_clone_elements = 0;
5158 for (i = 0; i < TILE_MAX; i++)
5160 int element_em = lev->android_array[i];
5162 boolean element_found = FALSE;
5164 if (element_em == Xblank)
5167 element_rnd = map_element_EM_to_RND(element_em);
5169 for (j = 0; j < level->num_android_clone_elements; j++)
5170 if (level->android_clone_element[j] == element_rnd)
5171 element_found = TRUE;
5175 level->android_clone_element[level->num_android_clone_elements++] =
5178 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5183 if (level->num_android_clone_elements == 0)
5185 level->num_android_clone_elements = 1;
5186 level->android_clone_element[0] = EL_EMPTY;
5190 int map_direction_RND_to_EM(int direction)
5192 return (direction == MV_UP ? 0 :
5193 direction == MV_RIGHT ? 1 :
5194 direction == MV_DOWN ? 2 :
5195 direction == MV_LEFT ? 3 :
5199 int map_direction_EM_to_RND(int direction)
5201 return (direction == 0 ? MV_UP :
5202 direction == 1 ? MV_RIGHT :
5203 direction == 2 ? MV_DOWN :
5204 direction == 3 ? MV_LEFT :
5208 int get_next_element(int element)
5212 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5213 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5214 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5215 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5216 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5217 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5218 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5220 default: return element;
5225 int el_act_dir2img(int element, int action, int direction)
5227 element = GFX_ELEMENT(element);
5229 if (direction == MV_NONE)
5230 return element_info[element].graphic[action];
5232 direction = MV_DIR_TO_BIT(direction);
5234 return element_info[element].direction_graphic[action][direction];
5237 int el_act_dir2img(int element, int action, int direction)
5239 element = GFX_ELEMENT(element);
5240 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5242 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5243 return element_info[element].direction_graphic[action][direction];
5248 static int el_act_dir2crm(int element, int action, int direction)
5250 element = GFX_ELEMENT(element);
5252 if (direction == MV_NONE)
5253 return element_info[element].crumbled[action];
5255 direction = MV_DIR_TO_BIT(direction);
5257 return element_info[element].direction_crumbled[action][direction];
5260 static int el_act_dir2crm(int element, int action, int direction)
5262 element = GFX_ELEMENT(element);
5263 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5265 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5266 return element_info[element].direction_crumbled[action][direction];
5270 int el_act2img(int element, int action)
5272 element = GFX_ELEMENT(element);
5274 return element_info[element].graphic[action];
5277 int el_act2crm(int element, int action)
5279 element = GFX_ELEMENT(element);
5281 return element_info[element].crumbled[action];
5284 int el_dir2img(int element, int direction)
5286 element = GFX_ELEMENT(element);
5288 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5291 int el2baseimg(int element)
5293 return element_info[element].graphic[ACTION_DEFAULT];
5296 int el2img(int element)
5298 element = GFX_ELEMENT(element);
5300 return element_info[element].graphic[ACTION_DEFAULT];
5303 int el2edimg(int element)
5305 element = GFX_ELEMENT(element);
5307 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5310 int el2preimg(int element)
5312 element = GFX_ELEMENT(element);
5314 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5317 int font2baseimg(int font_nr)
5319 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5323 void setCenteredPlayerNr_EM(int centered_player_nr)
5325 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5328 int getCenteredPlayerNr_EM()
5331 if (game.centered_player_nr_next >= 0 &&
5332 !native_em_level.ply[game.centered_player_nr_next]->alive)
5333 game.centered_player_nr_next = game.centered_player_nr;
5336 if (game.centered_player_nr != game.centered_player_nr_next)
5337 game.centered_player_nr = game.centered_player_nr_next;
5339 return game.centered_player_nr;
5342 void setSetCenteredPlayer_EM(boolean set_centered_player)
5344 game.set_centered_player = set_centered_player;
5347 boolean getSetCenteredPlayer_EM()
5349 return game.set_centered_player;
5353 int getNumActivePlayers_EM()
5355 int num_players = 0;
5361 for (i = 0; i < MAX_PLAYERS; i++)
5362 if (tape.player_participates[i])
5369 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5371 int game_frame_delay_value;
5373 game_frame_delay_value =
5374 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5375 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5378 if (tape.playing && tape.warp_forward && !tape.pausing)
5379 game_frame_delay_value = 0;
5381 return game_frame_delay_value;
5385 unsigned int InitRND(long seed)
5387 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5388 return InitEngineRND_EM(seed);
5390 return InitEngineRND(seed);
5393 void InitGraphicInfo_EM(void)
5395 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5396 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5400 int num_em_gfx_errors = 0;
5402 if (graphic_info_em_object[0][0].bitmap == NULL)
5404 /* EM graphics not yet initialized in em_open_all() */
5409 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5412 /* always start with reliable default values */
5413 for (i = 0; i < TILE_MAX; i++)
5415 object_mapping[i].element_rnd = EL_UNKNOWN;
5416 object_mapping[i].is_backside = FALSE;
5417 object_mapping[i].action = ACTION_DEFAULT;
5418 object_mapping[i].direction = MV_NONE;
5421 /* always start with reliable default values */
5422 for (p = 0; p < MAX_PLAYERS; p++)
5424 for (i = 0; i < SPR_MAX; i++)
5426 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5427 player_mapping[p][i].action = ACTION_DEFAULT;
5428 player_mapping[p][i].direction = MV_NONE;
5432 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5434 int e = em_object_mapping_list[i].element_em;
5436 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5437 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5439 if (em_object_mapping_list[i].action != -1)
5440 object_mapping[e].action = em_object_mapping_list[i].action;
5442 if (em_object_mapping_list[i].direction != -1)
5443 object_mapping[e].direction =
5444 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5447 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5449 int a = em_player_mapping_list[i].action_em;
5450 int p = em_player_mapping_list[i].player_nr;
5452 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5454 if (em_player_mapping_list[i].action != -1)
5455 player_mapping[p][a].action = em_player_mapping_list[i].action;
5457 if (em_player_mapping_list[i].direction != -1)
5458 player_mapping[p][a].direction =
5459 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5462 for (i = 0; i < TILE_MAX; i++)
5464 int element = object_mapping[i].element_rnd;
5465 int action = object_mapping[i].action;
5466 int direction = object_mapping[i].direction;
5467 boolean is_backside = object_mapping[i].is_backside;
5468 boolean action_removing = (action == ACTION_DIGGING ||
5469 action == ACTION_SNAPPING ||
5470 action == ACTION_COLLECTING);
5471 boolean action_exploding = ((action == ACTION_EXPLODING ||
5472 action == ACTION_SMASHED_BY_ROCK ||
5473 action == ACTION_SMASHED_BY_SPRING) &&
5474 element != EL_DIAMOND);
5475 boolean action_active = (action == ACTION_ACTIVE);
5476 boolean action_other = (action == ACTION_OTHER);
5478 for (j = 0; j < 8; j++)
5480 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5481 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5483 i == Xdrip_stretch ? element :
5484 i == Xdrip_stretchB ? element :
5485 i == Ydrip_s1 ? element :
5486 i == Ydrip_s1B ? element :
5487 i == Xball_1B ? element :
5488 i == Xball_2 ? element :
5489 i == Xball_2B ? element :
5490 i == Yball_eat ? element :
5491 i == Ykey_1_eat ? element :
5492 i == Ykey_2_eat ? element :
5493 i == Ykey_3_eat ? element :
5494 i == Ykey_4_eat ? element :
5495 i == Ykey_5_eat ? element :
5496 i == Ykey_6_eat ? element :
5497 i == Ykey_7_eat ? element :
5498 i == Ykey_8_eat ? element :
5499 i == Ylenses_eat ? element :
5500 i == Ymagnify_eat ? element :
5501 i == Ygrass_eat ? element :
5502 i == Ydirt_eat ? element :
5503 i == Yemerald_stone ? EL_EMERALD :
5504 i == Ydiamond_stone ? EL_ROCK :
5505 i == Xsand_stonein_1 ? element :
5506 i == Xsand_stonein_2 ? element :
5507 i == Xsand_stonein_3 ? element :
5508 i == Xsand_stonein_4 ? element :
5509 is_backside ? EL_EMPTY :
5510 action_removing ? EL_EMPTY :
5512 int effective_action = (j < 7 ? action :
5513 i == Xdrip_stretch ? action :
5514 i == Xdrip_stretchB ? action :
5515 i == Ydrip_s1 ? action :
5516 i == Ydrip_s1B ? action :
5517 i == Xball_1B ? action :
5518 i == Xball_2 ? action :
5519 i == Xball_2B ? action :
5520 i == Yball_eat ? action :
5521 i == Ykey_1_eat ? action :
5522 i == Ykey_2_eat ? action :
5523 i == Ykey_3_eat ? action :
5524 i == Ykey_4_eat ? action :
5525 i == Ykey_5_eat ? action :
5526 i == Ykey_6_eat ? action :
5527 i == Ykey_7_eat ? action :
5528 i == Ykey_8_eat ? action :
5529 i == Ylenses_eat ? action :
5530 i == Ymagnify_eat ? action :
5531 i == Ygrass_eat ? action :
5532 i == Ydirt_eat ? action :
5533 i == Xsand_stonein_1 ? action :
5534 i == Xsand_stonein_2 ? action :
5535 i == Xsand_stonein_3 ? action :
5536 i == Xsand_stonein_4 ? action :
5537 i == Xsand_stoneout_1 ? action :
5538 i == Xsand_stoneout_2 ? action :
5539 i == Xboom_android ? ACTION_EXPLODING :
5540 action_exploding ? ACTION_EXPLODING :
5541 action_active ? action :
5542 action_other ? action :
5544 int graphic = (el_act_dir2img(effective_element, effective_action,
5546 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5548 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5549 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5550 boolean has_action_graphics = (graphic != base_graphic);
5551 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5552 struct GraphicInfo *g = &graphic_info[graphic];
5553 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5556 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5557 boolean special_animation = (action != ACTION_DEFAULT &&
5558 g->anim_frames == 3 &&
5559 g->anim_delay == 2 &&
5560 g->anim_mode & ANIM_LINEAR);
5561 int sync_frame = (i == Xdrip_stretch ? 7 :
5562 i == Xdrip_stretchB ? 7 :
5563 i == Ydrip_s2 ? j + 8 :
5564 i == Ydrip_s2B ? j + 8 :
5573 i == Xfake_acid_1 ? 0 :
5574 i == Xfake_acid_2 ? 10 :
5575 i == Xfake_acid_3 ? 20 :
5576 i == Xfake_acid_4 ? 30 :
5577 i == Xfake_acid_5 ? 40 :
5578 i == Xfake_acid_6 ? 50 :
5579 i == Xfake_acid_7 ? 60 :
5580 i == Xfake_acid_8 ? 70 :
5582 i == Xball_2B ? j + 8 :
5583 i == Yball_eat ? j + 1 :
5584 i == Ykey_1_eat ? j + 1 :
5585 i == Ykey_2_eat ? j + 1 :
5586 i == Ykey_3_eat ? j + 1 :
5587 i == Ykey_4_eat ? j + 1 :
5588 i == Ykey_5_eat ? j + 1 :
5589 i == Ykey_6_eat ? j + 1 :
5590 i == Ykey_7_eat ? j + 1 :
5591 i == Ykey_8_eat ? j + 1 :
5592 i == Ylenses_eat ? j + 1 :
5593 i == Ymagnify_eat ? j + 1 :
5594 i == Ygrass_eat ? j + 1 :
5595 i == Ydirt_eat ? j + 1 :
5596 i == Xamoeba_1 ? 0 :
5597 i == Xamoeba_2 ? 1 :
5598 i == Xamoeba_3 ? 2 :
5599 i == Xamoeba_4 ? 3 :
5600 i == Xamoeba_5 ? 0 :
5601 i == Xamoeba_6 ? 1 :
5602 i == Xamoeba_7 ? 2 :
5603 i == Xamoeba_8 ? 3 :
5604 i == Xexit_2 ? j + 8 :
5605 i == Xexit_3 ? j + 16 :
5606 i == Xdynamite_1 ? 0 :
5607 i == Xdynamite_2 ? 8 :
5608 i == Xdynamite_3 ? 16 :
5609 i == Xdynamite_4 ? 24 :
5610 i == Xsand_stonein_1 ? j + 1 :
5611 i == Xsand_stonein_2 ? j + 9 :
5612 i == Xsand_stonein_3 ? j + 17 :
5613 i == Xsand_stonein_4 ? j + 25 :
5614 i == Xsand_stoneout_1 && j == 0 ? 0 :
5615 i == Xsand_stoneout_1 && j == 1 ? 0 :
5616 i == Xsand_stoneout_1 && j == 2 ? 1 :
5617 i == Xsand_stoneout_1 && j == 3 ? 2 :
5618 i == Xsand_stoneout_1 && j == 4 ? 2 :
5619 i == Xsand_stoneout_1 && j == 5 ? 3 :
5620 i == Xsand_stoneout_1 && j == 6 ? 4 :
5621 i == Xsand_stoneout_1 && j == 7 ? 4 :
5622 i == Xsand_stoneout_2 && j == 0 ? 5 :
5623 i == Xsand_stoneout_2 && j == 1 ? 6 :
5624 i == Xsand_stoneout_2 && j == 2 ? 7 :
5625 i == Xsand_stoneout_2 && j == 3 ? 8 :
5626 i == Xsand_stoneout_2 && j == 4 ? 9 :
5627 i == Xsand_stoneout_2 && j == 5 ? 11 :
5628 i == Xsand_stoneout_2 && j == 6 ? 13 :
5629 i == Xsand_stoneout_2 && j == 7 ? 15 :
5630 i == Xboom_bug && j == 1 ? 2 :
5631 i == Xboom_bug && j == 2 ? 2 :
5632 i == Xboom_bug && j == 3 ? 4 :
5633 i == Xboom_bug && j == 4 ? 4 :
5634 i == Xboom_bug && j == 5 ? 2 :
5635 i == Xboom_bug && j == 6 ? 2 :
5636 i == Xboom_bug && j == 7 ? 0 :
5637 i == Xboom_bomb && j == 1 ? 2 :
5638 i == Xboom_bomb && j == 2 ? 2 :
5639 i == Xboom_bomb && j == 3 ? 4 :
5640 i == Xboom_bomb && j == 4 ? 4 :
5641 i == Xboom_bomb && j == 5 ? 2 :
5642 i == Xboom_bomb && j == 6 ? 2 :
5643 i == Xboom_bomb && j == 7 ? 0 :
5644 i == Xboom_android && j == 7 ? 6 :
5645 i == Xboom_1 && j == 1 ? 2 :
5646 i == Xboom_1 && j == 2 ? 2 :
5647 i == Xboom_1 && j == 3 ? 4 :
5648 i == Xboom_1 && j == 4 ? 4 :
5649 i == Xboom_1 && j == 5 ? 6 :
5650 i == Xboom_1 && j == 6 ? 6 :
5651 i == Xboom_1 && j == 7 ? 8 :
5652 i == Xboom_2 && j == 0 ? 8 :
5653 i == Xboom_2 && j == 1 ? 8 :
5654 i == Xboom_2 && j == 2 ? 10 :
5655 i == Xboom_2 && j == 3 ? 10 :
5656 i == Xboom_2 && j == 4 ? 10 :
5657 i == Xboom_2 && j == 5 ? 12 :
5658 i == Xboom_2 && j == 6 ? 12 :
5659 i == Xboom_2 && j == 7 ? 12 :
5660 special_animation && j == 4 ? 3 :
5661 effective_action != action ? 0 :
5665 Bitmap *debug_bitmap = g_em->bitmap;
5666 int debug_src_x = g_em->src_x;
5667 int debug_src_y = g_em->src_y;
5670 int frame = getAnimationFrame(g->anim_frames,
5673 g->anim_start_frame,
5676 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5677 g->double_movement && is_backside);
5679 g_em->bitmap = src_bitmap;
5680 g_em->src_x = src_x;
5681 g_em->src_y = src_y;
5682 g_em->src_offset_x = 0;
5683 g_em->src_offset_y = 0;
5684 g_em->dst_offset_x = 0;
5685 g_em->dst_offset_y = 0;
5686 g_em->width = TILEX;
5687 g_em->height = TILEY;
5689 g_em->crumbled_bitmap = NULL;
5690 g_em->crumbled_src_x = 0;
5691 g_em->crumbled_src_y = 0;
5692 g_em->crumbled_border_size = 0;
5694 g_em->has_crumbled_graphics = FALSE;
5695 g_em->preserve_background = FALSE;
5698 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5699 printf("::: empty crumbled: %d [%s], %d, %d\n",
5700 effective_element, element_info[effective_element].token_name,
5701 effective_action, direction);
5704 /* if element can be crumbled, but certain action graphics are just empty
5705 space (like snapping sand with the original R'n'D graphics), do not
5706 treat these empty space graphics as crumbled graphics in EMC engine */
5707 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5709 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5711 g_em->has_crumbled_graphics = TRUE;
5712 g_em->crumbled_bitmap = src_bitmap;
5713 g_em->crumbled_src_x = src_x;
5714 g_em->crumbled_src_y = src_y;
5715 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5719 if (element == EL_ROCK &&
5720 effective_action == ACTION_FILLING)
5721 printf("::: has_action_graphics == %d\n", has_action_graphics);
5724 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5725 effective_action == ACTION_MOVING ||
5726 effective_action == ACTION_PUSHING ||
5727 effective_action == ACTION_EATING)) ||
5728 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5729 effective_action == ACTION_EMPTYING)))
5732 (effective_action == ACTION_FALLING ||
5733 effective_action == ACTION_FILLING ||
5734 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5735 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5736 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5737 int num_steps = (i == Ydrip_s1 ? 16 :
5738 i == Ydrip_s1B ? 16 :
5739 i == Ydrip_s2 ? 16 :
5740 i == Ydrip_s2B ? 16 :
5741 i == Xsand_stonein_1 ? 32 :
5742 i == Xsand_stonein_2 ? 32 :
5743 i == Xsand_stonein_3 ? 32 :
5744 i == Xsand_stonein_4 ? 32 :
5745 i == Xsand_stoneout_1 ? 16 :
5746 i == Xsand_stoneout_2 ? 16 : 8);
5747 int cx = ABS(dx) * (TILEX / num_steps);
5748 int cy = ABS(dy) * (TILEY / num_steps);
5749 int step_frame = (i == Ydrip_s2 ? j + 8 :
5750 i == Ydrip_s2B ? j + 8 :
5751 i == Xsand_stonein_2 ? j + 8 :
5752 i == Xsand_stonein_3 ? j + 16 :
5753 i == Xsand_stonein_4 ? j + 24 :
5754 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5755 int step = (is_backside ? step_frame : num_steps - step_frame);
5757 if (is_backside) /* tile where movement starts */
5759 if (dx < 0 || dy < 0)
5761 g_em->src_offset_x = cx * step;
5762 g_em->src_offset_y = cy * step;
5766 g_em->dst_offset_x = cx * step;
5767 g_em->dst_offset_y = cy * step;
5770 else /* tile where movement ends */
5772 if (dx < 0 || dy < 0)
5774 g_em->dst_offset_x = cx * step;
5775 g_em->dst_offset_y = cy * step;
5779 g_em->src_offset_x = cx * step;
5780 g_em->src_offset_y = cy * step;
5784 g_em->width = TILEX - cx * step;
5785 g_em->height = TILEY - cy * step;
5789 /* create unique graphic identifier to decide if tile must be redrawn */
5790 /* bit 31 - 16 (16 bit): EM style graphic
5791 bit 15 - 12 ( 4 bit): EM style frame
5792 bit 11 - 6 ( 6 bit): graphic width
5793 bit 5 - 0 ( 6 bit): graphic height */
5794 g_em->unique_identifier =
5795 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5797 /* create unique graphic identifier to decide if tile must be redrawn */
5798 /* bit 31 - 16 (16 bit): EM style element
5799 bit 15 - 12 ( 4 bit): EM style frame
5800 bit 11 - 6 ( 6 bit): graphic width
5801 bit 5 - 0 ( 6 bit): graphic height */
5802 g_em->unique_identifier =
5803 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5807 if (effective_element == EL_ROCK)
5808 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5809 effective_action, j, graphic, frame, g_em->unique_identifier);
5815 /* skip check for EMC elements not contained in original EMC artwork */
5816 if (element == EL_EMC_FAKE_ACID)
5820 if (g_em->bitmap != debug_bitmap ||
5821 g_em->src_x != debug_src_x ||
5822 g_em->src_y != debug_src_y ||
5823 g_em->src_offset_x != 0 ||
5824 g_em->src_offset_y != 0 ||
5825 g_em->dst_offset_x != 0 ||
5826 g_em->dst_offset_y != 0 ||
5827 g_em->width != TILEX ||
5828 g_em->height != TILEY)
5830 static int last_i = -1;
5838 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5839 i, element, element_info[element].token_name,
5840 element_action_info[effective_action].suffix, direction);
5842 if (element != effective_element)
5843 printf(" [%d ('%s')]",
5845 element_info[effective_element].token_name);
5849 if (g_em->bitmap != debug_bitmap)
5850 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5851 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5853 if (g_em->src_x != debug_src_x ||
5854 g_em->src_y != debug_src_y)
5855 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5856 j, (is_backside ? 'B' : 'F'),
5857 g_em->src_x, g_em->src_y,
5858 g_em->src_x / 32, g_em->src_y / 32,
5859 debug_src_x, debug_src_y,
5860 debug_src_x / 32, debug_src_y / 32);
5862 if (g_em->src_offset_x != 0 ||
5863 g_em->src_offset_y != 0 ||
5864 g_em->dst_offset_x != 0 ||
5865 g_em->dst_offset_y != 0)
5866 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5868 g_em->src_offset_x, g_em->src_offset_y,
5869 g_em->dst_offset_x, g_em->dst_offset_y);
5871 if (g_em->width != TILEX ||
5872 g_em->height != TILEY)
5873 printf(" %d (%d): size %d,%d should be %d,%d\n",
5875 g_em->width, g_em->height, TILEX, TILEY);
5877 num_em_gfx_errors++;
5884 for (i = 0; i < TILE_MAX; i++)
5886 for (j = 0; j < 8; j++)
5888 int element = object_mapping[i].element_rnd;
5889 int action = object_mapping[i].action;
5890 int direction = object_mapping[i].direction;
5891 boolean is_backside = object_mapping[i].is_backside;
5893 int graphic_action = el_act_dir2img(element, action, direction);
5894 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5896 int graphic_action = element_info[element].graphic[action];
5897 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5900 if ((action == ACTION_SMASHED_BY_ROCK ||
5901 action == ACTION_SMASHED_BY_SPRING ||
5902 action == ACTION_EATING) &&
5903 graphic_action == graphic_default)
5905 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5906 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5907 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5908 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5911 /* no separate animation for "smashed by rock" -- use rock instead */
5912 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5913 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5915 g_em->bitmap = g_xx->bitmap;
5916 g_em->src_x = g_xx->src_x;
5917 g_em->src_y = g_xx->src_y;
5918 g_em->src_offset_x = g_xx->src_offset_x;
5919 g_em->src_offset_y = g_xx->src_offset_y;
5920 g_em->dst_offset_x = g_xx->dst_offset_x;
5921 g_em->dst_offset_y = g_xx->dst_offset_y;
5922 g_em->width = g_xx->width;
5923 g_em->height = g_xx->height;
5925 g_em->unique_identifier = g_xx->unique_identifier;
5929 g_em->preserve_background = TRUE;
5934 for (p = 0; p < MAX_PLAYERS; p++)
5936 for (i = 0; i < SPR_MAX; i++)
5938 int element = player_mapping[p][i].element_rnd;
5939 int action = player_mapping[p][i].action;
5940 int direction = player_mapping[p][i].direction;
5942 for (j = 0; j < 8; j++)
5944 int effective_element = element;
5945 int effective_action = action;
5946 int graphic = (direction == MV_NONE ?
5947 el_act2img(effective_element, effective_action) :
5948 el_act_dir2img(effective_element, effective_action,
5950 struct GraphicInfo *g = &graphic_info[graphic];
5951 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5957 Bitmap *debug_bitmap = g_em->bitmap;
5958 int debug_src_x = g_em->src_x;
5959 int debug_src_y = g_em->src_y;
5962 int frame = getAnimationFrame(g->anim_frames,
5965 g->anim_start_frame,
5968 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5970 g_em->bitmap = src_bitmap;
5971 g_em->src_x = src_x;
5972 g_em->src_y = src_y;
5973 g_em->src_offset_x = 0;
5974 g_em->src_offset_y = 0;
5975 g_em->dst_offset_x = 0;
5976 g_em->dst_offset_y = 0;
5977 g_em->width = TILEX;
5978 g_em->height = TILEY;
5983 /* skip check for EMC elements not contained in original EMC artwork */
5984 if (element == EL_PLAYER_3 ||
5985 element == EL_PLAYER_4)
5989 if (g_em->bitmap != debug_bitmap ||
5990 g_em->src_x != debug_src_x ||
5991 g_em->src_y != debug_src_y)
5993 static int last_i = -1;
6001 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6002 p, i, element, element_info[element].token_name,
6003 element_action_info[effective_action].suffix, direction);
6005 if (element != effective_element)
6006 printf(" [%d ('%s')]",
6008 element_info[effective_element].token_name);
6012 if (g_em->bitmap != debug_bitmap)
6013 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6014 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6016 if (g_em->src_x != debug_src_x ||
6017 g_em->src_y != debug_src_y)
6018 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6020 g_em->src_x, g_em->src_y,
6021 g_em->src_x / 32, g_em->src_y / 32,
6022 debug_src_x, debug_src_y,
6023 debug_src_x / 32, debug_src_y / 32);
6025 num_em_gfx_errors++;
6035 printf("::: [%d errors found]\n", num_em_gfx_errors);
6041 void PlayMenuSound()
6043 int sound = menu.sound[game_status];
6045 if (sound == SND_UNDEFINED)
6048 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6049 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6052 if (IS_LOOP_SOUND(sound))
6053 PlaySoundLoop(sound);
6058 void PlayMenuSoundStereo(int sound, int stereo_position)
6060 if (sound == SND_UNDEFINED)
6063 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6064 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6067 if (IS_LOOP_SOUND(sound))
6068 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6070 PlaySoundStereo(sound, stereo_position);
6073 void PlayMenuSoundIfLoop()
6075 int sound = menu.sound[game_status];
6077 if (sound == SND_UNDEFINED)
6080 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6081 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6084 if (IS_LOOP_SOUND(sound))
6085 PlaySoundLoop(sound);
6088 void PlayMenuMusic()
6090 int music = menu.music[game_status];
6092 if (music == MUS_UNDEFINED)
6098 void ToggleFullscreenIfNeeded()
6100 if (setup.fullscreen != video.fullscreen_enabled ||
6101 setup.fullscreen_mode != video.fullscreen_mode_current)
6103 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6105 /* save backbuffer content which gets lost when toggling fullscreen mode */
6106 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6108 if (setup.fullscreen && video.fullscreen_enabled)
6110 /* keep fullscreen mode, but change screen mode */
6111 video.fullscreen_mode_current = setup.fullscreen_mode;
6112 video.fullscreen_enabled = FALSE;
6115 /* toggle fullscreen */
6116 ChangeVideoModeIfNeeded(setup.fullscreen);
6117 setup.fullscreen = video.fullscreen_enabled;
6119 /* restore backbuffer content from temporary backbuffer backup bitmap */
6120 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6122 FreeBitmap(tmp_backbuffer);
6124 redraw_mask = REDRAW_ALL;