1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX 0
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES 0
29 #define TOOL_CTRL_ID_NO 1
30 #define TOOL_CTRL_ID_CONFIRM 2
31 #define TOOL_CTRL_ID_PLAYER_1 3
32 #define TOOL_CTRL_ID_PLAYER_2 4
33 #define TOOL_CTRL_ID_PLAYER_3 5
34 #define TOOL_CTRL_ID_PLAYER_4 6
36 #define NUM_TOOL_BUTTONS 7
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
47 static char *print_if_not_empty(int element)
49 static char *s = NULL;
50 char *token_name = element_info[element].token_name;
55 s = checked_malloc(strlen(token_name) + 10 + 1);
57 if (element != EL_EMPTY)
58 sprintf(s, "%d\t['%s']", element, token_name);
60 sprintf(s, "%d", element);
65 void DumpTile(int x, int y)
70 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
77 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80 if (!IN_LEV_FIELD(x, y))
82 printf("(not in level field)\n");
88 printf(" Feld: %d\t['%s']\n", Feld[x][y],
89 element_info[Feld[x][y]].token_name);
90 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
91 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
92 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
93 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94 printf(" MovPos: %d\n", MovPos[x][y]);
95 printf(" MovDir: %d\n", MovDir[x][y]);
96 printf(" MovDelay: %d\n", MovDelay[x][y]);
97 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
98 printf(" CustomValue: %d\n", CustomValue[x][y]);
99 printf(" GfxElement: %d\n", GfxElement[x][y]);
100 printf(" GfxAction: %d\n", GfxAction[x][y]);
101 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
105 void SetDrawtoField(int mode)
107 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
118 drawto_field = fieldbuffer;
120 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
126 BX2 = SCR_FIELDX - 1;
127 BY2 = SCR_FIELDY - 1;
131 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 if (game_status == GAME_MODE_PLAYING &&
138 level.game_engine_type == GAME_ENGINE_TYPE_EM)
140 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
150 width = gfx.sxsize + 2 * TILEX;
151 height = gfx.sysize + 2 * TILEY;
154 if (force_redraw || setup.direct_draw)
157 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
158 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
160 if (setup.direct_draw)
161 SetDrawtoField(DRAW_BACKBUFFER);
163 for (xx = BX1; xx <= BX2; xx++)
164 for (yy = BY1; yy <= BY2; yy++)
165 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
166 DrawScreenField(xx, yy);
169 if (setup.direct_draw)
170 SetDrawtoField(DRAW_DIRECT);
173 if (setup.soft_scrolling)
175 int fx = FX, fy = FY;
177 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
178 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
180 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
184 BlitBitmap(drawto, window, x, y, width, height, x, y);
190 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
192 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
193 redraw_mask &= ~REDRAW_MAIN;
195 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
196 redraw_mask |= REDRAW_FIELD;
198 if (redraw_mask & REDRAW_FIELD)
199 redraw_mask &= ~REDRAW_TILES;
201 if (redraw_mask == REDRAW_NONE)
204 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
206 static boolean last_frame_skipped = FALSE;
207 boolean skip_even_when_not_scrolling = TRUE;
208 boolean just_scrolling = (ScreenMovDir != 0);
209 boolean verbose = FALSE;
211 if (global.fps_slowdown_factor > 1 &&
212 (FrameCounter % global.fps_slowdown_factor) &&
213 (just_scrolling || skip_even_when_not_scrolling))
215 redraw_mask &= ~REDRAW_MAIN;
217 last_frame_skipped = TRUE;
220 printf("FRAME SKIPPED\n");
224 if (last_frame_skipped)
225 redraw_mask |= REDRAW_FIELD;
227 last_frame_skipped = FALSE;
230 printf("frame not skipped\n");
234 /* synchronize X11 graphics at this point; if we would synchronize the
235 display immediately after the buffer switching (after the XFlush),
236 this could mean that we have to wait for the graphics to complete,
237 although we could go on doing calculations for the next frame */
241 if (redraw_mask & REDRAW_ALL)
243 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
245 redraw_mask = REDRAW_NONE;
248 if (redraw_mask & REDRAW_FIELD)
250 if (game_status != GAME_MODE_PLAYING ||
251 redraw_mask & REDRAW_FROM_BACKBUFFER)
253 BlitBitmap(backbuffer, window,
254 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
258 int fx = FX, fy = FY;
260 if (setup.soft_scrolling)
262 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
263 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
266 if (setup.soft_scrolling ||
267 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
268 ABS(ScreenMovPos) == ScrollStepSize ||
269 redraw_tiles > REDRAWTILES_THRESHOLD)
271 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
275 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
277 (setup.soft_scrolling ?
278 "setup.soft_scrolling" :
279 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
280 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
281 ABS(ScreenGfxPos) == ScrollStepSize ?
282 "ABS(ScreenGfxPos) == ScrollStepSize" :
283 "redraw_tiles > REDRAWTILES_THRESHOLD"));
289 redraw_mask &= ~REDRAW_MAIN;
292 if (redraw_mask & REDRAW_DOORS)
294 if (redraw_mask & REDRAW_DOOR_1)
295 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
297 if (redraw_mask & REDRAW_DOOR_2)
298 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
300 if (redraw_mask & REDRAW_DOOR_3)
301 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
303 redraw_mask &= ~REDRAW_DOORS;
306 if (redraw_mask & REDRAW_MICROLEVEL)
308 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
309 SX, SY + 10 * TILEY);
311 redraw_mask &= ~REDRAW_MICROLEVEL;
314 if (redraw_mask & REDRAW_TILES)
316 for (x = 0; x < SCR_FIELDX; x++)
317 for (y = 0 ; y < SCR_FIELDY; y++)
318 if (redraw[redraw_x1 + x][redraw_y1 + y])
319 BlitBitmap(buffer, window,
320 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
321 SX + x * TILEX, SY + y * TILEY);
324 if (redraw_mask & REDRAW_FPS) /* display frames per second */
329 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
330 if (!global.fps_slowdown)
333 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
334 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
339 for (x = 0; x < MAX_BUF_XSIZE; x++)
340 for (y = 0; y < MAX_BUF_YSIZE; y++)
343 redraw_mask = REDRAW_NONE;
349 long fading_delay = 300;
351 if (setup.fading && (redraw_mask & REDRAW_FIELD))
358 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
361 for (i = 0; i < 2 * FULL_SYSIZE; i++)
363 for (y = 0; y < FULL_SYSIZE; y++)
365 BlitBitmap(backbuffer, window,
366 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
374 for (i = 1; i < FULL_SYSIZE; i+=2)
375 BlitBitmap(backbuffer, window,
376 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
382 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
383 BlitBitmapMasked(backbuffer, window,
384 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
389 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
390 BlitBitmapMasked(backbuffer, window,
391 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
396 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
397 BlitBitmapMasked(backbuffer, window,
398 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
403 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
404 BlitBitmapMasked(backbuffer, window,
405 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
410 redraw_mask &= ~REDRAW_MAIN;
417 void FadeIn(int fade_delay)
426 FadeScreen(NULL, FADE_MODE_FADE_IN, fade_delay, 0);
428 redraw_mask = REDRAW_NONE;
431 void FadeOut(int fade_delay, int post_delay)
435 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
441 FadeScreen(NULL, FADE_MODE_FADE_OUT, fade_delay, post_delay);
443 redraw_mask = REDRAW_NONE;
446 void FadeCross(int fade_delay)
450 BlitBitmap(bitmap_db_title, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
456 FadeScreen(bitmap_db_title, FADE_MODE_CROSSFADE, fade_delay, 0);
458 redraw_mask = REDRAW_NONE;
461 void SetMainBackgroundImageIfDefined(int graphic)
463 if (graphic_info[graphic].bitmap)
464 SetMainBackgroundImage(graphic);
467 void SetMainBackgroundImage(int graphic)
469 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
470 graphic_info[graphic].bitmap ?
471 graphic_info[graphic].bitmap :
472 graphic_info[IMG_BACKGROUND].bitmap);
475 void SetDoorBackgroundImage(int graphic)
477 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
478 graphic_info[graphic].bitmap ?
479 graphic_info[graphic].bitmap :
480 graphic_info[IMG_BACKGROUND].bitmap);
483 void SetPanelBackground()
485 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
486 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
488 SetDoorBackgroundBitmap(bitmap_db_panel);
491 void DrawBackground(int dst_x, int dst_y, int width, int height)
493 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
495 redraw_mask |= REDRAW_FIELD;
500 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
502 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
504 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
505 SetDrawtoField(DRAW_BUFFERED);
508 SetDrawtoField(DRAW_BACKBUFFER);
510 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
512 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
513 SetDrawtoField(DRAW_DIRECT);
517 void MarkTileDirty(int x, int y)
519 int xx = redraw_x1 + x;
520 int yy = redraw_y1 + y;
525 redraw[xx][yy] = TRUE;
526 redraw_mask |= REDRAW_TILES;
529 void SetBorderElement()
533 BorderElement = EL_EMPTY;
535 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
537 for (x = 0; x < lev_fieldx; x++)
539 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
540 BorderElement = EL_STEELWALL;
542 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
548 void SetRandomAnimationValue(int x, int y)
550 gfx.anim_random_frame = GfxRandom[x][y];
553 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
555 /* animation synchronized with global frame counter, not move position */
556 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
557 sync_frame = FrameCounter;
560 if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
566 printf("::: FOO!\n");
570 return getAnimationFrame(graphic_info[graphic].anim_frames,
571 graphic_info[graphic].anim_delay,
572 graphic_info[graphic].anim_mode,
573 graphic_info[graphic].anim_start_frame,
577 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
578 int *x, int *y, boolean get_backside)
580 struct GraphicInfo *g = &graphic_info[graphic];
581 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
582 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
586 if (g->offset_y == 0) /* frames are ordered horizontally */
588 int max_width = g->anim_frames_per_line * g->width;
589 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
591 *x = pos % max_width;
592 *y = src_y % g->height + pos / max_width * g->height;
594 else if (g->offset_x == 0) /* frames are ordered vertically */
596 int max_height = g->anim_frames_per_line * g->height;
597 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
599 *x = src_x % g->width + pos / max_height * g->width;
600 *y = pos % max_height;
602 else /* frames are ordered diagonally */
604 *x = src_x + frame * g->offset_x;
605 *y = src_y + frame * g->offset_y;
609 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
611 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
614 void DrawGraphic(int x, int y, int graphic, int frame)
617 if (!IN_SCR_FIELD(x, y))
619 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
620 printf("DrawGraphic(): This should never happen!\n");
625 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
629 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
635 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
636 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
639 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
642 if (!IN_SCR_FIELD(x, y))
644 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
645 printf("DrawGraphicThruMask(): This should never happen!\n");
650 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
655 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
661 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
663 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
664 dst_x - src_x, dst_y - src_y);
665 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
668 void DrawMiniGraphic(int x, int y, int graphic)
670 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
671 MarkTileDirty(x / 2, y / 2);
674 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
676 struct GraphicInfo *g = &graphic_info[graphic];
678 int mini_starty = g->bitmap->height * 2 / 3;
681 *x = mini_startx + g->src_x / 2;
682 *y = mini_starty + g->src_y / 2;
685 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
690 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
691 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
694 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
695 int graphic, int frame,
696 int cut_mode, int mask_mode)
701 int width = TILEX, height = TILEY;
704 if (dx || dy) /* shifted graphic */
706 if (x < BX1) /* object enters playfield from the left */
713 else if (x > BX2) /* object enters playfield from the right */
719 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
725 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
727 else if (dx) /* general horizontal movement */
728 MarkTileDirty(x + SIGN(dx), y);
730 if (y < BY1) /* object enters playfield from the top */
732 if (cut_mode==CUT_BELOW) /* object completely above top border */
740 else if (y > BY2) /* object enters playfield from the bottom */
746 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
752 else if (dy > 0 && cut_mode == CUT_ABOVE)
754 if (y == BY2) /* object completely above bottom border */
760 MarkTileDirty(x, y + 1);
761 } /* object leaves playfield to the bottom */
762 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
764 else if (dy) /* general vertical movement */
765 MarkTileDirty(x, y + SIGN(dy));
769 if (!IN_SCR_FIELD(x, y))
771 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
772 printf("DrawGraphicShifted(): This should never happen!\n");
777 if (width > 0 && height > 0)
779 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
784 dst_x = FX + x * TILEX + dx;
785 dst_y = FY + y * TILEY + dy;
787 if (mask_mode == USE_MASKING)
789 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
790 dst_x - src_x, dst_y - src_y);
791 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
795 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
802 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
803 int graphic, int frame,
804 int cut_mode, int mask_mode)
809 int width = TILEX, height = TILEY;
812 int x2 = x + SIGN(dx);
813 int y2 = y + SIGN(dy);
814 int anim_frames = graphic_info[graphic].anim_frames;
815 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
816 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
817 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
819 /* re-calculate animation frame for two-tile movement animation */
820 frame = getGraphicAnimationFrame(graphic, sync_frame);
822 /* check if movement start graphic inside screen area and should be drawn */
823 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
825 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
827 dst_x = FX + x1 * TILEX;
828 dst_y = FY + y1 * TILEY;
830 if (mask_mode == USE_MASKING)
832 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
833 dst_x - src_x, dst_y - src_y);
834 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
838 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
841 MarkTileDirty(x1, y1);
844 /* check if movement end graphic inside screen area and should be drawn */
845 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
847 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
849 dst_x = FX + x2 * TILEX;
850 dst_y = FY + y2 * TILEY;
852 if (mask_mode == USE_MASKING)
854 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
855 dst_x - src_x, dst_y - src_y);
856 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
860 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
863 MarkTileDirty(x2, y2);
867 static void DrawGraphicShifted(int x, int y, int dx, int dy,
868 int graphic, int frame,
869 int cut_mode, int mask_mode)
873 DrawGraphic(x, y, graphic, frame);
878 if (graphic_info[graphic].double_movement) /* EM style movement images */
879 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
881 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
884 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
885 int frame, int cut_mode)
887 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
890 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
891 int cut_mode, int mask_mode)
893 int lx = LEVELX(x), ly = LEVELY(y);
897 if (IN_LEV_FIELD(lx, ly))
899 SetRandomAnimationValue(lx, ly);
901 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
902 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
904 /* do not use double (EM style) movement graphic when not moving */
905 if (graphic_info[graphic].double_movement && !dx && !dy)
907 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
908 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
911 else /* border element */
913 graphic = el2img(element);
914 frame = getGraphicAnimationFrame(graphic, -1);
917 if (element == EL_EXPANDABLE_WALL)
919 boolean left_stopped = FALSE, right_stopped = FALSE;
921 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
923 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
924 right_stopped = TRUE;
926 if (left_stopped && right_stopped)
928 else if (left_stopped)
930 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
931 frame = graphic_info[graphic].anim_frames - 1;
933 else if (right_stopped)
935 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
936 frame = graphic_info[graphic].anim_frames - 1;
941 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
942 else if (mask_mode == USE_MASKING)
943 DrawGraphicThruMask(x, y, graphic, frame);
945 DrawGraphic(x, y, graphic, frame);
948 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
949 int cut_mode, int mask_mode)
951 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
952 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
953 cut_mode, mask_mode);
956 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
959 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
962 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
965 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
968 void DrawLevelElementThruMask(int x, int y, int element)
970 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
973 void DrawLevelFieldThruMask(int x, int y)
975 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
978 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
982 int sx = SCREENX(x), sy = SCREENY(y);
984 int width, height, cx, cy, i;
985 int crumbled_border_size = graphic_info[graphic].border_size;
986 static int xy[4][2] =
994 if (!IN_LEV_FIELD(x, y))
997 element = TILE_GFX_ELEMENT(x, y);
999 /* crumble field itself */
1000 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1002 if (!IN_SCR_FIELD(sx, sy))
1005 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1007 for (i = 0; i < 4; i++)
1009 int xx = x + xy[i][0];
1010 int yy = y + xy[i][1];
1012 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1015 /* check if neighbour field is of same type */
1016 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1019 if (i == 1 || i == 2)
1021 width = crumbled_border_size;
1023 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1029 height = crumbled_border_size;
1031 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1034 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1035 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1038 MarkTileDirty(sx, sy);
1040 else /* crumble neighbour fields */
1042 for (i = 0; i < 4; i++)
1044 int xx = x + xy[i][0];
1045 int yy = y + xy[i][1];
1046 int sxx = sx + xy[i][0];
1047 int syy = sy + xy[i][1];
1050 if (!IN_LEV_FIELD(xx, yy) ||
1051 !IN_SCR_FIELD(sxx, syy) ||
1056 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1060 element = TILE_GFX_ELEMENT(xx, yy);
1062 if (!GFX_CRUMBLED(element))
1065 if (!IN_LEV_FIELD(xx, yy) ||
1066 !IN_SCR_FIELD(sxx, syy) ||
1067 !GFX_CRUMBLED(Feld[xx][yy]) ||
1073 graphic = el_act2crm(element, ACTION_DEFAULT);
1075 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1077 crumbled_border_size = graphic_info[graphic].border_size;
1079 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1081 if (i == 1 || i == 2)
1083 width = crumbled_border_size;
1085 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1091 height = crumbled_border_size;
1093 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1096 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1097 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1099 MarkTileDirty(sxx, syy);
1104 void DrawLevelFieldCrumbledSand(int x, int y)
1108 if (!IN_LEV_FIELD(x, y))
1112 /* !!! CHECK THIS !!! */
1115 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1116 GFX_CRUMBLED(GfxElement[x][y]))
1119 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1120 GfxElement[x][y] != EL_UNDEFINED &&
1121 GFX_CRUMBLED(GfxElement[x][y]))
1123 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1130 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1132 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1135 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1138 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1141 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1142 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1143 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1144 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1145 int sx = SCREENX(x), sy = SCREENY(y);
1147 DrawGraphic(sx, sy, graphic1, frame1);
1148 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1151 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1153 int sx = SCREENX(x), sy = SCREENY(y);
1154 static int xy[4][2] =
1163 for (i = 0; i < 4; i++)
1165 int xx = x + xy[i][0];
1166 int yy = y + xy[i][1];
1167 int sxx = sx + xy[i][0];
1168 int syy = sy + xy[i][1];
1170 if (!IN_LEV_FIELD(xx, yy) ||
1171 !IN_SCR_FIELD(sxx, syy) ||
1172 !GFX_CRUMBLED(Feld[xx][yy]) ||
1176 DrawLevelField(xx, yy);
1180 static int getBorderElement(int x, int y)
1184 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1185 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1186 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1187 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1188 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1189 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1190 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1192 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1193 int steel_position = (x == -1 && y == -1 ? 0 :
1194 x == lev_fieldx && y == -1 ? 1 :
1195 x == -1 && y == lev_fieldy ? 2 :
1196 x == lev_fieldx && y == lev_fieldy ? 3 :
1197 x == -1 || x == lev_fieldx ? 4 :
1198 y == -1 || y == lev_fieldy ? 5 : 6);
1200 return border[steel_position][steel_type];
1203 void DrawScreenElement(int x, int y, int element)
1205 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1206 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1209 void DrawLevelElement(int x, int y, int element)
1211 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1212 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1215 void DrawScreenField(int x, int y)
1217 int lx = LEVELX(x), ly = LEVELY(y);
1218 int element, content;
1220 if (!IN_LEV_FIELD(lx, ly))
1222 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1225 element = getBorderElement(lx, ly);
1227 DrawScreenElement(x, y, element);
1231 element = Feld[lx][ly];
1232 content = Store[lx][ly];
1234 if (IS_MOVING(lx, ly))
1236 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1237 boolean cut_mode = NO_CUTTING;
1239 if (element == EL_QUICKSAND_EMPTYING ||
1240 element == EL_MAGIC_WALL_EMPTYING ||
1241 element == EL_BD_MAGIC_WALL_EMPTYING ||
1242 element == EL_AMOEBA_DROPPING)
1243 cut_mode = CUT_ABOVE;
1244 else if (element == EL_QUICKSAND_FILLING ||
1245 element == EL_MAGIC_WALL_FILLING ||
1246 element == EL_BD_MAGIC_WALL_FILLING)
1247 cut_mode = CUT_BELOW;
1249 if (cut_mode == CUT_ABOVE)
1250 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1252 DrawScreenElement(x, y, EL_EMPTY);
1255 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1256 else if (cut_mode == NO_CUTTING)
1257 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1259 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1261 if (content == EL_ACID)
1263 int dir = MovDir[lx][ly];
1264 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1265 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1267 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1270 else if (IS_BLOCKED(lx, ly))
1275 boolean cut_mode = NO_CUTTING;
1276 int element_old, content_old;
1278 Blocked2Moving(lx, ly, &oldx, &oldy);
1281 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1282 MovDir[oldx][oldy] == MV_RIGHT);
1284 element_old = Feld[oldx][oldy];
1285 content_old = Store[oldx][oldy];
1287 if (element_old == EL_QUICKSAND_EMPTYING ||
1288 element_old == EL_MAGIC_WALL_EMPTYING ||
1289 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1290 element_old == EL_AMOEBA_DROPPING)
1291 cut_mode = CUT_ABOVE;
1293 DrawScreenElement(x, y, EL_EMPTY);
1296 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1298 else if (cut_mode == NO_CUTTING)
1299 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1302 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1305 else if (IS_DRAWABLE(element))
1306 DrawScreenElement(x, y, element);
1308 DrawScreenElement(x, y, EL_EMPTY);
1311 void DrawLevelField(int x, int y)
1313 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1314 DrawScreenField(SCREENX(x), SCREENY(y));
1315 else if (IS_MOVING(x, y))
1319 Moving2Blocked(x, y, &newx, &newy);
1320 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1321 DrawScreenField(SCREENX(newx), SCREENY(newy));
1323 else if (IS_BLOCKED(x, y))
1327 Blocked2Moving(x, y, &oldx, &oldy);
1328 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1329 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1333 void DrawMiniElement(int x, int y, int element)
1337 graphic = el2edimg(element);
1338 DrawMiniGraphic(x, y, graphic);
1341 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1343 int x = sx + scroll_x, y = sy + scroll_y;
1345 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1346 DrawMiniElement(sx, sy, EL_EMPTY);
1347 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1348 DrawMiniElement(sx, sy, Feld[x][y]);
1350 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1353 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1354 int x, int y, int xsize, int ysize, int font_nr)
1356 int font_width = getFontWidth(font_nr);
1357 int font_height = getFontHeight(font_nr);
1358 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1361 int dst_x = SX + startx + x * font_width;
1362 int dst_y = SY + starty + y * font_height;
1363 int width = graphic_info[graphic].width;
1364 int height = graphic_info[graphic].height;
1365 int inner_width = MAX(width - 2 * font_width, font_width);
1366 int inner_height = MAX(height - 2 * font_height, font_height);
1367 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1368 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1369 boolean draw_masked = graphic_info[graphic].draw_masked;
1371 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1373 if (src_bitmap == NULL || width < font_width || height < font_height)
1375 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1379 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1380 inner_sx + (x - 1) * font_width % inner_width);
1381 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1382 inner_sy + (y - 1) * font_height % inner_height);
1386 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1387 dst_x - src_x, dst_y - src_y);
1388 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1392 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1396 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1398 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1399 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1400 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1401 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1402 boolean no_delay = (tape.warp_forward);
1403 unsigned long anim_delay = 0;
1404 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1405 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1406 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1407 int font_width = getFontWidth(font_nr);
1408 int font_height = getFontHeight(font_nr);
1409 int max_xsize = level.envelope[envelope_nr].xsize;
1410 int max_ysize = level.envelope[envelope_nr].ysize;
1411 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1412 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1413 int xend = max_xsize;
1414 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1415 int xstep = (xstart < xend ? 1 : 0);
1416 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1419 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1421 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1422 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1423 int sx = (SXSIZE - xsize * font_width) / 2;
1424 int sy = (SYSIZE - ysize * font_height) / 2;
1427 SetDrawtoField(DRAW_BUFFERED);
1429 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1431 SetDrawtoField(DRAW_BACKBUFFER);
1433 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1434 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1436 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1437 level.envelope[envelope_nr].text, font_nr, max_xsize,
1438 xsize - 2, ysize - 2, mask_mode);
1440 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1443 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1447 void ShowEnvelope(int envelope_nr)
1449 int element = EL_ENVELOPE_1 + envelope_nr;
1450 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1451 int sound_opening = element_info[element].sound[ACTION_OPENING];
1452 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1453 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1454 boolean no_delay = (tape.warp_forward);
1455 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1456 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1457 int anim_mode = graphic_info[graphic].anim_mode;
1458 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1459 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1461 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1463 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1465 if (anim_mode == ANIM_DEFAULT)
1466 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1468 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1471 Delay(wait_delay_value);
1473 WaitForEventToContinue();
1475 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1477 if (anim_mode != ANIM_NONE)
1478 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1480 if (anim_mode == ANIM_DEFAULT)
1481 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1483 game.envelope_active = FALSE;
1485 SetDrawtoField(DRAW_BUFFERED);
1487 redraw_mask |= REDRAW_FIELD;
1491 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1496 int width_mult, width_div;
1497 int height_mult, height_div;
1505 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1506 5 - log_2(tilesize));
1507 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1508 int width_mult = offset_calc[offset_calc_pos].width_mult;
1509 int width_div = offset_calc[offset_calc_pos].width_div;
1510 int height_mult = offset_calc[offset_calc_pos].height_mult;
1511 int height_div = offset_calc[offset_calc_pos].height_div;
1512 int mini_startx = src_bitmap->width * width_mult / width_div;
1513 int mini_starty = src_bitmap->height * height_mult / height_div;
1514 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1515 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1517 *bitmap = src_bitmap;
1522 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1526 int graphic = el2preimg(element);
1528 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1529 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1536 SetDrawBackgroundMask(REDRAW_NONE);
1539 for (x = BX1; x <= BX2; x++)
1540 for (y = BY1; y <= BY2; y++)
1541 DrawScreenField(x, y);
1543 redraw_mask |= REDRAW_FIELD;
1546 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1550 for (x = 0; x < size_x; x++)
1551 for (y = 0; y < size_y; y++)
1552 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1554 redraw_mask |= REDRAW_FIELD;
1557 static void DrawPreviewLevelExt(int from_x, int from_y)
1559 boolean show_level_border = (BorderElement != EL_EMPTY);
1560 int dst_x = preview.x;
1561 int dst_y = preview.y;
1562 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1563 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1564 int tile_size = preview.tile_size;
1565 int preview_width = preview.xsize * tile_size;
1566 int preview_height = preview.ysize * tile_size;
1567 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1568 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1571 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1573 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1574 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1576 for (x = 0; x < real_preview_xsize; x++)
1578 for (y = 0; y < real_preview_ysize; y++)
1580 int lx = from_x + x + (show_level_border ? -1 : 0);
1581 int ly = from_y + y + (show_level_border ? -1 : 0);
1582 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1583 getBorderElement(lx, ly));
1585 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1586 element, tile_size);
1590 redraw_mask |= REDRAW_MICROLEVEL;
1593 #define MICROLABEL_EMPTY 0
1594 #define MICROLABEL_LEVEL_NAME 1
1595 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1596 #define MICROLABEL_LEVEL_AUTHOR 3
1597 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1598 #define MICROLABEL_IMPORTED_FROM 5
1599 #define MICROLABEL_IMPORTED_BY_HEAD 6
1600 #define MICROLABEL_IMPORTED_BY 7
1602 static void DrawPreviewLevelLabelExt(int mode)
1604 char label_text[MAX_OUTPUT_LINESIZE + 1];
1605 int max_len_label_text;
1606 int font_nr = FONT_TEXT_2;
1609 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1610 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1611 mode == MICROLABEL_IMPORTED_BY_HEAD)
1612 font_nr = FONT_TEXT_3;
1614 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1616 for (i = 0; i < max_len_label_text; i++)
1617 label_text[i] = ' ';
1618 label_text[max_len_label_text] = '\0';
1620 if (strlen(label_text) > 0)
1622 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1623 int lypos = MICROLABEL2_YPOS;
1625 DrawText(lxpos, lypos, label_text, font_nr);
1629 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1630 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1631 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1632 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1633 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1634 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1635 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1636 max_len_label_text);
1637 label_text[max_len_label_text] = '\0';
1639 if (strlen(label_text) > 0)
1641 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1642 int lypos = MICROLABEL2_YPOS;
1644 DrawText(lxpos, lypos, label_text, font_nr);
1647 redraw_mask |= REDRAW_MICROLEVEL;
1650 void DrawPreviewLevel(boolean restart)
1652 static unsigned long scroll_delay = 0;
1653 static unsigned long label_delay = 0;
1654 static int from_x, from_y, scroll_direction;
1655 static int label_state, label_counter;
1656 unsigned long scroll_delay_value = preview.step_delay;
1657 boolean show_level_border = (BorderElement != EL_EMPTY);
1658 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1659 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1660 int last_game_status = game_status; /* save current game status */
1662 /* force PREVIEW font on preview level */
1663 game_status = GAME_MODE_PSEUDO_PREVIEW;
1667 from_x = from_y = 0;
1668 scroll_direction = MV_RIGHT;
1672 DrawPreviewLevelExt(from_x, from_y);
1673 DrawPreviewLevelLabelExt(label_state);
1675 /* initialize delay counters */
1676 DelayReached(&scroll_delay, 0);
1677 DelayReached(&label_delay, 0);
1679 if (leveldir_current->name)
1681 char label_text[MAX_OUTPUT_LINESIZE + 1];
1682 int font_nr = FONT_TEXT_1;
1683 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1686 strncpy(label_text, leveldir_current->name, max_len_label_text);
1687 label_text[max_len_label_text] = '\0';
1689 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1690 lypos = SY + MICROLABEL1_YPOS;
1692 DrawText(lxpos, lypos, label_text, font_nr);
1695 game_status = last_game_status; /* restore current game status */
1700 /* scroll preview level, if needed */
1701 if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1702 DelayReached(&scroll_delay, scroll_delay_value))
1704 switch (scroll_direction)
1709 from_x -= preview.step_offset;
1710 from_x = (from_x < 0 ? 0 : from_x);
1713 scroll_direction = MV_UP;
1717 if (from_x < level_xsize - preview.xsize)
1719 from_x += preview.step_offset;
1720 from_x = (from_x > level_xsize - preview.xsize ?
1721 level_xsize - preview.xsize : from_x);
1724 scroll_direction = MV_DOWN;
1730 from_y -= preview.step_offset;
1731 from_y = (from_y < 0 ? 0 : from_y);
1734 scroll_direction = MV_RIGHT;
1738 if (from_y < level_ysize - preview.ysize)
1740 from_y += preview.step_offset;
1741 from_y = (from_y > level_ysize - preview.ysize ?
1742 level_ysize - preview.ysize : from_y);
1745 scroll_direction = MV_LEFT;
1752 DrawPreviewLevelExt(from_x, from_y);
1755 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1756 /* redraw micro level label, if needed */
1757 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1758 !strEqual(level.author, ANONYMOUS_NAME) &&
1759 !strEqual(level.author, leveldir_current->name) &&
1760 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1762 int max_label_counter = 23;
1764 if (leveldir_current->imported_from != NULL &&
1765 strlen(leveldir_current->imported_from) > 0)
1766 max_label_counter += 14;
1767 if (leveldir_current->imported_by != NULL &&
1768 strlen(leveldir_current->imported_by) > 0)
1769 max_label_counter += 14;
1771 label_counter = (label_counter + 1) % max_label_counter;
1772 label_state = (label_counter >= 0 && label_counter <= 7 ?
1773 MICROLABEL_LEVEL_NAME :
1774 label_counter >= 9 && label_counter <= 12 ?
1775 MICROLABEL_LEVEL_AUTHOR_HEAD :
1776 label_counter >= 14 && label_counter <= 21 ?
1777 MICROLABEL_LEVEL_AUTHOR :
1778 label_counter >= 23 && label_counter <= 26 ?
1779 MICROLABEL_IMPORTED_FROM_HEAD :
1780 label_counter >= 28 && label_counter <= 35 ?
1781 MICROLABEL_IMPORTED_FROM :
1782 label_counter >= 37 && label_counter <= 40 ?
1783 MICROLABEL_IMPORTED_BY_HEAD :
1784 label_counter >= 42 && label_counter <= 49 ?
1785 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1787 if (leveldir_current->imported_from == NULL &&
1788 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1789 label_state == MICROLABEL_IMPORTED_FROM))
1790 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1791 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1793 DrawPreviewLevelLabelExt(label_state);
1796 game_status = last_game_status; /* restore current game status */
1799 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1800 int graphic, int sync_frame, int mask_mode)
1802 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1804 if (mask_mode == USE_MASKING)
1805 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1807 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1810 inline void DrawGraphicAnimation(int x, int y, int graphic)
1812 int lx = LEVELX(x), ly = LEVELY(y);
1814 if (!IN_SCR_FIELD(x, y))
1817 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1818 graphic, GfxFrame[lx][ly], NO_MASKING);
1819 MarkTileDirty(x, y);
1822 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1824 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1827 void DrawLevelElementAnimation(int x, int y, int element)
1829 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1831 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1834 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1836 int sx = SCREENX(x), sy = SCREENY(y);
1838 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1841 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1844 DrawGraphicAnimation(sx, sy, graphic);
1847 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1848 DrawLevelFieldCrumbledSand(x, y);
1850 if (GFX_CRUMBLED(Feld[x][y]))
1851 DrawLevelFieldCrumbledSand(x, y);
1855 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1857 int sx = SCREENX(x), sy = SCREENY(y);
1860 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1863 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1865 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1868 DrawGraphicAnimation(sx, sy, graphic);
1870 if (GFX_CRUMBLED(element))
1871 DrawLevelFieldCrumbledSand(x, y);
1874 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1876 if (player->use_murphy)
1878 /* this works only because currently only one player can be "murphy" ... */
1879 static int last_horizontal_dir = MV_LEFT;
1880 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1882 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1883 last_horizontal_dir = move_dir;
1885 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1887 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1889 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1895 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1898 static boolean equalGraphics(int graphic1, int graphic2)
1900 struct GraphicInfo *g1 = &graphic_info[graphic1];
1901 struct GraphicInfo *g2 = &graphic_info[graphic2];
1903 return (g1->bitmap == g2->bitmap &&
1904 g1->src_x == g2->src_x &&
1905 g1->src_y == g2->src_y &&
1906 g1->anim_frames == g2->anim_frames &&
1907 g1->anim_delay == g2->anim_delay &&
1908 g1->anim_mode == g2->anim_mode);
1911 void DrawAllPlayers()
1915 for (i = 0; i < MAX_PLAYERS; i++)
1916 if (stored_player[i].active)
1917 DrawPlayer(&stored_player[i]);
1920 void DrawPlayerField(int x, int y)
1922 if (!IS_PLAYER(x, y))
1925 DrawPlayer(PLAYERINFO(x, y));
1928 void DrawPlayer(struct PlayerInfo *player)
1930 int jx = player->jx;
1931 int jy = player->jy;
1932 int move_dir = player->MovDir;
1933 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1934 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1935 int last_jx = (player->is_moving ? jx - dx : jx);
1936 int last_jy = (player->is_moving ? jy - dy : jy);
1937 int next_jx = jx + dx;
1938 int next_jy = jy + dy;
1939 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1940 boolean player_is_opaque = FALSE;
1941 int sx = SCREENX(jx), sy = SCREENY(jy);
1942 int sxx = 0, syy = 0;
1943 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1945 int action = ACTION_DEFAULT;
1946 int last_player_graphic = getPlayerGraphic(player, move_dir);
1947 int last_player_frame = player->Frame;
1951 /* GfxElement[][] is set to the element the player is digging or collecting;
1952 remove also for off-screen player if the player is not moving anymore */
1953 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1954 GfxElement[jx][jy] = EL_UNDEFINED;
1957 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1961 if (!IN_LEV_FIELD(jx, jy))
1963 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1964 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1965 printf("DrawPlayerField(): This should never happen!\n");
1970 if (element == EL_EXPLOSION)
1973 action = (player->is_pushing ? ACTION_PUSHING :
1974 player->is_digging ? ACTION_DIGGING :
1975 player->is_collecting ? ACTION_COLLECTING :
1976 player->is_moving ? ACTION_MOVING :
1977 player->is_snapping ? ACTION_SNAPPING :
1978 player->is_dropping ? ACTION_DROPPING :
1979 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1982 if (player->is_waiting)
1983 move_dir = player->dir_waiting;
1986 InitPlayerGfxAnimation(player, action, move_dir);
1988 /* ----------------------------------------------------------------------- */
1989 /* draw things in the field the player is leaving, if needed */
1990 /* ----------------------------------------------------------------------- */
1992 if (player->is_moving)
1994 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
1996 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
1998 if (last_element == EL_DYNAMITE_ACTIVE ||
1999 last_element == EL_EM_DYNAMITE_ACTIVE ||
2000 last_element == EL_SP_DISK_RED_ACTIVE)
2001 DrawDynamite(last_jx, last_jy);
2003 DrawLevelFieldThruMask(last_jx, last_jy);
2005 else if (last_element == EL_DYNAMITE_ACTIVE ||
2006 last_element == EL_EM_DYNAMITE_ACTIVE ||
2007 last_element == EL_SP_DISK_RED_ACTIVE)
2008 DrawDynamite(last_jx, last_jy);
2010 /* !!! this is not enough to prevent flickering of players which are
2011 moving next to each others without a free tile between them -- this
2012 can only be solved by drawing all players layer by layer (first the
2013 background, then the foreground etc.) !!! => TODO */
2014 else if (!IS_PLAYER(last_jx, last_jy))
2015 DrawLevelField(last_jx, last_jy);
2018 DrawLevelField(last_jx, last_jy);
2021 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2022 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2025 if (!IN_SCR_FIELD(sx, sy))
2028 if (setup.direct_draw)
2029 SetDrawtoField(DRAW_BUFFERED);
2031 /* ----------------------------------------------------------------------- */
2032 /* draw things behind the player, if needed */
2033 /* ----------------------------------------------------------------------- */
2036 DrawLevelElement(jx, jy, Back[jx][jy]);
2037 else if (IS_ACTIVE_BOMB(element))
2038 DrawLevelElement(jx, jy, EL_EMPTY);
2041 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2043 int old_element = GfxElement[jx][jy];
2044 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2045 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2047 if (GFX_CRUMBLED(old_element))
2048 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2050 DrawGraphic(sx, sy, old_graphic, frame);
2052 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2053 player_is_opaque = TRUE;
2057 GfxElement[jx][jy] = EL_UNDEFINED;
2059 /* make sure that pushed elements are drawn with correct frame rate */
2061 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2063 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2064 GfxFrame[jx][jy] = player->StepFrame;
2066 if (player->is_pushing && player->is_moving)
2067 GfxFrame[jx][jy] = player->StepFrame;
2070 DrawLevelField(jx, jy);
2074 /* ----------------------------------------------------------------------- */
2075 /* draw player himself */
2076 /* ----------------------------------------------------------------------- */
2078 graphic = getPlayerGraphic(player, move_dir);
2080 /* in the case of changed player action or direction, prevent the current
2081 animation frame from being restarted for identical animations */
2082 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2083 player->Frame = last_player_frame;
2085 frame = getGraphicAnimationFrame(graphic, player->Frame);
2089 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2090 sxx = player->GfxPos;
2092 syy = player->GfxPos;
2095 if (!setup.soft_scrolling && ScreenMovPos)
2098 if (player_is_opaque)
2099 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2101 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2103 if (SHIELD_ON(player))
2105 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2106 IMG_SHIELD_NORMAL_ACTIVE);
2107 int frame = getGraphicAnimationFrame(graphic, -1);
2109 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2112 /* ----------------------------------------------------------------------- */
2113 /* draw things the player is pushing, if needed */
2114 /* ----------------------------------------------------------------------- */
2117 printf("::: %d, %d [%d, %d] [%d]\n",
2118 player->is_pushing, player_is_moving, player->GfxAction,
2119 player->is_moving, player_is_moving);
2123 if (player->is_pushing && player->is_moving)
2125 int px = SCREENX(jx), py = SCREENY(jy);
2126 int pxx = (TILEX - ABS(sxx)) * dx;
2127 int pyy = (TILEY - ABS(syy)) * dy;
2128 int gfx_frame = GfxFrame[jx][jy];
2134 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2136 element = Feld[next_jx][next_jy];
2137 gfx_frame = GfxFrame[next_jx][next_jy];
2140 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2143 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2144 frame = getGraphicAnimationFrame(graphic, sync_frame);
2146 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2149 /* draw background element under pushed element (like the Sokoban field) */
2150 if (Back[next_jx][next_jy])
2151 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2153 /* masked drawing is needed for EMC style (double) movement graphics */
2154 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2158 /* ----------------------------------------------------------------------- */
2159 /* draw things in front of player (active dynamite or dynabombs) */
2160 /* ----------------------------------------------------------------------- */
2162 if (IS_ACTIVE_BOMB(element))
2164 graphic = el2img(element);
2165 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2167 if (game.emulation == EMU_SUPAPLEX)
2168 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2170 DrawGraphicThruMask(sx, sy, graphic, frame);
2173 if (player_is_moving && last_element == EL_EXPLOSION)
2175 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2176 GfxElement[last_jx][last_jy] : EL_EMPTY);
2177 int graphic = el_act2img(element, ACTION_EXPLODING);
2178 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2179 int phase = ExplodePhase[last_jx][last_jy] - 1;
2180 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2183 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2186 /* ----------------------------------------------------------------------- */
2187 /* draw elements the player is just walking/passing through/under */
2188 /* ----------------------------------------------------------------------- */
2190 if (player_is_moving)
2192 /* handle the field the player is leaving ... */
2193 if (IS_ACCESSIBLE_INSIDE(last_element))
2194 DrawLevelField(last_jx, last_jy);
2195 else if (IS_ACCESSIBLE_UNDER(last_element))
2196 DrawLevelFieldThruMask(last_jx, last_jy);
2199 /* do not redraw accessible elements if the player is just pushing them */
2200 if (!player_is_moving || !player->is_pushing)
2202 /* ... and the field the player is entering */
2203 if (IS_ACCESSIBLE_INSIDE(element))
2204 DrawLevelField(jx, jy);
2205 else if (IS_ACCESSIBLE_UNDER(element))
2206 DrawLevelFieldThruMask(jx, jy);
2209 if (setup.direct_draw)
2211 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2212 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2213 int x_size = TILEX * (1 + ABS(jx - last_jx));
2214 int y_size = TILEY * (1 + ABS(jy - last_jy));
2216 BlitBitmap(drawto_field, window,
2217 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2218 SetDrawtoField(DRAW_DIRECT);
2221 MarkTileDirty(sx, sy);
2224 /* ------------------------------------------------------------------------- */
2226 void WaitForEventToContinue()
2228 boolean still_wait = TRUE;
2230 /* simulate releasing mouse button over last gadget, if still pressed */
2232 HandleGadgets(-1, -1, 0);
2234 button_status = MB_RELEASED;
2246 case EVENT_BUTTONPRESS:
2247 case EVENT_KEYPRESS:
2251 case EVENT_KEYRELEASE:
2252 ClearPlayerAction();
2256 HandleOtherEvents(&event);
2260 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2267 /* don't eat all CPU time */
2272 #define MAX_REQUEST_LINES 13
2273 #define MAX_REQUEST_LINE_FONT1_LEN 7
2274 #define MAX_REQUEST_LINE_FONT2_LEN 10
2276 boolean Request(char *text, unsigned int req_state)
2278 int mx, my, ty, result = -1;
2279 unsigned int old_door_state;
2280 int last_game_status = game_status; /* save current game status */
2281 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2282 int font_nr = FONT_TEXT_2;
2283 int max_word_len = 0;
2286 for (text_ptr = text; *text_ptr; text_ptr++)
2288 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2290 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2292 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2293 font_nr = FONT_LEVEL_NUMBER;
2299 if (game_status == GAME_MODE_PLAYING &&
2300 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2301 BlitScreenToBitmap_EM(backbuffer);
2303 /* disable deactivated drawing when quick-loading level tape recording */
2304 if (tape.playing && tape.deactivate_display)
2305 TapeDeactivateDisplayOff(TRUE);
2307 SetMouseCursor(CURSOR_DEFAULT);
2309 #if defined(NETWORK_AVALIABLE)
2310 /* pause network game while waiting for request to answer */
2311 if (options.network &&
2312 game_status == GAME_MODE_PLAYING &&
2313 req_state & REQUEST_WAIT_FOR_INPUT)
2314 SendToServer_PausePlaying();
2317 old_door_state = GetDoorState();
2319 /* simulate releasing mouse button over last gadget, if still pressed */
2321 HandleGadgets(-1, -1, 0);
2325 if (old_door_state & DOOR_OPEN_1)
2327 CloseDoor(DOOR_CLOSE_1);
2329 /* save old door content */
2330 BlitBitmap(bitmap_db_door, bitmap_db_door,
2331 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2332 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2336 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2339 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2341 /* clear door drawing field */
2342 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2344 /* force DOOR font on preview level */
2345 game_status = GAME_MODE_PSEUDO_DOOR;
2347 /* write text for request */
2348 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2350 char text_line[max_request_line_len + 1];
2356 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2359 if (!tc || tc == ' ')
2370 strncpy(text_line, text, tl);
2373 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2374 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2375 text_line, font_nr);
2377 text += tl + (tc == ' ' ? 1 : 0);
2380 game_status = last_game_status; /* restore current game status */
2382 if (req_state & REQ_ASK)
2384 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2385 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2387 else if (req_state & REQ_CONFIRM)
2389 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2391 else if (req_state & REQ_PLAYER)
2393 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2394 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2395 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2396 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2399 /* copy request gadgets to door backbuffer */
2400 BlitBitmap(drawto, bitmap_db_door,
2401 DX, DY, DXSIZE, DYSIZE,
2402 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2404 OpenDoor(DOOR_OPEN_1);
2406 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2408 if (game_status == GAME_MODE_PLAYING)
2410 SetPanelBackground();
2411 SetDrawBackgroundMask(REDRAW_DOOR_1);
2415 SetDrawBackgroundMask(REDRAW_FIELD);
2421 if (game_status != GAME_MODE_MAIN)
2424 button_status = MB_RELEASED;
2426 request_gadget_id = -1;
2428 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2440 case EVENT_BUTTONPRESS:
2441 case EVENT_BUTTONRELEASE:
2442 case EVENT_MOTIONNOTIFY:
2444 if (event.type == EVENT_MOTIONNOTIFY)
2446 if (!PointerInWindow(window))
2447 continue; /* window and pointer are on different screens */
2452 motion_status = TRUE;
2453 mx = ((MotionEvent *) &event)->x;
2454 my = ((MotionEvent *) &event)->y;
2458 motion_status = FALSE;
2459 mx = ((ButtonEvent *) &event)->x;
2460 my = ((ButtonEvent *) &event)->y;
2461 if (event.type == EVENT_BUTTONPRESS)
2462 button_status = ((ButtonEvent *) &event)->button;
2464 button_status = MB_RELEASED;
2467 /* this sets 'request_gadget_id' */
2468 HandleGadgets(mx, my, button_status);
2470 switch(request_gadget_id)
2472 case TOOL_CTRL_ID_YES:
2475 case TOOL_CTRL_ID_NO:
2478 case TOOL_CTRL_ID_CONFIRM:
2479 result = TRUE | FALSE;
2482 case TOOL_CTRL_ID_PLAYER_1:
2485 case TOOL_CTRL_ID_PLAYER_2:
2488 case TOOL_CTRL_ID_PLAYER_3:
2491 case TOOL_CTRL_ID_PLAYER_4:
2502 case EVENT_KEYPRESS:
2503 switch(GetEventKey((KeyEvent *)&event, TRUE))
2516 if (req_state & REQ_PLAYER)
2520 case EVENT_KEYRELEASE:
2521 ClearPlayerAction();
2525 HandleOtherEvents(&event);
2529 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2531 int joy = AnyJoystick();
2533 if (joy & JOY_BUTTON_1)
2535 else if (joy & JOY_BUTTON_2)
2541 /* don't eat all CPU time */
2545 if (game_status != GAME_MODE_MAIN)
2550 if (!(req_state & REQ_STAY_OPEN))
2552 CloseDoor(DOOR_CLOSE_1);
2554 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2555 (req_state & REQ_REOPEN))
2556 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2561 if (game_status == GAME_MODE_PLAYING)
2563 SetPanelBackground();
2564 SetDrawBackgroundMask(REDRAW_DOOR_1);
2568 SetDrawBackgroundMask(REDRAW_FIELD);
2571 #if defined(NETWORK_AVALIABLE)
2572 /* continue network game after request */
2573 if (options.network &&
2574 game_status == GAME_MODE_PLAYING &&
2575 req_state & REQUEST_WAIT_FOR_INPUT)
2576 SendToServer_ContinuePlaying();
2579 /* restore deactivated drawing when quick-loading level tape recording */
2580 if (tape.playing && tape.deactivate_display)
2581 TapeDeactivateDisplayOn();
2586 unsigned int OpenDoor(unsigned int door_state)
2588 if (door_state & DOOR_COPY_BACK)
2590 if (door_state & DOOR_OPEN_1)
2591 BlitBitmap(bitmap_db_door, bitmap_db_door,
2592 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2593 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2595 if (door_state & DOOR_OPEN_2)
2596 BlitBitmap(bitmap_db_door, bitmap_db_door,
2597 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2598 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2600 door_state &= ~DOOR_COPY_BACK;
2603 return MoveDoor(door_state);
2606 unsigned int CloseDoor(unsigned int door_state)
2608 unsigned int old_door_state = GetDoorState();
2610 if (!(door_state & DOOR_NO_COPY_BACK))
2612 if (old_door_state & DOOR_OPEN_1)
2613 BlitBitmap(backbuffer, bitmap_db_door,
2614 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2616 if (old_door_state & DOOR_OPEN_2)
2617 BlitBitmap(backbuffer, bitmap_db_door,
2618 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2620 door_state &= ~DOOR_NO_COPY_BACK;
2623 return MoveDoor(door_state);
2626 unsigned int GetDoorState()
2628 return MoveDoor(DOOR_GET_STATE);
2631 unsigned int SetDoorState(unsigned int door_state)
2633 return MoveDoor(door_state | DOOR_SET_STATE);
2636 unsigned int MoveDoor(unsigned int door_state)
2638 static int door1 = DOOR_OPEN_1;
2639 static int door2 = DOOR_CLOSE_2;
2640 unsigned long door_delay = 0;
2641 unsigned long door_delay_value;
2644 if (door_1.width < 0 || door_1.width > DXSIZE)
2645 door_1.width = DXSIZE;
2646 if (door_1.height < 0 || door_1.height > DYSIZE)
2647 door_1.height = DYSIZE;
2648 if (door_2.width < 0 || door_2.width > VXSIZE)
2649 door_2.width = VXSIZE;
2650 if (door_2.height < 0 || door_2.height > VYSIZE)
2651 door_2.height = VYSIZE;
2653 if (door_state == DOOR_GET_STATE)
2654 return (door1 | door2);
2656 if (door_state & DOOR_SET_STATE)
2658 if (door_state & DOOR_ACTION_1)
2659 door1 = door_state & DOOR_ACTION_1;
2660 if (door_state & DOOR_ACTION_2)
2661 door2 = door_state & DOOR_ACTION_2;
2663 return (door1 | door2);
2666 if (!(door_state & DOOR_FORCE_REDRAW))
2668 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2669 door_state &= ~DOOR_OPEN_1;
2670 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2671 door_state &= ~DOOR_CLOSE_1;
2672 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2673 door_state &= ~DOOR_OPEN_2;
2674 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2675 door_state &= ~DOOR_CLOSE_2;
2678 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2681 if (setup.quick_doors)
2683 stepsize = 20; /* must be choosen to always draw last frame */
2684 door_delay_value = 0;
2687 if (global.autoplay_leveldir)
2689 door_state |= DOOR_NO_DELAY;
2690 door_state &= ~DOOR_CLOSE_ALL;
2693 if (door_state & DOOR_ACTION)
2695 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2696 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2697 boolean door_1_done = (!handle_door_1);
2698 boolean door_2_done = (!handle_door_2);
2699 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2700 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2701 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2702 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2703 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2704 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2705 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2706 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2707 int door_skip = max_door_size - door_size;
2709 int end = door_size;
2711 int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
2715 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2717 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2721 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2723 /* opening door sound has priority over simultaneously closing door */
2724 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2725 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2726 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2727 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2730 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2733 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2734 GC gc = bitmap->stored_clip_gc;
2736 if (door_state & DOOR_ACTION_1)
2738 int a = MIN(x * door_1.step_offset, end);
2739 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2740 int i = p + door_skip;
2742 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2744 BlitBitmap(bitmap_db_door, drawto,
2745 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2746 DXSIZE, DYSIZE, DX, DY);
2750 BlitBitmap(bitmap_db_door, drawto,
2751 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2752 DXSIZE, DYSIZE - p / 2, DX, DY);
2754 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2757 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2759 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2760 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2761 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2762 int dst2_x = DX, dst2_y = DY;
2763 int width = i, height = DYSIZE;
2765 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2766 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2769 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2770 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2773 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2775 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2776 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2777 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2778 int dst2_x = DX, dst2_y = DY;
2779 int width = DXSIZE, height = i;
2781 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2782 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2785 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2786 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2789 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2791 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2793 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2794 BlitBitmapMasked(bitmap, drawto,
2795 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2796 DX + DXSIZE - i, DY + j);
2797 BlitBitmapMasked(bitmap, drawto,
2798 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2799 DX + DXSIZE - i, DY + 140 + j);
2800 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2801 DY - (DOOR_GFX_PAGEY1 + j));
2802 BlitBitmapMasked(bitmap, drawto,
2803 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2805 BlitBitmapMasked(bitmap, drawto,
2806 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2809 BlitBitmapMasked(bitmap, drawto,
2810 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2812 BlitBitmapMasked(bitmap, drawto,
2813 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2815 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2816 BlitBitmapMasked(bitmap, drawto,
2817 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2818 DX + DXSIZE - i, DY + 77 + j);
2819 BlitBitmapMasked(bitmap, drawto,
2820 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2821 DX + DXSIZE - i, DY + 203 + j);
2824 redraw_mask |= REDRAW_DOOR_1;
2825 door_1_done = (a == end);
2828 if (door_state & DOOR_ACTION_2)
2831 int a = MIN(x * door_2.step_offset, door_size);
2832 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2833 int i = p + door_skip;
2835 int a = MIN(x * door_2.step_offset, door_size_2);
2836 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2837 int i = p + door_skip;
2840 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2842 BlitBitmap(bitmap_db_door, drawto,
2843 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2844 VXSIZE, VYSIZE, VX, VY);
2846 else if (x <= VYSIZE)
2848 BlitBitmap(bitmap_db_door, drawto,
2849 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2850 VXSIZE, VYSIZE - p / 2, VX, VY);
2852 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2855 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2857 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2858 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2859 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2860 int dst2_x = VX, dst2_y = VY;
2861 int width = i, height = VYSIZE;
2863 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2864 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2867 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2868 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2871 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2873 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2874 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2875 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2876 int dst2_x = VX, dst2_y = VY;
2877 int width = VXSIZE, height = i;
2879 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2880 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2883 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2884 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2887 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2889 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2891 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2892 BlitBitmapMasked(bitmap, drawto,
2893 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2894 VX + VXSIZE - i, VY + j);
2895 SetClipOrigin(bitmap, gc,
2896 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2897 BlitBitmapMasked(bitmap, drawto,
2898 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2901 BlitBitmapMasked(bitmap, drawto,
2902 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2903 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2904 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2905 BlitBitmapMasked(bitmap, drawto,
2906 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2908 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2911 redraw_mask |= REDRAW_DOOR_2;
2912 door_2_done = (a == VXSIZE);
2915 if (!(door_state & DOOR_NO_DELAY))
2919 if (game_status == GAME_MODE_MAIN)
2922 WaitUntilDelayReached(&door_delay, door_delay_value);
2927 if (door_state & DOOR_ACTION_1)
2928 door1 = door_state & DOOR_ACTION_1;
2929 if (door_state & DOOR_ACTION_2)
2930 door2 = door_state & DOOR_ACTION_2;
2932 return (door1 | door2);
2935 void DrawSpecialEditorDoor()
2937 /* draw bigger toolbox window */
2938 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2939 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2941 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2942 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2945 redraw_mask |= REDRAW_ALL;
2948 void UndrawSpecialEditorDoor()
2950 /* draw normal tape recorder window */
2951 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2952 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2955 redraw_mask |= REDRAW_ALL;
2959 /* ---------- new tool button stuff ---------------------------------------- */
2961 /* graphic position values for tool buttons */
2962 #define TOOL_BUTTON_YES_XPOS 2
2963 #define TOOL_BUTTON_YES_YPOS 250
2964 #define TOOL_BUTTON_YES_GFX_YPOS 0
2965 #define TOOL_BUTTON_YES_XSIZE 46
2966 #define TOOL_BUTTON_YES_YSIZE 28
2967 #define TOOL_BUTTON_NO_XPOS 52
2968 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2969 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2970 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2971 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2972 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2973 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2974 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2975 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2976 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2977 #define TOOL_BUTTON_PLAYER_XSIZE 30
2978 #define TOOL_BUTTON_PLAYER_YSIZE 30
2979 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2980 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2981 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2982 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2983 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2984 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2985 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2986 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2987 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2988 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2989 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2990 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2991 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2992 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2993 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2994 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2995 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2996 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2997 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2998 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3007 } toolbutton_info[NUM_TOOL_BUTTONS] =
3010 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3011 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3012 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3017 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3018 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3019 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3024 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3025 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3026 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3027 TOOL_CTRL_ID_CONFIRM,
3031 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3032 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3033 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3034 TOOL_CTRL_ID_PLAYER_1,
3038 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3039 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3040 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3041 TOOL_CTRL_ID_PLAYER_2,
3045 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3046 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3047 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3048 TOOL_CTRL_ID_PLAYER_3,
3052 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3053 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3054 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3055 TOOL_CTRL_ID_PLAYER_4,
3060 void CreateToolButtons()
3064 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3066 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3067 Bitmap *deco_bitmap = None;
3068 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3069 struct GadgetInfo *gi;
3070 unsigned long event_mask;
3071 int gd_xoffset, gd_yoffset;
3072 int gd_x1, gd_x2, gd_y;
3075 event_mask = GD_EVENT_RELEASED;
3077 gd_xoffset = toolbutton_info[i].xpos;
3078 gd_yoffset = toolbutton_info[i].ypos;
3079 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3080 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3081 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3083 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3085 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3087 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3088 &deco_bitmap, &deco_x, &deco_y);
3089 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3090 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3093 gi = CreateGadget(GDI_CUSTOM_ID, id,
3094 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3095 GDI_X, DX + toolbutton_info[i].x,
3096 GDI_Y, DY + toolbutton_info[i].y,
3097 GDI_WIDTH, toolbutton_info[i].width,
3098 GDI_HEIGHT, toolbutton_info[i].height,
3099 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3100 GDI_STATE, GD_BUTTON_UNPRESSED,
3101 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3102 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3103 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3104 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3105 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3106 GDI_DECORATION_SHIFTING, 1, 1,
3107 GDI_EVENT_MASK, event_mask,
3108 GDI_CALLBACK_ACTION, HandleToolButtons,
3112 Error(ERR_EXIT, "cannot create gadget");
3114 tool_gadget[id] = gi;
3118 void FreeToolButtons()
3122 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3123 FreeGadget(tool_gadget[i]);
3126 static void UnmapToolButtons()
3130 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3131 UnmapGadget(tool_gadget[i]);
3134 static void HandleToolButtons(struct GadgetInfo *gi)
3136 request_gadget_id = gi->custom_id;
3139 static struct Mapping_EM_to_RND_object
3142 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3143 boolean is_backside; /* backside of moving element */
3149 em_object_mapping_list[] =
3152 Xblank, TRUE, FALSE,
3156 Yacid_splash_eB, FALSE, FALSE,
3157 EL_ACID_SPLASH_RIGHT, -1, -1
3160 Yacid_splash_wB, FALSE, FALSE,
3161 EL_ACID_SPLASH_LEFT, -1, -1
3164 #ifdef EM_ENGINE_BAD_ROLL
3166 Xstone_force_e, FALSE, FALSE,
3167 EL_ROCK, -1, MV_BIT_RIGHT
3170 Xstone_force_w, FALSE, FALSE,
3171 EL_ROCK, -1, MV_BIT_LEFT
3174 Xnut_force_e, FALSE, FALSE,
3175 EL_NUT, -1, MV_BIT_RIGHT
3178 Xnut_force_w, FALSE, FALSE,
3179 EL_NUT, -1, MV_BIT_LEFT
3182 Xspring_force_e, FALSE, FALSE,
3183 EL_SPRING, -1, MV_BIT_RIGHT
3186 Xspring_force_w, FALSE, FALSE,
3187 EL_SPRING, -1, MV_BIT_LEFT
3190 Xemerald_force_e, FALSE, FALSE,
3191 EL_EMERALD, -1, MV_BIT_RIGHT
3194 Xemerald_force_w, FALSE, FALSE,
3195 EL_EMERALD, -1, MV_BIT_LEFT
3198 Xdiamond_force_e, FALSE, FALSE,
3199 EL_DIAMOND, -1, MV_BIT_RIGHT
3202 Xdiamond_force_w, FALSE, FALSE,
3203 EL_DIAMOND, -1, MV_BIT_LEFT
3206 Xbomb_force_e, FALSE, FALSE,
3207 EL_BOMB, -1, MV_BIT_RIGHT
3210 Xbomb_force_w, FALSE, FALSE,
3211 EL_BOMB, -1, MV_BIT_LEFT
3213 #endif /* EM_ENGINE_BAD_ROLL */
3216 Xstone, TRUE, FALSE,
3220 Xstone_pause, FALSE, FALSE,
3224 Xstone_fall, FALSE, FALSE,
3228 Ystone_s, FALSE, FALSE,
3229 EL_ROCK, ACTION_FALLING, -1
3232 Ystone_sB, FALSE, TRUE,
3233 EL_ROCK, ACTION_FALLING, -1
3236 Ystone_e, FALSE, FALSE,
3237 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3240 Ystone_eB, FALSE, TRUE,
3241 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3244 Ystone_w, FALSE, FALSE,
3245 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3248 Ystone_wB, FALSE, TRUE,
3249 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3256 Xnut_pause, FALSE, FALSE,
3260 Xnut_fall, FALSE, FALSE,
3264 Ynut_s, FALSE, FALSE,
3265 EL_NUT, ACTION_FALLING, -1
3268 Ynut_sB, FALSE, TRUE,
3269 EL_NUT, ACTION_FALLING, -1
3272 Ynut_e, FALSE, FALSE,
3273 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3276 Ynut_eB, FALSE, TRUE,
3277 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3280 Ynut_w, FALSE, FALSE,
3281 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3284 Ynut_wB, FALSE, TRUE,
3285 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3288 Xbug_n, TRUE, FALSE,
3292 Xbug_e, TRUE, FALSE,
3293 EL_BUG_RIGHT, -1, -1
3296 Xbug_s, TRUE, FALSE,
3300 Xbug_w, TRUE, FALSE,
3304 Xbug_gon, FALSE, FALSE,
3308 Xbug_goe, FALSE, FALSE,
3309 EL_BUG_RIGHT, -1, -1
3312 Xbug_gos, FALSE, FALSE,
3316 Xbug_gow, FALSE, FALSE,
3320 Ybug_n, FALSE, FALSE,
3321 EL_BUG, ACTION_MOVING, MV_BIT_UP
3324 Ybug_nB, FALSE, TRUE,
3325 EL_BUG, ACTION_MOVING, MV_BIT_UP
3328 Ybug_e, FALSE, FALSE,
3329 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3332 Ybug_eB, FALSE, TRUE,
3333 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3336 Ybug_s, FALSE, FALSE,
3337 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3340 Ybug_sB, FALSE, TRUE,
3341 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3344 Ybug_w, FALSE, FALSE,
3345 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3348 Ybug_wB, FALSE, TRUE,
3349 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3352 Ybug_w_n, FALSE, FALSE,
3353 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3356 Ybug_n_e, FALSE, FALSE,
3357 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3360 Ybug_e_s, FALSE, FALSE,
3361 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3364 Ybug_s_w, FALSE, FALSE,
3365 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3368 Ybug_e_n, FALSE, FALSE,
3369 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3372 Ybug_s_e, FALSE, FALSE,
3373 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3376 Ybug_w_s, FALSE, FALSE,
3377 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3380 Ybug_n_w, FALSE, FALSE,
3381 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3384 Ybug_stone, FALSE, FALSE,
3385 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3388 Ybug_spring, FALSE, FALSE,
3389 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3392 Xtank_n, TRUE, FALSE,
3393 EL_SPACESHIP_UP, -1, -1
3396 Xtank_e, TRUE, FALSE,
3397 EL_SPACESHIP_RIGHT, -1, -1
3400 Xtank_s, TRUE, FALSE,
3401 EL_SPACESHIP_DOWN, -1, -1
3404 Xtank_w, TRUE, FALSE,
3405 EL_SPACESHIP_LEFT, -1, -1
3408 Xtank_gon, FALSE, FALSE,
3409 EL_SPACESHIP_UP, -1, -1
3412 Xtank_goe, FALSE, FALSE,
3413 EL_SPACESHIP_RIGHT, -1, -1
3416 Xtank_gos, FALSE, FALSE,
3417 EL_SPACESHIP_DOWN, -1, -1
3420 Xtank_gow, FALSE, FALSE,
3421 EL_SPACESHIP_LEFT, -1, -1
3424 Ytank_n, FALSE, FALSE,
3425 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3428 Ytank_nB, FALSE, TRUE,
3429 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3432 Ytank_e, FALSE, FALSE,
3433 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3436 Ytank_eB, FALSE, TRUE,
3437 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3440 Ytank_s, FALSE, FALSE,
3441 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3444 Ytank_sB, FALSE, TRUE,
3445 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3448 Ytank_w, FALSE, FALSE,
3449 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3452 Ytank_wB, FALSE, TRUE,
3453 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3456 Ytank_w_n, FALSE, FALSE,
3457 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3460 Ytank_n_e, FALSE, FALSE,
3461 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3464 Ytank_e_s, FALSE, FALSE,
3465 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3468 Ytank_s_w, FALSE, FALSE,
3469 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3472 Ytank_e_n, FALSE, FALSE,
3473 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3476 Ytank_s_e, FALSE, FALSE,
3477 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3480 Ytank_w_s, FALSE, FALSE,
3481 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3484 Ytank_n_w, FALSE, FALSE,
3485 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3488 Ytank_stone, FALSE, FALSE,
3489 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3492 Ytank_spring, FALSE, FALSE,
3493 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3496 Xandroid, TRUE, FALSE,
3497 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3500 Xandroid_1_n, FALSE, FALSE,
3501 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3504 Xandroid_2_n, FALSE, FALSE,
3505 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3508 Xandroid_1_e, FALSE, FALSE,
3509 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3512 Xandroid_2_e, FALSE, FALSE,
3513 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3516 Xandroid_1_w, FALSE, FALSE,
3517 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3520 Xandroid_2_w, FALSE, FALSE,
3521 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3524 Xandroid_1_s, FALSE, FALSE,
3525 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3528 Xandroid_2_s, FALSE, FALSE,
3529 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3532 Yandroid_n, FALSE, FALSE,
3533 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3536 Yandroid_nB, FALSE, TRUE,
3537 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3540 Yandroid_ne, FALSE, FALSE,
3541 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3544 Yandroid_neB, FALSE, TRUE,
3545 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3548 Yandroid_e, FALSE, FALSE,
3549 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3552 Yandroid_eB, FALSE, TRUE,
3553 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3556 Yandroid_se, FALSE, FALSE,
3557 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3560 Yandroid_seB, FALSE, TRUE,
3561 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3564 Yandroid_s, FALSE, FALSE,
3565 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3568 Yandroid_sB, FALSE, TRUE,
3569 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3572 Yandroid_sw, FALSE, FALSE,
3573 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3576 Yandroid_swB, FALSE, TRUE,
3577 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3580 Yandroid_w, FALSE, FALSE,
3581 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3584 Yandroid_wB, FALSE, TRUE,
3585 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3588 Yandroid_nw, FALSE, FALSE,
3589 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3592 Yandroid_nwB, FALSE, TRUE,
3593 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3596 Xspring, TRUE, FALSE,
3600 Xspring_pause, FALSE, FALSE,
3604 Xspring_e, FALSE, FALSE,
3608 Xspring_w, FALSE, FALSE,
3612 Xspring_fall, FALSE, FALSE,
3616 Yspring_s, FALSE, FALSE,
3617 EL_SPRING, ACTION_FALLING, -1
3620 Yspring_sB, FALSE, TRUE,
3621 EL_SPRING, ACTION_FALLING, -1
3624 Yspring_e, FALSE, FALSE,
3625 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3628 Yspring_eB, FALSE, TRUE,
3629 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3632 Yspring_w, FALSE, FALSE,
3633 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3636 Yspring_wB, FALSE, TRUE,
3637 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3640 Yspring_kill_e, FALSE, FALSE,
3641 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3644 Yspring_kill_eB, FALSE, TRUE,
3645 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3648 Yspring_kill_w, FALSE, FALSE,
3649 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3652 Yspring_kill_wB, FALSE, TRUE,
3653 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3656 Xeater_n, TRUE, FALSE,
3657 EL_YAMYAM_UP, -1, -1
3660 Xeater_e, TRUE, FALSE,
3661 EL_YAMYAM_RIGHT, -1, -1
3664 Xeater_w, TRUE, FALSE,
3665 EL_YAMYAM_LEFT, -1, -1
3668 Xeater_s, TRUE, FALSE,
3669 EL_YAMYAM_DOWN, -1, -1
3672 Yeater_n, FALSE, FALSE,
3673 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3676 Yeater_nB, FALSE, TRUE,
3677 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3680 Yeater_e, FALSE, FALSE,
3681 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3684 Yeater_eB, FALSE, TRUE,
3685 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3688 Yeater_s, FALSE, FALSE,
3689 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3692 Yeater_sB, FALSE, TRUE,
3693 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3696 Yeater_w, FALSE, FALSE,
3697 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3700 Yeater_wB, FALSE, TRUE,
3701 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3704 Yeater_stone, FALSE, FALSE,
3705 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3708 Yeater_spring, FALSE, FALSE,
3709 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3712 Xalien, TRUE, FALSE,
3716 Xalien_pause, FALSE, FALSE,
3720 Yalien_n, FALSE, FALSE,
3721 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3724 Yalien_nB, FALSE, TRUE,
3725 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3728 Yalien_e, FALSE, FALSE,
3729 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3732 Yalien_eB, FALSE, TRUE,
3733 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3736 Yalien_s, FALSE, FALSE,
3737 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3740 Yalien_sB, FALSE, TRUE,
3741 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3744 Yalien_w, FALSE, FALSE,
3745 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3748 Yalien_wB, FALSE, TRUE,
3749 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3752 Yalien_stone, FALSE, FALSE,
3753 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3756 Yalien_spring, FALSE, FALSE,
3757 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3760 Xemerald, TRUE, FALSE,
3764 Xemerald_pause, FALSE, FALSE,
3768 Xemerald_fall, FALSE, FALSE,
3772 Xemerald_shine, FALSE, FALSE,
3773 EL_EMERALD, ACTION_TWINKLING, -1
3776 Yemerald_s, FALSE, FALSE,
3777 EL_EMERALD, ACTION_FALLING, -1
3780 Yemerald_sB, FALSE, TRUE,
3781 EL_EMERALD, ACTION_FALLING, -1
3784 Yemerald_e, FALSE, FALSE,
3785 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3788 Yemerald_eB, FALSE, TRUE,
3789 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3792 Yemerald_w, FALSE, FALSE,
3793 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3796 Yemerald_wB, FALSE, TRUE,
3797 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3800 Yemerald_eat, FALSE, FALSE,
3801 EL_EMERALD, ACTION_COLLECTING, -1
3804 Yemerald_stone, FALSE, FALSE,
3805 EL_NUT, ACTION_BREAKING, -1
3808 Xdiamond, TRUE, FALSE,
3812 Xdiamond_pause, FALSE, FALSE,
3816 Xdiamond_fall, FALSE, FALSE,
3820 Xdiamond_shine, FALSE, FALSE,
3821 EL_DIAMOND, ACTION_TWINKLING, -1
3824 Ydiamond_s, FALSE, FALSE,
3825 EL_DIAMOND, ACTION_FALLING, -1
3828 Ydiamond_sB, FALSE, TRUE,
3829 EL_DIAMOND, ACTION_FALLING, -1
3832 Ydiamond_e, FALSE, FALSE,
3833 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3836 Ydiamond_eB, FALSE, TRUE,
3837 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3840 Ydiamond_w, FALSE, FALSE,
3841 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3844 Ydiamond_wB, FALSE, TRUE,
3845 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3848 Ydiamond_eat, FALSE, FALSE,
3849 EL_DIAMOND, ACTION_COLLECTING, -1
3852 Ydiamond_stone, FALSE, FALSE,
3853 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3856 Xdrip_fall, TRUE, FALSE,
3857 EL_AMOEBA_DROP, -1, -1
3860 Xdrip_stretch, FALSE, FALSE,
3861 EL_AMOEBA_DROP, ACTION_FALLING, -1
3864 Xdrip_stretchB, FALSE, TRUE,
3865 EL_AMOEBA_DROP, ACTION_FALLING, -1
3868 Xdrip_eat, FALSE, FALSE,
3869 EL_AMOEBA_DROP, ACTION_GROWING, -1
3872 Ydrip_s1, FALSE, FALSE,
3873 EL_AMOEBA_DROP, ACTION_FALLING, -1
3876 Ydrip_s1B, FALSE, TRUE,
3877 EL_AMOEBA_DROP, ACTION_FALLING, -1
3880 Ydrip_s2, FALSE, FALSE,
3881 EL_AMOEBA_DROP, ACTION_FALLING, -1
3884 Ydrip_s2B, FALSE, TRUE,
3885 EL_AMOEBA_DROP, ACTION_FALLING, -1
3892 Xbomb_pause, FALSE, FALSE,
3896 Xbomb_fall, FALSE, FALSE,
3900 Ybomb_s, FALSE, FALSE,
3901 EL_BOMB, ACTION_FALLING, -1
3904 Ybomb_sB, FALSE, TRUE,
3905 EL_BOMB, ACTION_FALLING, -1
3908 Ybomb_e, FALSE, FALSE,
3909 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3912 Ybomb_eB, FALSE, TRUE,
3913 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3916 Ybomb_w, FALSE, FALSE,
3917 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3920 Ybomb_wB, FALSE, TRUE,
3921 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3924 Ybomb_eat, FALSE, FALSE,
3925 EL_BOMB, ACTION_ACTIVATING, -1
3928 Xballoon, TRUE, FALSE,
3932 Yballoon_n, FALSE, FALSE,
3933 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3936 Yballoon_nB, FALSE, TRUE,
3937 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3940 Yballoon_e, FALSE, FALSE,
3941 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3944 Yballoon_eB, FALSE, TRUE,
3945 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3948 Yballoon_s, FALSE, FALSE,
3949 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3952 Yballoon_sB, FALSE, TRUE,
3953 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3956 Yballoon_w, FALSE, FALSE,
3957 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3960 Yballoon_wB, FALSE, TRUE,
3961 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3964 Xgrass, TRUE, FALSE,
3965 EL_EMC_GRASS, -1, -1
3968 Ygrass_nB, FALSE, FALSE,
3969 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3972 Ygrass_eB, FALSE, FALSE,
3973 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3976 Ygrass_sB, FALSE, FALSE,
3977 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3980 Ygrass_wB, FALSE, FALSE,
3981 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
3988 Ydirt_nB, FALSE, FALSE,
3989 EL_SAND, ACTION_DIGGING, MV_BIT_UP
3992 Ydirt_eB, FALSE, FALSE,
3993 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
3996 Ydirt_sB, FALSE, FALSE,
3997 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4000 Ydirt_wB, FALSE, FALSE,
4001 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4004 Xacid_ne, TRUE, FALSE,
4005 EL_ACID_POOL_TOPRIGHT, -1, -1
4008 Xacid_se, TRUE, FALSE,
4009 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4012 Xacid_s, TRUE, FALSE,
4013 EL_ACID_POOL_BOTTOM, -1, -1
4016 Xacid_sw, TRUE, FALSE,
4017 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4020 Xacid_nw, TRUE, FALSE,
4021 EL_ACID_POOL_TOPLEFT, -1, -1
4024 Xacid_1, TRUE, FALSE,
4028 Xacid_2, FALSE, FALSE,
4032 Xacid_3, FALSE, FALSE,
4036 Xacid_4, FALSE, FALSE,
4040 Xacid_5, FALSE, FALSE,
4044 Xacid_6, FALSE, FALSE,
4048 Xacid_7, FALSE, FALSE,
4052 Xacid_8, FALSE, FALSE,
4056 Xball_1, TRUE, FALSE,
4057 EL_EMC_MAGIC_BALL, -1, -1
4060 Xball_1B, FALSE, FALSE,
4061 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4064 Xball_2, FALSE, FALSE,
4065 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4068 Xball_2B, FALSE, FALSE,
4069 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4072 Yball_eat, FALSE, FALSE,
4073 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4076 Ykey_1_eat, FALSE, FALSE,
4077 EL_EM_KEY_1, ACTION_COLLECTING, -1
4080 Ykey_2_eat, FALSE, FALSE,
4081 EL_EM_KEY_2, ACTION_COLLECTING, -1
4084 Ykey_3_eat, FALSE, FALSE,
4085 EL_EM_KEY_3, ACTION_COLLECTING, -1
4088 Ykey_4_eat, FALSE, FALSE,
4089 EL_EM_KEY_4, ACTION_COLLECTING, -1
4092 Ykey_5_eat, FALSE, FALSE,
4093 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4096 Ykey_6_eat, FALSE, FALSE,
4097 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4100 Ykey_7_eat, FALSE, FALSE,
4101 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4104 Ykey_8_eat, FALSE, FALSE,
4105 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4108 Ylenses_eat, FALSE, FALSE,
4109 EL_EMC_LENSES, ACTION_COLLECTING, -1
4112 Ymagnify_eat, FALSE, FALSE,
4113 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4116 Ygrass_eat, FALSE, FALSE,
4117 EL_EMC_GRASS, ACTION_SNAPPING, -1
4120 Ydirt_eat, FALSE, FALSE,
4121 EL_SAND, ACTION_SNAPPING, -1
4124 Xgrow_ns, TRUE, FALSE,
4125 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4128 Ygrow_ns_eat, FALSE, FALSE,
4129 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4132 Xgrow_ew, TRUE, FALSE,
4133 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4136 Ygrow_ew_eat, FALSE, FALSE,
4137 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4140 Xwonderwall, TRUE, FALSE,
4141 EL_MAGIC_WALL, -1, -1
4144 XwonderwallB, FALSE, FALSE,
4145 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4148 Xamoeba_1, TRUE, FALSE,
4149 EL_AMOEBA_DRY, ACTION_OTHER, -1
4152 Xamoeba_2, FALSE, FALSE,
4153 EL_AMOEBA_DRY, ACTION_OTHER, -1
4156 Xamoeba_3, FALSE, FALSE,
4157 EL_AMOEBA_DRY, ACTION_OTHER, -1
4160 Xamoeba_4, FALSE, FALSE,
4161 EL_AMOEBA_DRY, ACTION_OTHER, -1
4164 Xamoeba_5, TRUE, FALSE,
4165 EL_AMOEBA_WET, ACTION_OTHER, -1
4168 Xamoeba_6, FALSE, FALSE,
4169 EL_AMOEBA_WET, ACTION_OTHER, -1
4172 Xamoeba_7, FALSE, FALSE,
4173 EL_AMOEBA_WET, ACTION_OTHER, -1
4176 Xamoeba_8, FALSE, FALSE,
4177 EL_AMOEBA_WET, ACTION_OTHER, -1
4180 Xdoor_1, TRUE, FALSE,
4181 EL_EM_GATE_1, -1, -1
4184 Xdoor_2, TRUE, FALSE,
4185 EL_EM_GATE_2, -1, -1
4188 Xdoor_3, TRUE, FALSE,
4189 EL_EM_GATE_3, -1, -1
4192 Xdoor_4, TRUE, FALSE,
4193 EL_EM_GATE_4, -1, -1
4196 Xdoor_5, TRUE, FALSE,
4197 EL_EMC_GATE_5, -1, -1
4200 Xdoor_6, TRUE, FALSE,
4201 EL_EMC_GATE_6, -1, -1
4204 Xdoor_7, TRUE, FALSE,
4205 EL_EMC_GATE_7, -1, -1
4208 Xdoor_8, TRUE, FALSE,
4209 EL_EMC_GATE_8, -1, -1
4212 Xkey_1, TRUE, FALSE,
4216 Xkey_2, TRUE, FALSE,
4220 Xkey_3, TRUE, FALSE,
4224 Xkey_4, TRUE, FALSE,
4228 Xkey_5, TRUE, FALSE,
4229 EL_EMC_KEY_5, -1, -1
4232 Xkey_6, TRUE, FALSE,
4233 EL_EMC_KEY_6, -1, -1
4236 Xkey_7, TRUE, FALSE,
4237 EL_EMC_KEY_7, -1, -1
4240 Xkey_8, TRUE, FALSE,
4241 EL_EMC_KEY_8, -1, -1
4244 Xwind_n, TRUE, FALSE,
4245 EL_BALLOON_SWITCH_UP, -1, -1
4248 Xwind_e, TRUE, FALSE,
4249 EL_BALLOON_SWITCH_RIGHT, -1, -1
4252 Xwind_s, TRUE, FALSE,
4253 EL_BALLOON_SWITCH_DOWN, -1, -1
4256 Xwind_w, TRUE, FALSE,
4257 EL_BALLOON_SWITCH_LEFT, -1, -1
4260 Xwind_nesw, TRUE, FALSE,
4261 EL_BALLOON_SWITCH_ANY, -1, -1
4264 Xwind_stop, TRUE, FALSE,
4265 EL_BALLOON_SWITCH_NONE, -1, -1
4269 EL_EXIT_CLOSED, -1, -1
4272 Xexit_1, TRUE, FALSE,
4273 EL_EXIT_OPEN, -1, -1
4276 Xexit_2, FALSE, FALSE,
4277 EL_EXIT_OPEN, -1, -1
4280 Xexit_3, FALSE, FALSE,
4281 EL_EXIT_OPEN, -1, -1
4284 Xdynamite, TRUE, FALSE,
4285 EL_EM_DYNAMITE, -1, -1
4288 Ydynamite_eat, FALSE, FALSE,
4289 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4292 Xdynamite_1, TRUE, FALSE,
4293 EL_EM_DYNAMITE_ACTIVE, -1, -1
4296 Xdynamite_2, FALSE, FALSE,
4297 EL_EM_DYNAMITE_ACTIVE, -1, -1
4300 Xdynamite_3, FALSE, FALSE,
4301 EL_EM_DYNAMITE_ACTIVE, -1, -1
4304 Xdynamite_4, FALSE, FALSE,
4305 EL_EM_DYNAMITE_ACTIVE, -1, -1
4308 Xbumper, TRUE, FALSE,
4309 EL_EMC_SPRING_BUMPER, -1, -1
4312 XbumperB, FALSE, FALSE,
4313 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4316 Xwheel, TRUE, FALSE,
4317 EL_ROBOT_WHEEL, -1, -1
4320 XwheelB, FALSE, FALSE,
4321 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4324 Xswitch, TRUE, FALSE,
4325 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4328 XswitchB, FALSE, FALSE,
4329 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4333 EL_QUICKSAND_EMPTY, -1, -1
4336 Xsand_stone, TRUE, FALSE,
4337 EL_QUICKSAND_FULL, -1, -1
4340 Xsand_stonein_1, FALSE, TRUE,
4341 EL_ROCK, ACTION_FILLING, -1
4344 Xsand_stonein_2, FALSE, TRUE,
4345 EL_ROCK, ACTION_FILLING, -1
4348 Xsand_stonein_3, FALSE, TRUE,
4349 EL_ROCK, ACTION_FILLING, -1
4352 Xsand_stonein_4, FALSE, TRUE,
4353 EL_ROCK, ACTION_FILLING, -1
4356 Xsand_stonesand_1, FALSE, FALSE,
4357 EL_QUICKSAND_FULL, -1, -1
4360 Xsand_stonesand_2, FALSE, FALSE,
4361 EL_QUICKSAND_FULL, -1, -1
4364 Xsand_stonesand_3, FALSE, FALSE,
4365 EL_QUICKSAND_FULL, -1, -1
4368 Xsand_stonesand_4, FALSE, FALSE,
4369 EL_QUICKSAND_FULL, -1, -1
4372 Xsand_stoneout_1, FALSE, FALSE,
4373 EL_ROCK, ACTION_EMPTYING, -1
4376 Xsand_stoneout_2, FALSE, FALSE,
4377 EL_ROCK, ACTION_EMPTYING, -1
4380 Xsand_sandstone_1, FALSE, FALSE,
4381 EL_QUICKSAND_FULL, -1, -1
4384 Xsand_sandstone_2, FALSE, FALSE,
4385 EL_QUICKSAND_FULL, -1, -1
4388 Xsand_sandstone_3, FALSE, FALSE,
4389 EL_QUICKSAND_FULL, -1, -1
4392 Xsand_sandstone_4, FALSE, FALSE,
4393 EL_QUICKSAND_FULL, -1, -1
4396 Xplant, TRUE, FALSE,
4397 EL_EMC_PLANT, -1, -1
4400 Yplant, FALSE, FALSE,
4401 EL_EMC_PLANT, -1, -1
4404 Xlenses, TRUE, FALSE,
4405 EL_EMC_LENSES, -1, -1
4408 Xmagnify, TRUE, FALSE,
4409 EL_EMC_MAGNIFIER, -1, -1
4412 Xdripper, TRUE, FALSE,
4413 EL_EMC_DRIPPER, -1, -1
4416 XdripperB, FALSE, FALSE,
4417 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4420 Xfake_blank, TRUE, FALSE,
4421 EL_INVISIBLE_WALL, -1, -1
4424 Xfake_blankB, FALSE, FALSE,
4425 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4428 Xfake_grass, TRUE, FALSE,
4429 EL_EMC_FAKE_GRASS, -1, -1
4432 Xfake_grassB, FALSE, FALSE,
4433 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4436 Xfake_door_1, TRUE, FALSE,
4437 EL_EM_GATE_1_GRAY, -1, -1
4440 Xfake_door_2, TRUE, FALSE,
4441 EL_EM_GATE_2_GRAY, -1, -1
4444 Xfake_door_3, TRUE, FALSE,
4445 EL_EM_GATE_3_GRAY, -1, -1
4448 Xfake_door_4, TRUE, FALSE,
4449 EL_EM_GATE_4_GRAY, -1, -1
4452 Xfake_door_5, TRUE, FALSE,
4453 EL_EMC_GATE_5_GRAY, -1, -1
4456 Xfake_door_6, TRUE, FALSE,
4457 EL_EMC_GATE_6_GRAY, -1, -1
4460 Xfake_door_7, TRUE, FALSE,
4461 EL_EMC_GATE_7_GRAY, -1, -1
4464 Xfake_door_8, TRUE, FALSE,
4465 EL_EMC_GATE_8_GRAY, -1, -1
4468 Xfake_acid_1, TRUE, FALSE,
4469 EL_EMC_FAKE_ACID, -1, -1
4472 Xfake_acid_2, FALSE, FALSE,
4473 EL_EMC_FAKE_ACID, -1, -1
4476 Xfake_acid_3, FALSE, FALSE,
4477 EL_EMC_FAKE_ACID, -1, -1
4480 Xfake_acid_4, FALSE, FALSE,
4481 EL_EMC_FAKE_ACID, -1, -1
4484 Xfake_acid_5, FALSE, FALSE,
4485 EL_EMC_FAKE_ACID, -1, -1
4488 Xfake_acid_6, FALSE, FALSE,
4489 EL_EMC_FAKE_ACID, -1, -1
4492 Xfake_acid_7, FALSE, FALSE,
4493 EL_EMC_FAKE_ACID, -1, -1
4496 Xfake_acid_8, FALSE, FALSE,
4497 EL_EMC_FAKE_ACID, -1, -1
4500 Xsteel_1, TRUE, FALSE,
4501 EL_STEELWALL, -1, -1
4504 Xsteel_2, TRUE, FALSE,
4505 EL_EMC_STEELWALL_2, -1, -1
4508 Xsteel_3, TRUE, FALSE,
4509 EL_EMC_STEELWALL_3, -1, -1
4512 Xsteel_4, TRUE, FALSE,
4513 EL_EMC_STEELWALL_4, -1, -1
4516 Xwall_1, TRUE, FALSE,
4520 Xwall_2, TRUE, FALSE,
4521 EL_EMC_WALL_14, -1, -1
4524 Xwall_3, TRUE, FALSE,
4525 EL_EMC_WALL_15, -1, -1
4528 Xwall_4, TRUE, FALSE,
4529 EL_EMC_WALL_16, -1, -1
4532 Xround_wall_1, TRUE, FALSE,
4533 EL_WALL_SLIPPERY, -1, -1
4536 Xround_wall_2, TRUE, FALSE,
4537 EL_EMC_WALL_SLIPPERY_2, -1, -1
4540 Xround_wall_3, TRUE, FALSE,
4541 EL_EMC_WALL_SLIPPERY_3, -1, -1
4544 Xround_wall_4, TRUE, FALSE,
4545 EL_EMC_WALL_SLIPPERY_4, -1, -1
4548 Xdecor_1, TRUE, FALSE,
4549 EL_EMC_WALL_8, -1, -1
4552 Xdecor_2, TRUE, FALSE,
4553 EL_EMC_WALL_6, -1, -1
4556 Xdecor_3, TRUE, FALSE,
4557 EL_EMC_WALL_4, -1, -1
4560 Xdecor_4, TRUE, FALSE,
4561 EL_EMC_WALL_7, -1, -1
4564 Xdecor_5, TRUE, FALSE,
4565 EL_EMC_WALL_5, -1, -1
4568 Xdecor_6, TRUE, FALSE,
4569 EL_EMC_WALL_9, -1, -1
4572 Xdecor_7, TRUE, FALSE,
4573 EL_EMC_WALL_10, -1, -1
4576 Xdecor_8, TRUE, FALSE,
4577 EL_EMC_WALL_1, -1, -1
4580 Xdecor_9, TRUE, FALSE,
4581 EL_EMC_WALL_2, -1, -1
4584 Xdecor_10, TRUE, FALSE,
4585 EL_EMC_WALL_3, -1, -1
4588 Xdecor_11, TRUE, FALSE,
4589 EL_EMC_WALL_11, -1, -1
4592 Xdecor_12, TRUE, FALSE,
4593 EL_EMC_WALL_12, -1, -1
4596 Xalpha_0, TRUE, FALSE,
4597 EL_CHAR('0'), -1, -1
4600 Xalpha_1, TRUE, FALSE,
4601 EL_CHAR('1'), -1, -1
4604 Xalpha_2, TRUE, FALSE,
4605 EL_CHAR('2'), -1, -1
4608 Xalpha_3, TRUE, FALSE,
4609 EL_CHAR('3'), -1, -1
4612 Xalpha_4, TRUE, FALSE,
4613 EL_CHAR('4'), -1, -1
4616 Xalpha_5, TRUE, FALSE,
4617 EL_CHAR('5'), -1, -1
4620 Xalpha_6, TRUE, FALSE,
4621 EL_CHAR('6'), -1, -1
4624 Xalpha_7, TRUE, FALSE,
4625 EL_CHAR('7'), -1, -1
4628 Xalpha_8, TRUE, FALSE,
4629 EL_CHAR('8'), -1, -1
4632 Xalpha_9, TRUE, FALSE,
4633 EL_CHAR('9'), -1, -1
4636 Xalpha_excla, TRUE, FALSE,
4637 EL_CHAR('!'), -1, -1
4640 Xalpha_quote, TRUE, FALSE,
4641 EL_CHAR('"'), -1, -1
4644 Xalpha_comma, TRUE, FALSE,
4645 EL_CHAR(','), -1, -1
4648 Xalpha_minus, TRUE, FALSE,
4649 EL_CHAR('-'), -1, -1
4652 Xalpha_perio, TRUE, FALSE,
4653 EL_CHAR('.'), -1, -1
4656 Xalpha_colon, TRUE, FALSE,
4657 EL_CHAR(':'), -1, -1
4660 Xalpha_quest, TRUE, FALSE,
4661 EL_CHAR('?'), -1, -1
4664 Xalpha_a, TRUE, FALSE,
4665 EL_CHAR('A'), -1, -1
4668 Xalpha_b, TRUE, FALSE,
4669 EL_CHAR('B'), -1, -1
4672 Xalpha_c, TRUE, FALSE,
4673 EL_CHAR('C'), -1, -1
4676 Xalpha_d, TRUE, FALSE,
4677 EL_CHAR('D'), -1, -1
4680 Xalpha_e, TRUE, FALSE,
4681 EL_CHAR('E'), -1, -1
4684 Xalpha_f, TRUE, FALSE,
4685 EL_CHAR('F'), -1, -1
4688 Xalpha_g, TRUE, FALSE,
4689 EL_CHAR('G'), -1, -1
4692 Xalpha_h, TRUE, FALSE,
4693 EL_CHAR('H'), -1, -1
4696 Xalpha_i, TRUE, FALSE,
4697 EL_CHAR('I'), -1, -1
4700 Xalpha_j, TRUE, FALSE,
4701 EL_CHAR('J'), -1, -1
4704 Xalpha_k, TRUE, FALSE,
4705 EL_CHAR('K'), -1, -1
4708 Xalpha_l, TRUE, FALSE,
4709 EL_CHAR('L'), -1, -1
4712 Xalpha_m, TRUE, FALSE,
4713 EL_CHAR('M'), -1, -1
4716 Xalpha_n, TRUE, FALSE,
4717 EL_CHAR('N'), -1, -1
4720 Xalpha_o, TRUE, FALSE,
4721 EL_CHAR('O'), -1, -1
4724 Xalpha_p, TRUE, FALSE,
4725 EL_CHAR('P'), -1, -1
4728 Xalpha_q, TRUE, FALSE,
4729 EL_CHAR('Q'), -1, -1
4732 Xalpha_r, TRUE, FALSE,
4733 EL_CHAR('R'), -1, -1
4736 Xalpha_s, TRUE, FALSE,
4737 EL_CHAR('S'), -1, -1
4740 Xalpha_t, TRUE, FALSE,
4741 EL_CHAR('T'), -1, -1
4744 Xalpha_u, TRUE, FALSE,
4745 EL_CHAR('U'), -1, -1
4748 Xalpha_v, TRUE, FALSE,
4749 EL_CHAR('V'), -1, -1
4752 Xalpha_w, TRUE, FALSE,
4753 EL_CHAR('W'), -1, -1
4756 Xalpha_x, TRUE, FALSE,
4757 EL_CHAR('X'), -1, -1
4760 Xalpha_y, TRUE, FALSE,
4761 EL_CHAR('Y'), -1, -1
4764 Xalpha_z, TRUE, FALSE,
4765 EL_CHAR('Z'), -1, -1
4768 Xalpha_arrow_e, TRUE, FALSE,
4769 EL_CHAR('>'), -1, -1
4772 Xalpha_arrow_w, TRUE, FALSE,
4773 EL_CHAR('<'), -1, -1
4776 Xalpha_copyr, TRUE, FALSE,
4777 EL_CHAR('©'), -1, -1
4781 Xboom_bug, FALSE, FALSE,
4782 EL_BUG, ACTION_EXPLODING, -1
4785 Xboom_bomb, FALSE, FALSE,
4786 EL_BOMB, ACTION_EXPLODING, -1
4789 Xboom_android, FALSE, FALSE,
4790 EL_EMC_ANDROID, ACTION_OTHER, -1
4793 Xboom_1, FALSE, FALSE,
4794 EL_DEFAULT, ACTION_EXPLODING, -1
4797 Xboom_2, FALSE, FALSE,
4798 EL_DEFAULT, ACTION_EXPLODING, -1
4801 Znormal, FALSE, FALSE,
4805 Zdynamite, FALSE, FALSE,
4809 Zplayer, FALSE, FALSE,
4813 ZBORDER, FALSE, FALSE,
4823 static struct Mapping_EM_to_RND_player
4832 em_player_mapping_list[] =
4836 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4840 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4844 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4848 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4852 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4856 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4860 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4864 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4868 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4872 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4876 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4880 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4884 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4888 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4892 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4896 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4900 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4904 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4908 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4912 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4916 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4920 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4924 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4928 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4932 EL_PLAYER_1, ACTION_DEFAULT, -1,
4936 EL_PLAYER_2, ACTION_DEFAULT, -1,
4940 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4944 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4948 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4952 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4956 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4960 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4964 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4968 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4972 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4976 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4980 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
4984 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
4988 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
4992 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
4996 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5000 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5004 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5008 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5012 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5016 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5020 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5024 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5028 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5032 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5036 EL_PLAYER_3, ACTION_DEFAULT, -1,
5040 EL_PLAYER_4, ACTION_DEFAULT, -1,
5049 int map_element_RND_to_EM(int element_rnd)
5051 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5052 static boolean mapping_initialized = FALSE;
5054 if (!mapping_initialized)
5058 /* return "Xalpha_quest" for all undefined elements in mapping array */
5059 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5060 mapping_RND_to_EM[i] = Xalpha_quest;
5062 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5063 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5064 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5065 em_object_mapping_list[i].element_em;
5067 mapping_initialized = TRUE;
5070 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5071 return mapping_RND_to_EM[element_rnd];
5073 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5078 int map_element_EM_to_RND(int element_em)
5080 static unsigned short mapping_EM_to_RND[TILE_MAX];
5081 static boolean mapping_initialized = FALSE;
5083 if (!mapping_initialized)
5087 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5088 for (i = 0; i < TILE_MAX; i++)
5089 mapping_EM_to_RND[i] = EL_UNKNOWN;
5091 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5092 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5093 em_object_mapping_list[i].element_rnd;
5095 mapping_initialized = TRUE;
5098 if (element_em >= 0 && element_em < TILE_MAX)
5099 return mapping_EM_to_RND[element_em];
5101 Error(ERR_WARN, "invalid EM level element %d", element_em);
5106 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5108 struct LevelInfo_EM *level_em = level->native_em_level;
5109 struct LEVEL *lev = level_em->lev;
5112 for (i = 0; i < TILE_MAX; i++)
5113 lev->android_array[i] = Xblank;
5115 for (i = 0; i < level->num_android_clone_elements; i++)
5117 int element_rnd = level->android_clone_element[i];
5118 int element_em = map_element_RND_to_EM(element_rnd);
5120 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5121 if (em_object_mapping_list[j].element_rnd == element_rnd)
5122 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5126 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5128 struct LevelInfo_EM *level_em = level->native_em_level;
5129 struct LEVEL *lev = level_em->lev;
5132 level->num_android_clone_elements = 0;
5134 for (i = 0; i < TILE_MAX; i++)
5136 int element_em = lev->android_array[i];
5138 boolean element_found = FALSE;
5140 if (element_em == Xblank)
5143 element_rnd = map_element_EM_to_RND(element_em);
5145 for (j = 0; j < level->num_android_clone_elements; j++)
5146 if (level->android_clone_element[j] == element_rnd)
5147 element_found = TRUE;
5151 level->android_clone_element[level->num_android_clone_elements++] =
5154 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5159 if (level->num_android_clone_elements == 0)
5161 level->num_android_clone_elements = 1;
5162 level->android_clone_element[0] = EL_EMPTY;
5166 int map_direction_RND_to_EM(int direction)
5168 return (direction == MV_UP ? 0 :
5169 direction == MV_RIGHT ? 1 :
5170 direction == MV_DOWN ? 2 :
5171 direction == MV_LEFT ? 3 :
5175 int map_direction_EM_to_RND(int direction)
5177 return (direction == 0 ? MV_UP :
5178 direction == 1 ? MV_RIGHT :
5179 direction == 2 ? MV_DOWN :
5180 direction == 3 ? MV_LEFT :
5184 int get_next_element(int element)
5188 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5189 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5190 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5191 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5192 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5193 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5194 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5196 default: return element;
5201 int el_act_dir2img(int element, int action, int direction)
5203 element = GFX_ELEMENT(element);
5205 if (direction == MV_NONE)
5206 return element_info[element].graphic[action];
5208 direction = MV_DIR_TO_BIT(direction);
5210 return element_info[element].direction_graphic[action][direction];
5213 int el_act_dir2img(int element, int action, int direction)
5215 element = GFX_ELEMENT(element);
5216 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5218 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5219 return element_info[element].direction_graphic[action][direction];
5224 static int el_act_dir2crm(int element, int action, int direction)
5226 element = GFX_ELEMENT(element);
5228 if (direction == MV_NONE)
5229 return element_info[element].crumbled[action];
5231 direction = MV_DIR_TO_BIT(direction);
5233 return element_info[element].direction_crumbled[action][direction];
5236 static int el_act_dir2crm(int element, int action, int direction)
5238 element = GFX_ELEMENT(element);
5239 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5241 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5242 return element_info[element].direction_crumbled[action][direction];
5246 int el_act2img(int element, int action)
5248 element = GFX_ELEMENT(element);
5250 return element_info[element].graphic[action];
5253 int el_act2crm(int element, int action)
5255 element = GFX_ELEMENT(element);
5257 return element_info[element].crumbled[action];
5260 int el_dir2img(int element, int direction)
5262 element = GFX_ELEMENT(element);
5264 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5267 int el2baseimg(int element)
5269 return element_info[element].graphic[ACTION_DEFAULT];
5272 int el2img(int element)
5274 element = GFX_ELEMENT(element);
5276 return element_info[element].graphic[ACTION_DEFAULT];
5279 int el2edimg(int element)
5281 element = GFX_ELEMENT(element);
5283 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5286 int el2preimg(int element)
5288 element = GFX_ELEMENT(element);
5290 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5293 int font2baseimg(int font_nr)
5295 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5299 void setCenteredPlayerNr_EM(int centered_player_nr)
5301 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5304 int getCenteredPlayerNr_EM()
5307 if (game.centered_player_nr_next >= 0 &&
5308 !native_em_level.ply[game.centered_player_nr_next]->alive)
5309 game.centered_player_nr_next = game.centered_player_nr;
5312 if (game.centered_player_nr != game.centered_player_nr_next)
5313 game.centered_player_nr = game.centered_player_nr_next;
5315 return game.centered_player_nr;
5318 void setSetCenteredPlayer_EM(boolean set_centered_player)
5320 game.set_centered_player = set_centered_player;
5323 boolean getSetCenteredPlayer_EM()
5325 return game.set_centered_player;
5329 int getNumActivePlayers_EM()
5331 int num_players = 0;
5337 for (i = 0; i < MAX_PLAYERS; i++)
5338 if (tape.player_participates[i])
5345 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5347 int game_frame_delay_value;
5349 game_frame_delay_value =
5350 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5351 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5354 if (tape.playing && tape.warp_forward && !tape.pausing)
5355 game_frame_delay_value = 0;
5357 return game_frame_delay_value;
5361 unsigned int InitRND(long seed)
5363 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5364 return InitEngineRND_EM(seed);
5366 return InitEngineRND(seed);
5369 void InitGraphicInfo_EM(void)
5371 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5372 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5376 int num_em_gfx_errors = 0;
5378 if (graphic_info_em_object[0][0].bitmap == NULL)
5380 /* EM graphics not yet initialized in em_open_all() */
5385 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5388 /* always start with reliable default values */
5389 for (i = 0; i < TILE_MAX; i++)
5391 object_mapping[i].element_rnd = EL_UNKNOWN;
5392 object_mapping[i].is_backside = FALSE;
5393 object_mapping[i].action = ACTION_DEFAULT;
5394 object_mapping[i].direction = MV_NONE;
5397 /* always start with reliable default values */
5398 for (p = 0; p < MAX_PLAYERS; p++)
5400 for (i = 0; i < SPR_MAX; i++)
5402 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5403 player_mapping[p][i].action = ACTION_DEFAULT;
5404 player_mapping[p][i].direction = MV_NONE;
5408 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5410 int e = em_object_mapping_list[i].element_em;
5412 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5413 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5415 if (em_object_mapping_list[i].action != -1)
5416 object_mapping[e].action = em_object_mapping_list[i].action;
5418 if (em_object_mapping_list[i].direction != -1)
5419 object_mapping[e].direction =
5420 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5423 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5425 int a = em_player_mapping_list[i].action_em;
5426 int p = em_player_mapping_list[i].player_nr;
5428 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5430 if (em_player_mapping_list[i].action != -1)
5431 player_mapping[p][a].action = em_player_mapping_list[i].action;
5433 if (em_player_mapping_list[i].direction != -1)
5434 player_mapping[p][a].direction =
5435 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5438 for (i = 0; i < TILE_MAX; i++)
5440 int element = object_mapping[i].element_rnd;
5441 int action = object_mapping[i].action;
5442 int direction = object_mapping[i].direction;
5443 boolean is_backside = object_mapping[i].is_backside;
5444 boolean action_removing = (action == ACTION_DIGGING ||
5445 action == ACTION_SNAPPING ||
5446 action == ACTION_COLLECTING);
5447 boolean action_exploding = ((action == ACTION_EXPLODING ||
5448 action == ACTION_SMASHED_BY_ROCK ||
5449 action == ACTION_SMASHED_BY_SPRING) &&
5450 element != EL_DIAMOND);
5451 boolean action_active = (action == ACTION_ACTIVE);
5452 boolean action_other = (action == ACTION_OTHER);
5454 for (j = 0; j < 8; j++)
5456 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5457 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5459 i == Xdrip_stretch ? element :
5460 i == Xdrip_stretchB ? element :
5461 i == Ydrip_s1 ? element :
5462 i == Ydrip_s1B ? element :
5463 i == Xball_1B ? element :
5464 i == Xball_2 ? element :
5465 i == Xball_2B ? element :
5466 i == Yball_eat ? element :
5467 i == Ykey_1_eat ? element :
5468 i == Ykey_2_eat ? element :
5469 i == Ykey_3_eat ? element :
5470 i == Ykey_4_eat ? element :
5471 i == Ykey_5_eat ? element :
5472 i == Ykey_6_eat ? element :
5473 i == Ykey_7_eat ? element :
5474 i == Ykey_8_eat ? element :
5475 i == Ylenses_eat ? element :
5476 i == Ymagnify_eat ? element :
5477 i == Ygrass_eat ? element :
5478 i == Ydirt_eat ? element :
5479 i == Yemerald_stone ? EL_EMERALD :
5480 i == Ydiamond_stone ? EL_ROCK :
5481 i == Xsand_stonein_1 ? element :
5482 i == Xsand_stonein_2 ? element :
5483 i == Xsand_stonein_3 ? element :
5484 i == Xsand_stonein_4 ? element :
5485 is_backside ? EL_EMPTY :
5486 action_removing ? EL_EMPTY :
5488 int effective_action = (j < 7 ? action :
5489 i == Xdrip_stretch ? action :
5490 i == Xdrip_stretchB ? action :
5491 i == Ydrip_s1 ? action :
5492 i == Ydrip_s1B ? action :
5493 i == Xball_1B ? action :
5494 i == Xball_2 ? action :
5495 i == Xball_2B ? action :
5496 i == Yball_eat ? action :
5497 i == Ykey_1_eat ? action :
5498 i == Ykey_2_eat ? action :
5499 i == Ykey_3_eat ? action :
5500 i == Ykey_4_eat ? action :
5501 i == Ykey_5_eat ? action :
5502 i == Ykey_6_eat ? action :
5503 i == Ykey_7_eat ? action :
5504 i == Ykey_8_eat ? action :
5505 i == Ylenses_eat ? action :
5506 i == Ymagnify_eat ? action :
5507 i == Ygrass_eat ? action :
5508 i == Ydirt_eat ? action :
5509 i == Xsand_stonein_1 ? action :
5510 i == Xsand_stonein_2 ? action :
5511 i == Xsand_stonein_3 ? action :
5512 i == Xsand_stonein_4 ? action :
5513 i == Xsand_stoneout_1 ? action :
5514 i == Xsand_stoneout_2 ? action :
5515 i == Xboom_android ? ACTION_EXPLODING :
5516 action_exploding ? ACTION_EXPLODING :
5517 action_active ? action :
5518 action_other ? action :
5520 int graphic = (el_act_dir2img(effective_element, effective_action,
5522 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5524 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5525 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5526 boolean has_action_graphics = (graphic != base_graphic);
5527 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5528 struct GraphicInfo *g = &graphic_info[graphic];
5529 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5532 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5533 boolean special_animation = (action != ACTION_DEFAULT &&
5534 g->anim_frames == 3 &&
5535 g->anim_delay == 2 &&
5536 g->anim_mode & ANIM_LINEAR);
5537 int sync_frame = (i == Xdrip_stretch ? 7 :
5538 i == Xdrip_stretchB ? 7 :
5539 i == Ydrip_s2 ? j + 8 :
5540 i == Ydrip_s2B ? j + 8 :
5549 i == Xfake_acid_1 ? 0 :
5550 i == Xfake_acid_2 ? 10 :
5551 i == Xfake_acid_3 ? 20 :
5552 i == Xfake_acid_4 ? 30 :
5553 i == Xfake_acid_5 ? 40 :
5554 i == Xfake_acid_6 ? 50 :
5555 i == Xfake_acid_7 ? 60 :
5556 i == Xfake_acid_8 ? 70 :
5558 i == Xball_2B ? j + 8 :
5559 i == Yball_eat ? j + 1 :
5560 i == Ykey_1_eat ? j + 1 :
5561 i == Ykey_2_eat ? j + 1 :
5562 i == Ykey_3_eat ? j + 1 :
5563 i == Ykey_4_eat ? j + 1 :
5564 i == Ykey_5_eat ? j + 1 :
5565 i == Ykey_6_eat ? j + 1 :
5566 i == Ykey_7_eat ? j + 1 :
5567 i == Ykey_8_eat ? j + 1 :
5568 i == Ylenses_eat ? j + 1 :
5569 i == Ymagnify_eat ? j + 1 :
5570 i == Ygrass_eat ? j + 1 :
5571 i == Ydirt_eat ? j + 1 :
5572 i == Xamoeba_1 ? 0 :
5573 i == Xamoeba_2 ? 1 :
5574 i == Xamoeba_3 ? 2 :
5575 i == Xamoeba_4 ? 3 :
5576 i == Xamoeba_5 ? 0 :
5577 i == Xamoeba_6 ? 1 :
5578 i == Xamoeba_7 ? 2 :
5579 i == Xamoeba_8 ? 3 :
5580 i == Xexit_2 ? j + 8 :
5581 i == Xexit_3 ? j + 16 :
5582 i == Xdynamite_1 ? 0 :
5583 i == Xdynamite_2 ? 8 :
5584 i == Xdynamite_3 ? 16 :
5585 i == Xdynamite_4 ? 24 :
5586 i == Xsand_stonein_1 ? j + 1 :
5587 i == Xsand_stonein_2 ? j + 9 :
5588 i == Xsand_stonein_3 ? j + 17 :
5589 i == Xsand_stonein_4 ? j + 25 :
5590 i == Xsand_stoneout_1 && j == 0 ? 0 :
5591 i == Xsand_stoneout_1 && j == 1 ? 0 :
5592 i == Xsand_stoneout_1 && j == 2 ? 1 :
5593 i == Xsand_stoneout_1 && j == 3 ? 2 :
5594 i == Xsand_stoneout_1 && j == 4 ? 2 :
5595 i == Xsand_stoneout_1 && j == 5 ? 3 :
5596 i == Xsand_stoneout_1 && j == 6 ? 4 :
5597 i == Xsand_stoneout_1 && j == 7 ? 4 :
5598 i == Xsand_stoneout_2 && j == 0 ? 5 :
5599 i == Xsand_stoneout_2 && j == 1 ? 6 :
5600 i == Xsand_stoneout_2 && j == 2 ? 7 :
5601 i == Xsand_stoneout_2 && j == 3 ? 8 :
5602 i == Xsand_stoneout_2 && j == 4 ? 9 :
5603 i == Xsand_stoneout_2 && j == 5 ? 11 :
5604 i == Xsand_stoneout_2 && j == 6 ? 13 :
5605 i == Xsand_stoneout_2 && j == 7 ? 15 :
5606 i == Xboom_bug && j == 1 ? 2 :
5607 i == Xboom_bug && j == 2 ? 2 :
5608 i == Xboom_bug && j == 3 ? 4 :
5609 i == Xboom_bug && j == 4 ? 4 :
5610 i == Xboom_bug && j == 5 ? 2 :
5611 i == Xboom_bug && j == 6 ? 2 :
5612 i == Xboom_bug && j == 7 ? 0 :
5613 i == Xboom_bomb && j == 1 ? 2 :
5614 i == Xboom_bomb && j == 2 ? 2 :
5615 i == Xboom_bomb && j == 3 ? 4 :
5616 i == Xboom_bomb && j == 4 ? 4 :
5617 i == Xboom_bomb && j == 5 ? 2 :
5618 i == Xboom_bomb && j == 6 ? 2 :
5619 i == Xboom_bomb && j == 7 ? 0 :
5620 i == Xboom_android && j == 7 ? 6 :
5621 i == Xboom_1 && j == 1 ? 2 :
5622 i == Xboom_1 && j == 2 ? 2 :
5623 i == Xboom_1 && j == 3 ? 4 :
5624 i == Xboom_1 && j == 4 ? 4 :
5625 i == Xboom_1 && j == 5 ? 6 :
5626 i == Xboom_1 && j == 6 ? 6 :
5627 i == Xboom_1 && j == 7 ? 8 :
5628 i == Xboom_2 && j == 0 ? 8 :
5629 i == Xboom_2 && j == 1 ? 8 :
5630 i == Xboom_2 && j == 2 ? 10 :
5631 i == Xboom_2 && j == 3 ? 10 :
5632 i == Xboom_2 && j == 4 ? 10 :
5633 i == Xboom_2 && j == 5 ? 12 :
5634 i == Xboom_2 && j == 6 ? 12 :
5635 i == Xboom_2 && j == 7 ? 12 :
5636 special_animation && j == 4 ? 3 :
5637 effective_action != action ? 0 :
5641 Bitmap *debug_bitmap = g_em->bitmap;
5642 int debug_src_x = g_em->src_x;
5643 int debug_src_y = g_em->src_y;
5646 int frame = getAnimationFrame(g->anim_frames,
5649 g->anim_start_frame,
5652 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5653 g->double_movement && is_backside);
5655 g_em->bitmap = src_bitmap;
5656 g_em->src_x = src_x;
5657 g_em->src_y = src_y;
5658 g_em->src_offset_x = 0;
5659 g_em->src_offset_y = 0;
5660 g_em->dst_offset_x = 0;
5661 g_em->dst_offset_y = 0;
5662 g_em->width = TILEX;
5663 g_em->height = TILEY;
5665 g_em->crumbled_bitmap = NULL;
5666 g_em->crumbled_src_x = 0;
5667 g_em->crumbled_src_y = 0;
5668 g_em->crumbled_border_size = 0;
5670 g_em->has_crumbled_graphics = FALSE;
5671 g_em->preserve_background = FALSE;
5674 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5675 printf("::: empty crumbled: %d [%s], %d, %d\n",
5676 effective_element, element_info[effective_element].token_name,
5677 effective_action, direction);
5680 /* if element can be crumbled, but certain action graphics are just empty
5681 space (like snapping sand with the original R'n'D graphics), do not
5682 treat these empty space graphics as crumbled graphics in EMC engine */
5683 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5685 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5687 g_em->has_crumbled_graphics = TRUE;
5688 g_em->crumbled_bitmap = src_bitmap;
5689 g_em->crumbled_src_x = src_x;
5690 g_em->crumbled_src_y = src_y;
5691 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5695 if (element == EL_ROCK &&
5696 effective_action == ACTION_FILLING)
5697 printf("::: has_action_graphics == %d\n", has_action_graphics);
5700 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5701 effective_action == ACTION_MOVING ||
5702 effective_action == ACTION_PUSHING ||
5703 effective_action == ACTION_EATING)) ||
5704 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5705 effective_action == ACTION_EMPTYING)))
5708 (effective_action == ACTION_FALLING ||
5709 effective_action == ACTION_FILLING ||
5710 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5711 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5712 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5713 int num_steps = (i == Ydrip_s1 ? 16 :
5714 i == Ydrip_s1B ? 16 :
5715 i == Ydrip_s2 ? 16 :
5716 i == Ydrip_s2B ? 16 :
5717 i == Xsand_stonein_1 ? 32 :
5718 i == Xsand_stonein_2 ? 32 :
5719 i == Xsand_stonein_3 ? 32 :
5720 i == Xsand_stonein_4 ? 32 :
5721 i == Xsand_stoneout_1 ? 16 :
5722 i == Xsand_stoneout_2 ? 16 : 8);
5723 int cx = ABS(dx) * (TILEX / num_steps);
5724 int cy = ABS(dy) * (TILEY / num_steps);
5725 int step_frame = (i == Ydrip_s2 ? j + 8 :
5726 i == Ydrip_s2B ? j + 8 :
5727 i == Xsand_stonein_2 ? j + 8 :
5728 i == Xsand_stonein_3 ? j + 16 :
5729 i == Xsand_stonein_4 ? j + 24 :
5730 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5731 int step = (is_backside ? step_frame : num_steps - step_frame);
5733 if (is_backside) /* tile where movement starts */
5735 if (dx < 0 || dy < 0)
5737 g_em->src_offset_x = cx * step;
5738 g_em->src_offset_y = cy * step;
5742 g_em->dst_offset_x = cx * step;
5743 g_em->dst_offset_y = cy * step;
5746 else /* tile where movement ends */
5748 if (dx < 0 || dy < 0)
5750 g_em->dst_offset_x = cx * step;
5751 g_em->dst_offset_y = cy * step;
5755 g_em->src_offset_x = cx * step;
5756 g_em->src_offset_y = cy * step;
5760 g_em->width = TILEX - cx * step;
5761 g_em->height = TILEY - cy * step;
5765 /* create unique graphic identifier to decide if tile must be redrawn */
5766 /* bit 31 - 16 (16 bit): EM style graphic
5767 bit 15 - 12 ( 4 bit): EM style frame
5768 bit 11 - 6 ( 6 bit): graphic width
5769 bit 5 - 0 ( 6 bit): graphic height */
5770 g_em->unique_identifier =
5771 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5773 /* create unique graphic identifier to decide if tile must be redrawn */
5774 /* bit 31 - 16 (16 bit): EM style element
5775 bit 15 - 12 ( 4 bit): EM style frame
5776 bit 11 - 6 ( 6 bit): graphic width
5777 bit 5 - 0 ( 6 bit): graphic height */
5778 g_em->unique_identifier =
5779 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5783 if (effective_element == EL_ROCK)
5784 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5785 effective_action, j, graphic, frame, g_em->unique_identifier);
5791 /* skip check for EMC elements not contained in original EMC artwork */
5792 if (element == EL_EMC_FAKE_ACID)
5796 if (g_em->bitmap != debug_bitmap ||
5797 g_em->src_x != debug_src_x ||
5798 g_em->src_y != debug_src_y ||
5799 g_em->src_offset_x != 0 ||
5800 g_em->src_offset_y != 0 ||
5801 g_em->dst_offset_x != 0 ||
5802 g_em->dst_offset_y != 0 ||
5803 g_em->width != TILEX ||
5804 g_em->height != TILEY)
5806 static int last_i = -1;
5814 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5815 i, element, element_info[element].token_name,
5816 element_action_info[effective_action].suffix, direction);
5818 if (element != effective_element)
5819 printf(" [%d ('%s')]",
5821 element_info[effective_element].token_name);
5825 if (g_em->bitmap != debug_bitmap)
5826 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5827 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5829 if (g_em->src_x != debug_src_x ||
5830 g_em->src_y != debug_src_y)
5831 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5832 j, (is_backside ? 'B' : 'F'),
5833 g_em->src_x, g_em->src_y,
5834 g_em->src_x / 32, g_em->src_y / 32,
5835 debug_src_x, debug_src_y,
5836 debug_src_x / 32, debug_src_y / 32);
5838 if (g_em->src_offset_x != 0 ||
5839 g_em->src_offset_y != 0 ||
5840 g_em->dst_offset_x != 0 ||
5841 g_em->dst_offset_y != 0)
5842 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5844 g_em->src_offset_x, g_em->src_offset_y,
5845 g_em->dst_offset_x, g_em->dst_offset_y);
5847 if (g_em->width != TILEX ||
5848 g_em->height != TILEY)
5849 printf(" %d (%d): size %d,%d should be %d,%d\n",
5851 g_em->width, g_em->height, TILEX, TILEY);
5853 num_em_gfx_errors++;
5860 for (i = 0; i < TILE_MAX; i++)
5862 for (j = 0; j < 8; j++)
5864 int element = object_mapping[i].element_rnd;
5865 int action = object_mapping[i].action;
5866 int direction = object_mapping[i].direction;
5867 boolean is_backside = object_mapping[i].is_backside;
5869 int graphic_action = el_act_dir2img(element, action, direction);
5870 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5872 int graphic_action = element_info[element].graphic[action];
5873 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5876 if ((action == ACTION_SMASHED_BY_ROCK ||
5877 action == ACTION_SMASHED_BY_SPRING ||
5878 action == ACTION_EATING) &&
5879 graphic_action == graphic_default)
5881 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5882 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5883 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5884 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5887 /* no separate animation for "smashed by rock" -- use rock instead */
5888 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5889 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5891 g_em->bitmap = g_xx->bitmap;
5892 g_em->src_x = g_xx->src_x;
5893 g_em->src_y = g_xx->src_y;
5894 g_em->src_offset_x = g_xx->src_offset_x;
5895 g_em->src_offset_y = g_xx->src_offset_y;
5896 g_em->dst_offset_x = g_xx->dst_offset_x;
5897 g_em->dst_offset_y = g_xx->dst_offset_y;
5898 g_em->width = g_xx->width;
5899 g_em->height = g_xx->height;
5901 g_em->unique_identifier = g_xx->unique_identifier;
5905 g_em->preserve_background = TRUE;
5910 for (p = 0; p < MAX_PLAYERS; p++)
5912 for (i = 0; i < SPR_MAX; i++)
5914 int element = player_mapping[p][i].element_rnd;
5915 int action = player_mapping[p][i].action;
5916 int direction = player_mapping[p][i].direction;
5918 for (j = 0; j < 8; j++)
5920 int effective_element = element;
5921 int effective_action = action;
5922 int graphic = (direction == MV_NONE ?
5923 el_act2img(effective_element, effective_action) :
5924 el_act_dir2img(effective_element, effective_action,
5926 struct GraphicInfo *g = &graphic_info[graphic];
5927 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5933 Bitmap *debug_bitmap = g_em->bitmap;
5934 int debug_src_x = g_em->src_x;
5935 int debug_src_y = g_em->src_y;
5938 int frame = getAnimationFrame(g->anim_frames,
5941 g->anim_start_frame,
5944 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5946 g_em->bitmap = src_bitmap;
5947 g_em->src_x = src_x;
5948 g_em->src_y = src_y;
5949 g_em->src_offset_x = 0;
5950 g_em->src_offset_y = 0;
5951 g_em->dst_offset_x = 0;
5952 g_em->dst_offset_y = 0;
5953 g_em->width = TILEX;
5954 g_em->height = TILEY;
5959 /* skip check for EMC elements not contained in original EMC artwork */
5960 if (element == EL_PLAYER_3 ||
5961 element == EL_PLAYER_4)
5965 if (g_em->bitmap != debug_bitmap ||
5966 g_em->src_x != debug_src_x ||
5967 g_em->src_y != debug_src_y)
5969 static int last_i = -1;
5977 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5978 p, i, element, element_info[element].token_name,
5979 element_action_info[effective_action].suffix, direction);
5981 if (element != effective_element)
5982 printf(" [%d ('%s')]",
5984 element_info[effective_element].token_name);
5988 if (g_em->bitmap != debug_bitmap)
5989 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
5990 j, (int)(g_em->bitmap), (int)(debug_bitmap));
5992 if (g_em->src_x != debug_src_x ||
5993 g_em->src_y != debug_src_y)
5994 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5996 g_em->src_x, g_em->src_y,
5997 g_em->src_x / 32, g_em->src_y / 32,
5998 debug_src_x, debug_src_y,
5999 debug_src_x / 32, debug_src_y / 32);
6001 num_em_gfx_errors++;
6011 printf("::: [%d errors found]\n", num_em_gfx_errors);
6017 void PlayMenuSound()
6019 int sound = menu.sound[game_status];
6021 if (sound == SND_UNDEFINED)
6024 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6025 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6028 if (IS_LOOP_SOUND(sound))
6029 PlaySoundLoop(sound);
6034 void PlayMenuSoundStereo(int sound, int stereo_position)
6036 if (sound == SND_UNDEFINED)
6039 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6040 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6043 if (IS_LOOP_SOUND(sound))
6044 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6046 PlaySoundStereo(sound, stereo_position);
6049 void PlayMenuSoundIfLoop()
6051 int sound = menu.sound[game_status];
6053 if (sound == SND_UNDEFINED)
6056 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6057 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6060 if (IS_LOOP_SOUND(sound))
6061 PlaySoundLoop(sound);
6064 void PlayMenuMusic()
6066 int music = menu.music[game_status];
6068 if (music == MUS_UNDEFINED)
6074 void ToggleFullscreenIfNeeded()
6076 if (setup.fullscreen != video.fullscreen_enabled ||
6077 setup.fullscreen_mode != video.fullscreen_mode_current)
6079 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6081 /* save backbuffer content which gets lost when toggling fullscreen mode */
6082 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6084 if (setup.fullscreen && video.fullscreen_enabled)
6086 /* keep fullscreen mode, but change screen mode */
6087 video.fullscreen_mode_current = setup.fullscreen_mode;
6088 video.fullscreen_enabled = FALSE;
6091 /* toggle fullscreen */
6092 ChangeVideoModeIfNeeded(setup.fullscreen);
6093 setup.fullscreen = video.fullscreen_enabled;
6095 /* restore backbuffer content from temporary backbuffer backup bitmap */
6096 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6098 FreeBitmap(tmp_backbuffer);
6100 redraw_mask = REDRAW_ALL;