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 FadeExt(int fade_mask, int fade_mode)
419 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
420 int fade_delay = menu.fade_delay;
421 int post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
422 int x, y, width, height;
424 if (fade_mask & REDRAW_ALL)
431 else if (fade_mask & REDRAW_FIELD)
436 height = FULL_SYSIZE;
439 redraw_mask |= fade_mask;
441 if (!setup.fading || fade_delay == 0)
443 if (fade_mode == FADE_MODE_FADE_OUT)
444 ClearRectangle(backbuffer, x, y, width, height);
451 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay);
453 redraw_mask &= ~fade_mask;
456 void FadeIn(int fade_mask)
458 FadeExt(fade_mask, FADE_MODE_FADE_IN);
461 void FadeOut(int fade_mask)
463 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
466 void FadeCross(int fade_mask)
468 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
471 void FadeCrossSaveBackbuffer()
473 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
476 void SetMainBackgroundImageIfDefined(int graphic)
478 if (graphic_info[graphic].bitmap)
479 SetMainBackgroundImage(graphic);
482 void SetMainBackgroundImage(int graphic)
484 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
485 graphic_info[graphic].bitmap ?
486 graphic_info[graphic].bitmap :
487 graphic_info[IMG_BACKGROUND].bitmap);
490 void SetDoorBackgroundImage(int graphic)
492 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
493 graphic_info[graphic].bitmap ?
494 graphic_info[graphic].bitmap :
495 graphic_info[IMG_BACKGROUND].bitmap);
498 void SetPanelBackground()
500 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
501 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
503 SetDoorBackgroundBitmap(bitmap_db_panel);
506 void DrawBackground(int dst_x, int dst_y, int width, int height)
509 ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
511 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
514 redraw_mask |= REDRAW_FIELD;
519 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
521 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
523 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
524 SetDrawtoField(DRAW_BUFFERED);
527 SetDrawtoField(DRAW_BACKBUFFER);
529 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
531 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
532 SetDrawtoField(DRAW_DIRECT);
536 void MarkTileDirty(int x, int y)
538 int xx = redraw_x1 + x;
539 int yy = redraw_y1 + y;
544 redraw[xx][yy] = TRUE;
545 redraw_mask |= REDRAW_TILES;
548 void SetBorderElement()
552 BorderElement = EL_EMPTY;
554 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
556 for (x = 0; x < lev_fieldx; x++)
558 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
559 BorderElement = EL_STEELWALL;
561 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
567 void SetRandomAnimationValue(int x, int y)
569 gfx.anim_random_frame = GfxRandom[x][y];
572 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
574 /* animation synchronized with global frame counter, not move position */
575 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
576 sync_frame = FrameCounter;
579 if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
585 printf("::: FOO!\n");
589 return getAnimationFrame(graphic_info[graphic].anim_frames,
590 graphic_info[graphic].anim_delay,
591 graphic_info[graphic].anim_mode,
592 graphic_info[graphic].anim_start_frame,
596 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
597 int *x, int *y, boolean get_backside)
599 struct GraphicInfo *g = &graphic_info[graphic];
600 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
601 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
605 if (g->offset_y == 0) /* frames are ordered horizontally */
607 int max_width = g->anim_frames_per_line * g->width;
608 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
610 *x = pos % max_width;
611 *y = src_y % g->height + pos / max_width * g->height;
613 else if (g->offset_x == 0) /* frames are ordered vertically */
615 int max_height = g->anim_frames_per_line * g->height;
616 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
618 *x = src_x % g->width + pos / max_height * g->width;
619 *y = pos % max_height;
621 else /* frames are ordered diagonally */
623 *x = src_x + frame * g->offset_x;
624 *y = src_y + frame * g->offset_y;
628 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
630 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
633 void DrawGraphic(int x, int y, int graphic, int frame)
636 if (!IN_SCR_FIELD(x, y))
638 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
639 printf("DrawGraphic(): This should never happen!\n");
644 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
648 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
654 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
655 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
658 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
661 if (!IN_SCR_FIELD(x, y))
663 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
664 printf("DrawGraphicThruMask(): This should never happen!\n");
669 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
674 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
680 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
682 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
683 dst_x - src_x, dst_y - src_y);
684 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
687 void DrawMiniGraphic(int x, int y, int graphic)
689 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
690 MarkTileDirty(x / 2, y / 2);
693 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
695 struct GraphicInfo *g = &graphic_info[graphic];
697 int mini_starty = g->bitmap->height * 2 / 3;
700 *x = mini_startx + g->src_x / 2;
701 *y = mini_starty + g->src_y / 2;
704 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
709 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
710 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
713 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
714 int graphic, int frame,
715 int cut_mode, int mask_mode)
720 int width = TILEX, height = TILEY;
723 if (dx || dy) /* shifted graphic */
725 if (x < BX1) /* object enters playfield from the left */
732 else if (x > BX2) /* object enters playfield from the right */
738 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
744 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
746 else if (dx) /* general horizontal movement */
747 MarkTileDirty(x + SIGN(dx), y);
749 if (y < BY1) /* object enters playfield from the top */
751 if (cut_mode==CUT_BELOW) /* object completely above top border */
759 else if (y > BY2) /* object enters playfield from the bottom */
765 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
771 else if (dy > 0 && cut_mode == CUT_ABOVE)
773 if (y == BY2) /* object completely above bottom border */
779 MarkTileDirty(x, y + 1);
780 } /* object leaves playfield to the bottom */
781 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
783 else if (dy) /* general vertical movement */
784 MarkTileDirty(x, y + SIGN(dy));
788 if (!IN_SCR_FIELD(x, y))
790 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
791 printf("DrawGraphicShifted(): This should never happen!\n");
796 if (width > 0 && height > 0)
798 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
803 dst_x = FX + x * TILEX + dx;
804 dst_y = FY + y * TILEY + dy;
806 if (mask_mode == USE_MASKING)
808 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
809 dst_x - src_x, dst_y - src_y);
810 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
814 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
821 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
822 int graphic, int frame,
823 int cut_mode, int mask_mode)
828 int width = TILEX, height = TILEY;
831 int x2 = x + SIGN(dx);
832 int y2 = y + SIGN(dy);
833 int anim_frames = graphic_info[graphic].anim_frames;
834 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
835 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
836 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
838 /* re-calculate animation frame for two-tile movement animation */
839 frame = getGraphicAnimationFrame(graphic, sync_frame);
841 /* check if movement start graphic inside screen area and should be drawn */
842 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
844 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
846 dst_x = FX + x1 * TILEX;
847 dst_y = FY + y1 * TILEY;
849 if (mask_mode == USE_MASKING)
851 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
852 dst_x - src_x, dst_y - src_y);
853 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
857 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
860 MarkTileDirty(x1, y1);
863 /* check if movement end graphic inside screen area and should be drawn */
864 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
866 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
868 dst_x = FX + x2 * TILEX;
869 dst_y = FY + y2 * TILEY;
871 if (mask_mode == USE_MASKING)
873 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
874 dst_x - src_x, dst_y - src_y);
875 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
879 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
882 MarkTileDirty(x2, y2);
886 static void DrawGraphicShifted(int x, int y, int dx, int dy,
887 int graphic, int frame,
888 int cut_mode, int mask_mode)
892 DrawGraphic(x, y, graphic, frame);
897 if (graphic_info[graphic].double_movement) /* EM style movement images */
898 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
900 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
903 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
904 int frame, int cut_mode)
906 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
909 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
910 int cut_mode, int mask_mode)
912 int lx = LEVELX(x), ly = LEVELY(y);
916 if (IN_LEV_FIELD(lx, ly))
918 SetRandomAnimationValue(lx, ly);
920 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
921 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
923 /* do not use double (EM style) movement graphic when not moving */
924 if (graphic_info[graphic].double_movement && !dx && !dy)
926 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
927 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
930 else /* border element */
932 graphic = el2img(element);
933 frame = getGraphicAnimationFrame(graphic, -1);
936 if (element == EL_EXPANDABLE_WALL)
938 boolean left_stopped = FALSE, right_stopped = FALSE;
940 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
942 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
943 right_stopped = TRUE;
945 if (left_stopped && right_stopped)
947 else if (left_stopped)
949 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
950 frame = graphic_info[graphic].anim_frames - 1;
952 else if (right_stopped)
954 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
955 frame = graphic_info[graphic].anim_frames - 1;
960 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
961 else if (mask_mode == USE_MASKING)
962 DrawGraphicThruMask(x, y, graphic, frame);
964 DrawGraphic(x, y, graphic, frame);
967 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
968 int cut_mode, int mask_mode)
970 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
971 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
972 cut_mode, mask_mode);
975 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
978 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
981 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
984 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
987 void DrawLevelElementThruMask(int x, int y, int element)
989 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
992 void DrawLevelFieldThruMask(int x, int y)
994 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
997 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1001 int sx = SCREENX(x), sy = SCREENY(y);
1003 int width, height, cx, cy, i;
1004 int crumbled_border_size = graphic_info[graphic].border_size;
1005 static int xy[4][2] =
1013 if (!IN_LEV_FIELD(x, y))
1016 element = TILE_GFX_ELEMENT(x, y);
1018 /* crumble field itself */
1019 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1021 if (!IN_SCR_FIELD(sx, sy))
1024 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1026 for (i = 0; i < 4; i++)
1028 int xx = x + xy[i][0];
1029 int yy = y + xy[i][1];
1031 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1034 /* check if neighbour field is of same type */
1035 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1038 if (i == 1 || i == 2)
1040 width = crumbled_border_size;
1042 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1048 height = crumbled_border_size;
1050 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1053 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1054 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1057 MarkTileDirty(sx, sy);
1059 else /* crumble neighbour fields */
1061 for (i = 0; i < 4; i++)
1063 int xx = x + xy[i][0];
1064 int yy = y + xy[i][1];
1065 int sxx = sx + xy[i][0];
1066 int syy = sy + xy[i][1];
1069 if (!IN_LEV_FIELD(xx, yy) ||
1070 !IN_SCR_FIELD(sxx, syy) ||
1075 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1079 element = TILE_GFX_ELEMENT(xx, yy);
1081 if (!GFX_CRUMBLED(element))
1084 if (!IN_LEV_FIELD(xx, yy) ||
1085 !IN_SCR_FIELD(sxx, syy) ||
1086 !GFX_CRUMBLED(Feld[xx][yy]) ||
1092 graphic = el_act2crm(element, ACTION_DEFAULT);
1094 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1096 crumbled_border_size = graphic_info[graphic].border_size;
1098 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1100 if (i == 1 || i == 2)
1102 width = crumbled_border_size;
1104 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1110 height = crumbled_border_size;
1112 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1115 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1116 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1118 MarkTileDirty(sxx, syy);
1123 void DrawLevelFieldCrumbledSand(int x, int y)
1127 if (!IN_LEV_FIELD(x, y))
1131 /* !!! CHECK THIS !!! */
1134 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1135 GFX_CRUMBLED(GfxElement[x][y]))
1138 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1139 GfxElement[x][y] != EL_UNDEFINED &&
1140 GFX_CRUMBLED(GfxElement[x][y]))
1142 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1149 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1151 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1154 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1157 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1160 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1161 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1162 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1163 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1164 int sx = SCREENX(x), sy = SCREENY(y);
1166 DrawGraphic(sx, sy, graphic1, frame1);
1167 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1170 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1172 int sx = SCREENX(x), sy = SCREENY(y);
1173 static int xy[4][2] =
1182 for (i = 0; i < 4; i++)
1184 int xx = x + xy[i][0];
1185 int yy = y + xy[i][1];
1186 int sxx = sx + xy[i][0];
1187 int syy = sy + xy[i][1];
1189 if (!IN_LEV_FIELD(xx, yy) ||
1190 !IN_SCR_FIELD(sxx, syy) ||
1191 !GFX_CRUMBLED(Feld[xx][yy]) ||
1195 DrawLevelField(xx, yy);
1199 static int getBorderElement(int x, int y)
1203 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1204 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1205 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1206 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1207 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1208 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1209 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1211 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1212 int steel_position = (x == -1 && y == -1 ? 0 :
1213 x == lev_fieldx && y == -1 ? 1 :
1214 x == -1 && y == lev_fieldy ? 2 :
1215 x == lev_fieldx && y == lev_fieldy ? 3 :
1216 x == -1 || x == lev_fieldx ? 4 :
1217 y == -1 || y == lev_fieldy ? 5 : 6);
1219 return border[steel_position][steel_type];
1222 void DrawScreenElement(int x, int y, int element)
1224 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1225 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1228 void DrawLevelElement(int x, int y, int element)
1230 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1231 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1234 void DrawScreenField(int x, int y)
1236 int lx = LEVELX(x), ly = LEVELY(y);
1237 int element, content;
1239 if (!IN_LEV_FIELD(lx, ly))
1241 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1244 element = getBorderElement(lx, ly);
1246 DrawScreenElement(x, y, element);
1250 element = Feld[lx][ly];
1251 content = Store[lx][ly];
1253 if (IS_MOVING(lx, ly))
1255 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1256 boolean cut_mode = NO_CUTTING;
1258 if (element == EL_QUICKSAND_EMPTYING ||
1259 element == EL_MAGIC_WALL_EMPTYING ||
1260 element == EL_BD_MAGIC_WALL_EMPTYING ||
1261 element == EL_AMOEBA_DROPPING)
1262 cut_mode = CUT_ABOVE;
1263 else if (element == EL_QUICKSAND_FILLING ||
1264 element == EL_MAGIC_WALL_FILLING ||
1265 element == EL_BD_MAGIC_WALL_FILLING)
1266 cut_mode = CUT_BELOW;
1268 if (cut_mode == CUT_ABOVE)
1269 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1271 DrawScreenElement(x, y, EL_EMPTY);
1274 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1275 else if (cut_mode == NO_CUTTING)
1276 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1278 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1280 if (content == EL_ACID)
1282 int dir = MovDir[lx][ly];
1283 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1284 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1286 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1289 else if (IS_BLOCKED(lx, ly))
1294 boolean cut_mode = NO_CUTTING;
1295 int element_old, content_old;
1297 Blocked2Moving(lx, ly, &oldx, &oldy);
1300 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1301 MovDir[oldx][oldy] == MV_RIGHT);
1303 element_old = Feld[oldx][oldy];
1304 content_old = Store[oldx][oldy];
1306 if (element_old == EL_QUICKSAND_EMPTYING ||
1307 element_old == EL_MAGIC_WALL_EMPTYING ||
1308 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1309 element_old == EL_AMOEBA_DROPPING)
1310 cut_mode = CUT_ABOVE;
1312 DrawScreenElement(x, y, EL_EMPTY);
1315 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1317 else if (cut_mode == NO_CUTTING)
1318 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1321 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1324 else if (IS_DRAWABLE(element))
1325 DrawScreenElement(x, y, element);
1327 DrawScreenElement(x, y, EL_EMPTY);
1330 void DrawLevelField(int x, int y)
1332 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1333 DrawScreenField(SCREENX(x), SCREENY(y));
1334 else if (IS_MOVING(x, y))
1338 Moving2Blocked(x, y, &newx, &newy);
1339 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1340 DrawScreenField(SCREENX(newx), SCREENY(newy));
1342 else if (IS_BLOCKED(x, y))
1346 Blocked2Moving(x, y, &oldx, &oldy);
1347 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1348 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1352 void DrawMiniElement(int x, int y, int element)
1356 graphic = el2edimg(element);
1357 DrawMiniGraphic(x, y, graphic);
1360 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1362 int x = sx + scroll_x, y = sy + scroll_y;
1364 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1365 DrawMiniElement(sx, sy, EL_EMPTY);
1366 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1367 DrawMiniElement(sx, sy, Feld[x][y]);
1369 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1372 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1373 int x, int y, int xsize, int ysize, int font_nr)
1375 int font_width = getFontWidth(font_nr);
1376 int font_height = getFontHeight(font_nr);
1377 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1380 int dst_x = SX + startx + x * font_width;
1381 int dst_y = SY + starty + y * font_height;
1382 int width = graphic_info[graphic].width;
1383 int height = graphic_info[graphic].height;
1384 int inner_width = MAX(width - 2 * font_width, font_width);
1385 int inner_height = MAX(height - 2 * font_height, font_height);
1386 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1387 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1388 boolean draw_masked = graphic_info[graphic].draw_masked;
1390 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1392 if (src_bitmap == NULL || width < font_width || height < font_height)
1394 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1398 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1399 inner_sx + (x - 1) * font_width % inner_width);
1400 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1401 inner_sy + (y - 1) * font_height % inner_height);
1405 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1406 dst_x - src_x, dst_y - src_y);
1407 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1411 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1415 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1417 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1418 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1419 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1420 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1421 boolean no_delay = (tape.warp_forward);
1422 unsigned long anim_delay = 0;
1423 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1424 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1425 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1426 int font_width = getFontWidth(font_nr);
1427 int font_height = getFontHeight(font_nr);
1428 int max_xsize = level.envelope[envelope_nr].xsize;
1429 int max_ysize = level.envelope[envelope_nr].ysize;
1430 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1431 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1432 int xend = max_xsize;
1433 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1434 int xstep = (xstart < xend ? 1 : 0);
1435 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1438 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1440 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1441 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1442 int sx = (SXSIZE - xsize * font_width) / 2;
1443 int sy = (SYSIZE - ysize * font_height) / 2;
1446 SetDrawtoField(DRAW_BUFFERED);
1448 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1450 SetDrawtoField(DRAW_BACKBUFFER);
1452 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1453 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1455 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1456 level.envelope[envelope_nr].text, font_nr, max_xsize,
1457 xsize - 2, ysize - 2, mask_mode);
1459 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1462 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1466 void ShowEnvelope(int envelope_nr)
1468 int element = EL_ENVELOPE_1 + envelope_nr;
1469 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1470 int sound_opening = element_info[element].sound[ACTION_OPENING];
1471 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1472 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1473 boolean no_delay = (tape.warp_forward);
1474 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1475 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1476 int anim_mode = graphic_info[graphic].anim_mode;
1477 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1478 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1480 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1482 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1484 if (anim_mode == ANIM_DEFAULT)
1485 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1487 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1490 Delay(wait_delay_value);
1492 WaitForEventToContinue();
1494 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1496 if (anim_mode != ANIM_NONE)
1497 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1499 if (anim_mode == ANIM_DEFAULT)
1500 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1502 game.envelope_active = FALSE;
1504 SetDrawtoField(DRAW_BUFFERED);
1506 redraw_mask |= REDRAW_FIELD;
1510 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1515 int width_mult, width_div;
1516 int height_mult, height_div;
1524 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1525 5 - log_2(tilesize));
1526 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1527 int width_mult = offset_calc[offset_calc_pos].width_mult;
1528 int width_div = offset_calc[offset_calc_pos].width_div;
1529 int height_mult = offset_calc[offset_calc_pos].height_mult;
1530 int height_div = offset_calc[offset_calc_pos].height_div;
1531 int mini_startx = src_bitmap->width * width_mult / width_div;
1532 int mini_starty = src_bitmap->height * height_mult / height_div;
1533 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1534 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1536 *bitmap = src_bitmap;
1541 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1545 int graphic = el2preimg(element);
1547 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1548 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1555 SetDrawBackgroundMask(REDRAW_NONE);
1558 for (x = BX1; x <= BX2; x++)
1559 for (y = BY1; y <= BY2; y++)
1560 DrawScreenField(x, y);
1562 redraw_mask |= REDRAW_FIELD;
1565 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1569 for (x = 0; x < size_x; x++)
1570 for (y = 0; y < size_y; y++)
1571 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1573 redraw_mask |= REDRAW_FIELD;
1576 static void DrawPreviewLevelExt(int from_x, int from_y)
1578 boolean show_level_border = (BorderElement != EL_EMPTY);
1579 int dst_x = preview.x;
1580 int dst_y = preview.y;
1581 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1582 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1583 int tile_size = preview.tile_size;
1584 int preview_width = preview.xsize * tile_size;
1585 int preview_height = preview.ysize * tile_size;
1586 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1587 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1590 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1592 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1593 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1595 for (x = 0; x < real_preview_xsize; x++)
1597 for (y = 0; y < real_preview_ysize; y++)
1599 int lx = from_x + x + (show_level_border ? -1 : 0);
1600 int ly = from_y + y + (show_level_border ? -1 : 0);
1601 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1602 getBorderElement(lx, ly));
1604 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1605 element, tile_size);
1609 redraw_mask |= REDRAW_MICROLEVEL;
1612 #define MICROLABEL_EMPTY 0
1613 #define MICROLABEL_LEVEL_NAME 1
1614 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1615 #define MICROLABEL_LEVEL_AUTHOR 3
1616 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1617 #define MICROLABEL_IMPORTED_FROM 5
1618 #define MICROLABEL_IMPORTED_BY_HEAD 6
1619 #define MICROLABEL_IMPORTED_BY 7
1621 static void DrawPreviewLevelLabelExt(int mode)
1623 char label_text[MAX_OUTPUT_LINESIZE + 1];
1624 int max_len_label_text;
1625 int font_nr = FONT_TEXT_2;
1628 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1629 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1630 mode == MICROLABEL_IMPORTED_BY_HEAD)
1631 font_nr = FONT_TEXT_3;
1633 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1635 for (i = 0; i < max_len_label_text; i++)
1636 label_text[i] = ' ';
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);
1648 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1649 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1650 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1651 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1652 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1653 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1654 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1655 max_len_label_text);
1656 label_text[max_len_label_text] = '\0';
1658 if (strlen(label_text) > 0)
1660 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1661 int lypos = MICROLABEL2_YPOS;
1663 DrawText(lxpos, lypos, label_text, font_nr);
1666 redraw_mask |= REDRAW_MICROLEVEL;
1669 void DrawPreviewLevel(boolean restart)
1671 static unsigned long scroll_delay = 0;
1672 static unsigned long label_delay = 0;
1673 static int from_x, from_y, scroll_direction;
1674 static int label_state, label_counter;
1675 unsigned long scroll_delay_value = preview.step_delay;
1676 boolean show_level_border = (BorderElement != EL_EMPTY);
1677 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1678 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1679 int last_game_status = game_status; /* save current game status */
1681 /* force PREVIEW font on preview level */
1682 game_status = GAME_MODE_PSEUDO_PREVIEW;
1686 from_x = from_y = 0;
1687 scroll_direction = MV_RIGHT;
1691 DrawPreviewLevelExt(from_x, from_y);
1692 DrawPreviewLevelLabelExt(label_state);
1694 /* initialize delay counters */
1695 DelayReached(&scroll_delay, 0);
1696 DelayReached(&label_delay, 0);
1698 if (leveldir_current->name)
1700 char label_text[MAX_OUTPUT_LINESIZE + 1];
1701 int font_nr = FONT_TEXT_1;
1702 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1705 strncpy(label_text, leveldir_current->name, max_len_label_text);
1706 label_text[max_len_label_text] = '\0';
1708 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1709 lypos = SY + MICROLABEL1_YPOS;
1711 DrawText(lxpos, lypos, label_text, font_nr);
1714 game_status = last_game_status; /* restore current game status */
1719 /* scroll preview level, if needed */
1720 if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1721 DelayReached(&scroll_delay, scroll_delay_value))
1723 switch (scroll_direction)
1728 from_x -= preview.step_offset;
1729 from_x = (from_x < 0 ? 0 : from_x);
1732 scroll_direction = MV_UP;
1736 if (from_x < level_xsize - preview.xsize)
1738 from_x += preview.step_offset;
1739 from_x = (from_x > level_xsize - preview.xsize ?
1740 level_xsize - preview.xsize : from_x);
1743 scroll_direction = MV_DOWN;
1749 from_y -= preview.step_offset;
1750 from_y = (from_y < 0 ? 0 : from_y);
1753 scroll_direction = MV_RIGHT;
1757 if (from_y < level_ysize - preview.ysize)
1759 from_y += preview.step_offset;
1760 from_y = (from_y > level_ysize - preview.ysize ?
1761 level_ysize - preview.ysize : from_y);
1764 scroll_direction = MV_LEFT;
1771 DrawPreviewLevelExt(from_x, from_y);
1774 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1775 /* redraw micro level label, if needed */
1776 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1777 !strEqual(level.author, ANONYMOUS_NAME) &&
1778 !strEqual(level.author, leveldir_current->name) &&
1779 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1781 int max_label_counter = 23;
1783 if (leveldir_current->imported_from != NULL &&
1784 strlen(leveldir_current->imported_from) > 0)
1785 max_label_counter += 14;
1786 if (leveldir_current->imported_by != NULL &&
1787 strlen(leveldir_current->imported_by) > 0)
1788 max_label_counter += 14;
1790 label_counter = (label_counter + 1) % max_label_counter;
1791 label_state = (label_counter >= 0 && label_counter <= 7 ?
1792 MICROLABEL_LEVEL_NAME :
1793 label_counter >= 9 && label_counter <= 12 ?
1794 MICROLABEL_LEVEL_AUTHOR_HEAD :
1795 label_counter >= 14 && label_counter <= 21 ?
1796 MICROLABEL_LEVEL_AUTHOR :
1797 label_counter >= 23 && label_counter <= 26 ?
1798 MICROLABEL_IMPORTED_FROM_HEAD :
1799 label_counter >= 28 && label_counter <= 35 ?
1800 MICROLABEL_IMPORTED_FROM :
1801 label_counter >= 37 && label_counter <= 40 ?
1802 MICROLABEL_IMPORTED_BY_HEAD :
1803 label_counter >= 42 && label_counter <= 49 ?
1804 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1806 if (leveldir_current->imported_from == NULL &&
1807 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1808 label_state == MICROLABEL_IMPORTED_FROM))
1809 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1810 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1812 DrawPreviewLevelLabelExt(label_state);
1815 game_status = last_game_status; /* restore current game status */
1818 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1819 int graphic, int sync_frame, int mask_mode)
1821 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1823 if (mask_mode == USE_MASKING)
1824 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1826 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1829 inline void DrawGraphicAnimation(int x, int y, int graphic)
1831 int lx = LEVELX(x), ly = LEVELY(y);
1833 if (!IN_SCR_FIELD(x, y))
1836 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1837 graphic, GfxFrame[lx][ly], NO_MASKING);
1838 MarkTileDirty(x, y);
1841 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1843 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1846 void DrawLevelElementAnimation(int x, int y, int element)
1848 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1850 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1853 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1855 int sx = SCREENX(x), sy = SCREENY(y);
1857 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1860 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1863 DrawGraphicAnimation(sx, sy, graphic);
1866 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1867 DrawLevelFieldCrumbledSand(x, y);
1869 if (GFX_CRUMBLED(Feld[x][y]))
1870 DrawLevelFieldCrumbledSand(x, y);
1874 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1876 int sx = SCREENX(x), sy = SCREENY(y);
1879 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1882 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1884 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1887 DrawGraphicAnimation(sx, sy, graphic);
1889 if (GFX_CRUMBLED(element))
1890 DrawLevelFieldCrumbledSand(x, y);
1893 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1895 if (player->use_murphy)
1897 /* this works only because currently only one player can be "murphy" ... */
1898 static int last_horizontal_dir = MV_LEFT;
1899 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1901 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1902 last_horizontal_dir = move_dir;
1904 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1906 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1908 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1914 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1917 static boolean equalGraphics(int graphic1, int graphic2)
1919 struct GraphicInfo *g1 = &graphic_info[graphic1];
1920 struct GraphicInfo *g2 = &graphic_info[graphic2];
1922 return (g1->bitmap == g2->bitmap &&
1923 g1->src_x == g2->src_x &&
1924 g1->src_y == g2->src_y &&
1925 g1->anim_frames == g2->anim_frames &&
1926 g1->anim_delay == g2->anim_delay &&
1927 g1->anim_mode == g2->anim_mode);
1930 void DrawAllPlayers()
1934 for (i = 0; i < MAX_PLAYERS; i++)
1935 if (stored_player[i].active)
1936 DrawPlayer(&stored_player[i]);
1939 void DrawPlayerField(int x, int y)
1941 if (!IS_PLAYER(x, y))
1944 DrawPlayer(PLAYERINFO(x, y));
1947 void DrawPlayer(struct PlayerInfo *player)
1949 int jx = player->jx;
1950 int jy = player->jy;
1951 int move_dir = player->MovDir;
1952 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1953 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1954 int last_jx = (player->is_moving ? jx - dx : jx);
1955 int last_jy = (player->is_moving ? jy - dy : jy);
1956 int next_jx = jx + dx;
1957 int next_jy = jy + dy;
1958 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1959 boolean player_is_opaque = FALSE;
1960 int sx = SCREENX(jx), sy = SCREENY(jy);
1961 int sxx = 0, syy = 0;
1962 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1964 int action = ACTION_DEFAULT;
1965 int last_player_graphic = getPlayerGraphic(player, move_dir);
1966 int last_player_frame = player->Frame;
1970 /* GfxElement[][] is set to the element the player is digging or collecting;
1971 remove also for off-screen player if the player is not moving anymore */
1972 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1973 GfxElement[jx][jy] = EL_UNDEFINED;
1976 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1980 if (!IN_LEV_FIELD(jx, jy))
1982 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1983 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1984 printf("DrawPlayerField(): This should never happen!\n");
1989 if (element == EL_EXPLOSION)
1992 action = (player->is_pushing ? ACTION_PUSHING :
1993 player->is_digging ? ACTION_DIGGING :
1994 player->is_collecting ? ACTION_COLLECTING :
1995 player->is_moving ? ACTION_MOVING :
1996 player->is_snapping ? ACTION_SNAPPING :
1997 player->is_dropping ? ACTION_DROPPING :
1998 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2001 if (player->is_waiting)
2002 move_dir = player->dir_waiting;
2005 InitPlayerGfxAnimation(player, action, move_dir);
2007 /* ----------------------------------------------------------------------- */
2008 /* draw things in the field the player is leaving, if needed */
2009 /* ----------------------------------------------------------------------- */
2011 if (player->is_moving)
2013 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2015 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2017 if (last_element == EL_DYNAMITE_ACTIVE ||
2018 last_element == EL_EM_DYNAMITE_ACTIVE ||
2019 last_element == EL_SP_DISK_RED_ACTIVE)
2020 DrawDynamite(last_jx, last_jy);
2022 DrawLevelFieldThruMask(last_jx, last_jy);
2024 else if (last_element == EL_DYNAMITE_ACTIVE ||
2025 last_element == EL_EM_DYNAMITE_ACTIVE ||
2026 last_element == EL_SP_DISK_RED_ACTIVE)
2027 DrawDynamite(last_jx, last_jy);
2029 /* !!! this is not enough to prevent flickering of players which are
2030 moving next to each others without a free tile between them -- this
2031 can only be solved by drawing all players layer by layer (first the
2032 background, then the foreground etc.) !!! => TODO */
2033 else if (!IS_PLAYER(last_jx, last_jy))
2034 DrawLevelField(last_jx, last_jy);
2037 DrawLevelField(last_jx, last_jy);
2040 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2041 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2044 if (!IN_SCR_FIELD(sx, sy))
2047 if (setup.direct_draw)
2048 SetDrawtoField(DRAW_BUFFERED);
2050 /* ----------------------------------------------------------------------- */
2051 /* draw things behind the player, if needed */
2052 /* ----------------------------------------------------------------------- */
2055 DrawLevelElement(jx, jy, Back[jx][jy]);
2056 else if (IS_ACTIVE_BOMB(element))
2057 DrawLevelElement(jx, jy, EL_EMPTY);
2060 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2062 int old_element = GfxElement[jx][jy];
2063 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2064 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2066 if (GFX_CRUMBLED(old_element))
2067 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2069 DrawGraphic(sx, sy, old_graphic, frame);
2071 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2072 player_is_opaque = TRUE;
2076 GfxElement[jx][jy] = EL_UNDEFINED;
2078 /* make sure that pushed elements are drawn with correct frame rate */
2080 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2082 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2083 GfxFrame[jx][jy] = player->StepFrame;
2085 if (player->is_pushing && player->is_moving)
2086 GfxFrame[jx][jy] = player->StepFrame;
2089 DrawLevelField(jx, jy);
2093 /* ----------------------------------------------------------------------- */
2094 /* draw player himself */
2095 /* ----------------------------------------------------------------------- */
2097 graphic = getPlayerGraphic(player, move_dir);
2099 /* in the case of changed player action or direction, prevent the current
2100 animation frame from being restarted for identical animations */
2101 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2102 player->Frame = last_player_frame;
2104 frame = getGraphicAnimationFrame(graphic, player->Frame);
2108 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2109 sxx = player->GfxPos;
2111 syy = player->GfxPos;
2114 if (!setup.soft_scrolling && ScreenMovPos)
2117 if (player_is_opaque)
2118 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2120 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2122 if (SHIELD_ON(player))
2124 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2125 IMG_SHIELD_NORMAL_ACTIVE);
2126 int frame = getGraphicAnimationFrame(graphic, -1);
2128 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2131 /* ----------------------------------------------------------------------- */
2132 /* draw things the player is pushing, if needed */
2133 /* ----------------------------------------------------------------------- */
2136 printf("::: %d, %d [%d, %d] [%d]\n",
2137 player->is_pushing, player_is_moving, player->GfxAction,
2138 player->is_moving, player_is_moving);
2142 if (player->is_pushing && player->is_moving)
2144 int px = SCREENX(jx), py = SCREENY(jy);
2145 int pxx = (TILEX - ABS(sxx)) * dx;
2146 int pyy = (TILEY - ABS(syy)) * dy;
2147 int gfx_frame = GfxFrame[jx][jy];
2153 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2155 element = Feld[next_jx][next_jy];
2156 gfx_frame = GfxFrame[next_jx][next_jy];
2159 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2162 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2163 frame = getGraphicAnimationFrame(graphic, sync_frame);
2165 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2168 /* draw background element under pushed element (like the Sokoban field) */
2169 if (Back[next_jx][next_jy])
2170 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2172 /* masked drawing is needed for EMC style (double) movement graphics */
2173 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2177 /* ----------------------------------------------------------------------- */
2178 /* draw things in front of player (active dynamite or dynabombs) */
2179 /* ----------------------------------------------------------------------- */
2181 if (IS_ACTIVE_BOMB(element))
2183 graphic = el2img(element);
2184 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2186 if (game.emulation == EMU_SUPAPLEX)
2187 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2189 DrawGraphicThruMask(sx, sy, graphic, frame);
2192 if (player_is_moving && last_element == EL_EXPLOSION)
2194 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2195 GfxElement[last_jx][last_jy] : EL_EMPTY);
2196 int graphic = el_act2img(element, ACTION_EXPLODING);
2197 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2198 int phase = ExplodePhase[last_jx][last_jy] - 1;
2199 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2202 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2205 /* ----------------------------------------------------------------------- */
2206 /* draw elements the player is just walking/passing through/under */
2207 /* ----------------------------------------------------------------------- */
2209 if (player_is_moving)
2211 /* handle the field the player is leaving ... */
2212 if (IS_ACCESSIBLE_INSIDE(last_element))
2213 DrawLevelField(last_jx, last_jy);
2214 else if (IS_ACCESSIBLE_UNDER(last_element))
2215 DrawLevelFieldThruMask(last_jx, last_jy);
2218 /* do not redraw accessible elements if the player is just pushing them */
2219 if (!player_is_moving || !player->is_pushing)
2221 /* ... and the field the player is entering */
2222 if (IS_ACCESSIBLE_INSIDE(element))
2223 DrawLevelField(jx, jy);
2224 else if (IS_ACCESSIBLE_UNDER(element))
2225 DrawLevelFieldThruMask(jx, jy);
2228 if (setup.direct_draw)
2230 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2231 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2232 int x_size = TILEX * (1 + ABS(jx - last_jx));
2233 int y_size = TILEY * (1 + ABS(jy - last_jy));
2235 BlitBitmap(drawto_field, window,
2236 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2237 SetDrawtoField(DRAW_DIRECT);
2240 MarkTileDirty(sx, sy);
2243 /* ------------------------------------------------------------------------- */
2245 void WaitForEventToContinue()
2247 boolean still_wait = TRUE;
2249 /* simulate releasing mouse button over last gadget, if still pressed */
2251 HandleGadgets(-1, -1, 0);
2253 button_status = MB_RELEASED;
2265 case EVENT_BUTTONPRESS:
2266 case EVENT_KEYPRESS:
2270 case EVENT_KEYRELEASE:
2271 ClearPlayerAction();
2275 HandleOtherEvents(&event);
2279 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2286 /* don't eat all CPU time */
2291 #define MAX_REQUEST_LINES 13
2292 #define MAX_REQUEST_LINE_FONT1_LEN 7
2293 #define MAX_REQUEST_LINE_FONT2_LEN 10
2295 boolean Request(char *text, unsigned int req_state)
2297 int mx, my, ty, result = -1;
2298 unsigned int old_door_state;
2299 int last_game_status = game_status; /* save current game status */
2300 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2301 int font_nr = FONT_TEXT_2;
2302 int max_word_len = 0;
2305 for (text_ptr = text; *text_ptr; text_ptr++)
2307 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2309 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2311 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2312 font_nr = FONT_LEVEL_NUMBER;
2318 if (game_status == GAME_MODE_PLAYING &&
2319 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2320 BlitScreenToBitmap_EM(backbuffer);
2322 /* disable deactivated drawing when quick-loading level tape recording */
2323 if (tape.playing && tape.deactivate_display)
2324 TapeDeactivateDisplayOff(TRUE);
2326 SetMouseCursor(CURSOR_DEFAULT);
2328 #if defined(NETWORK_AVALIABLE)
2329 /* pause network game while waiting for request to answer */
2330 if (options.network &&
2331 game_status == GAME_MODE_PLAYING &&
2332 req_state & REQUEST_WAIT_FOR_INPUT)
2333 SendToServer_PausePlaying();
2336 old_door_state = GetDoorState();
2338 /* simulate releasing mouse button over last gadget, if still pressed */
2340 HandleGadgets(-1, -1, 0);
2344 if (old_door_state & DOOR_OPEN_1)
2346 CloseDoor(DOOR_CLOSE_1);
2348 /* save old door content */
2349 BlitBitmap(bitmap_db_door, bitmap_db_door,
2350 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2351 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2355 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2358 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2360 /* clear door drawing field */
2361 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2363 /* force DOOR font on preview level */
2364 game_status = GAME_MODE_PSEUDO_DOOR;
2366 /* write text for request */
2367 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2369 char text_line[max_request_line_len + 1];
2375 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2378 if (!tc || tc == ' ')
2389 strncpy(text_line, text, tl);
2392 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2393 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2394 text_line, font_nr);
2396 text += tl + (tc == ' ' ? 1 : 0);
2399 game_status = last_game_status; /* restore current game status */
2401 if (req_state & REQ_ASK)
2403 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2404 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2406 else if (req_state & REQ_CONFIRM)
2408 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2410 else if (req_state & REQ_PLAYER)
2412 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2413 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2414 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2415 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2418 /* copy request gadgets to door backbuffer */
2419 BlitBitmap(drawto, bitmap_db_door,
2420 DX, DY, DXSIZE, DYSIZE,
2421 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2423 OpenDoor(DOOR_OPEN_1);
2425 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2427 if (game_status == GAME_MODE_PLAYING)
2429 SetPanelBackground();
2430 SetDrawBackgroundMask(REDRAW_DOOR_1);
2434 SetDrawBackgroundMask(REDRAW_FIELD);
2440 if (game_status != GAME_MODE_MAIN)
2443 button_status = MB_RELEASED;
2445 request_gadget_id = -1;
2447 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2459 case EVENT_BUTTONPRESS:
2460 case EVENT_BUTTONRELEASE:
2461 case EVENT_MOTIONNOTIFY:
2463 if (event.type == EVENT_MOTIONNOTIFY)
2465 if (!PointerInWindow(window))
2466 continue; /* window and pointer are on different screens */
2471 motion_status = TRUE;
2472 mx = ((MotionEvent *) &event)->x;
2473 my = ((MotionEvent *) &event)->y;
2477 motion_status = FALSE;
2478 mx = ((ButtonEvent *) &event)->x;
2479 my = ((ButtonEvent *) &event)->y;
2480 if (event.type == EVENT_BUTTONPRESS)
2481 button_status = ((ButtonEvent *) &event)->button;
2483 button_status = MB_RELEASED;
2486 /* this sets 'request_gadget_id' */
2487 HandleGadgets(mx, my, button_status);
2489 switch(request_gadget_id)
2491 case TOOL_CTRL_ID_YES:
2494 case TOOL_CTRL_ID_NO:
2497 case TOOL_CTRL_ID_CONFIRM:
2498 result = TRUE | FALSE;
2501 case TOOL_CTRL_ID_PLAYER_1:
2504 case TOOL_CTRL_ID_PLAYER_2:
2507 case TOOL_CTRL_ID_PLAYER_3:
2510 case TOOL_CTRL_ID_PLAYER_4:
2521 case EVENT_KEYPRESS:
2522 switch(GetEventKey((KeyEvent *)&event, TRUE))
2535 if (req_state & REQ_PLAYER)
2539 case EVENT_KEYRELEASE:
2540 ClearPlayerAction();
2544 HandleOtherEvents(&event);
2548 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2550 int joy = AnyJoystick();
2552 if (joy & JOY_BUTTON_1)
2554 else if (joy & JOY_BUTTON_2)
2560 /* don't eat all CPU time */
2564 if (game_status != GAME_MODE_MAIN)
2569 if (!(req_state & REQ_STAY_OPEN))
2571 CloseDoor(DOOR_CLOSE_1);
2573 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2574 (req_state & REQ_REOPEN))
2575 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2580 if (game_status == GAME_MODE_PLAYING)
2582 SetPanelBackground();
2583 SetDrawBackgroundMask(REDRAW_DOOR_1);
2587 SetDrawBackgroundMask(REDRAW_FIELD);
2590 #if defined(NETWORK_AVALIABLE)
2591 /* continue network game after request */
2592 if (options.network &&
2593 game_status == GAME_MODE_PLAYING &&
2594 req_state & REQUEST_WAIT_FOR_INPUT)
2595 SendToServer_ContinuePlaying();
2598 /* restore deactivated drawing when quick-loading level tape recording */
2599 if (tape.playing && tape.deactivate_display)
2600 TapeDeactivateDisplayOn();
2605 unsigned int OpenDoor(unsigned int door_state)
2607 if (door_state & DOOR_COPY_BACK)
2609 if (door_state & DOOR_OPEN_1)
2610 BlitBitmap(bitmap_db_door, bitmap_db_door,
2611 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2612 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2614 if (door_state & DOOR_OPEN_2)
2615 BlitBitmap(bitmap_db_door, bitmap_db_door,
2616 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2617 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2619 door_state &= ~DOOR_COPY_BACK;
2622 return MoveDoor(door_state);
2625 unsigned int CloseDoor(unsigned int door_state)
2627 unsigned int old_door_state = GetDoorState();
2629 if (!(door_state & DOOR_NO_COPY_BACK))
2631 if (old_door_state & DOOR_OPEN_1)
2632 BlitBitmap(backbuffer, bitmap_db_door,
2633 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2635 if (old_door_state & DOOR_OPEN_2)
2636 BlitBitmap(backbuffer, bitmap_db_door,
2637 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2639 door_state &= ~DOOR_NO_COPY_BACK;
2642 return MoveDoor(door_state);
2645 unsigned int GetDoorState()
2647 return MoveDoor(DOOR_GET_STATE);
2650 unsigned int SetDoorState(unsigned int door_state)
2652 return MoveDoor(door_state | DOOR_SET_STATE);
2655 unsigned int MoveDoor(unsigned int door_state)
2657 static int door1 = DOOR_OPEN_1;
2658 static int door2 = DOOR_CLOSE_2;
2659 unsigned long door_delay = 0;
2660 unsigned long door_delay_value;
2663 if (door_1.width < 0 || door_1.width > DXSIZE)
2664 door_1.width = DXSIZE;
2665 if (door_1.height < 0 || door_1.height > DYSIZE)
2666 door_1.height = DYSIZE;
2667 if (door_2.width < 0 || door_2.width > VXSIZE)
2668 door_2.width = VXSIZE;
2669 if (door_2.height < 0 || door_2.height > VYSIZE)
2670 door_2.height = VYSIZE;
2672 if (door_state == DOOR_GET_STATE)
2673 return (door1 | door2);
2675 if (door_state & DOOR_SET_STATE)
2677 if (door_state & DOOR_ACTION_1)
2678 door1 = door_state & DOOR_ACTION_1;
2679 if (door_state & DOOR_ACTION_2)
2680 door2 = door_state & DOOR_ACTION_2;
2682 return (door1 | door2);
2685 if (!(door_state & DOOR_FORCE_REDRAW))
2687 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2688 door_state &= ~DOOR_OPEN_1;
2689 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2690 door_state &= ~DOOR_CLOSE_1;
2691 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2692 door_state &= ~DOOR_OPEN_2;
2693 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2694 door_state &= ~DOOR_CLOSE_2;
2697 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2700 if (setup.quick_doors)
2702 stepsize = 20; /* must be choosen to always draw last frame */
2703 door_delay_value = 0;
2706 if (global.autoplay_leveldir)
2708 door_state |= DOOR_NO_DELAY;
2709 door_state &= ~DOOR_CLOSE_ALL;
2712 if (door_state & DOOR_ACTION)
2714 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2715 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2716 boolean door_1_done = (!handle_door_1);
2717 boolean door_2_done = (!handle_door_2);
2718 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2719 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2720 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2721 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2722 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2723 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2724 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2725 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2726 int door_skip = max_door_size - door_size;
2728 int end = door_size;
2730 int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
2734 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2736 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2740 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2742 /* opening door sound has priority over simultaneously closing door */
2743 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2744 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2745 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2746 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2749 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2752 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2753 GC gc = bitmap->stored_clip_gc;
2755 if (door_state & DOOR_ACTION_1)
2757 int a = MIN(x * door_1.step_offset, end);
2758 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2759 int i = p + door_skip;
2761 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2763 BlitBitmap(bitmap_db_door, drawto,
2764 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2765 DXSIZE, DYSIZE, DX, DY);
2769 BlitBitmap(bitmap_db_door, drawto,
2770 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2771 DXSIZE, DYSIZE - p / 2, DX, DY);
2773 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2776 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2778 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2779 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2780 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2781 int dst2_x = DX, dst2_y = DY;
2782 int width = i, height = DYSIZE;
2784 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2785 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2788 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2789 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2792 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2794 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2795 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2796 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2797 int dst2_x = DX, dst2_y = DY;
2798 int width = DXSIZE, height = i;
2800 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2801 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2804 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2805 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2808 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2810 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2812 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2813 BlitBitmapMasked(bitmap, drawto,
2814 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2815 DX + DXSIZE - i, DY + j);
2816 BlitBitmapMasked(bitmap, drawto,
2817 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2818 DX + DXSIZE - i, DY + 140 + j);
2819 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2820 DY - (DOOR_GFX_PAGEY1 + j));
2821 BlitBitmapMasked(bitmap, drawto,
2822 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2824 BlitBitmapMasked(bitmap, drawto,
2825 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2828 BlitBitmapMasked(bitmap, drawto,
2829 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2831 BlitBitmapMasked(bitmap, drawto,
2832 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2834 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2835 BlitBitmapMasked(bitmap, drawto,
2836 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2837 DX + DXSIZE - i, DY + 77 + j);
2838 BlitBitmapMasked(bitmap, drawto,
2839 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2840 DX + DXSIZE - i, DY + 203 + j);
2843 redraw_mask |= REDRAW_DOOR_1;
2844 door_1_done = (a == end);
2847 if (door_state & DOOR_ACTION_2)
2850 int a = MIN(x * door_2.step_offset, door_size);
2851 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2852 int i = p + door_skip;
2854 int a = MIN(x * door_2.step_offset, door_size_2);
2855 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2856 int i = p + door_skip;
2859 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2861 BlitBitmap(bitmap_db_door, drawto,
2862 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2863 VXSIZE, VYSIZE, VX, VY);
2865 else if (x <= VYSIZE)
2867 BlitBitmap(bitmap_db_door, drawto,
2868 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2869 VXSIZE, VYSIZE - p / 2, VX, VY);
2871 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2874 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2876 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2877 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2878 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2879 int dst2_x = VX, dst2_y = VY;
2880 int width = i, height = VYSIZE;
2882 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2883 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2886 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2887 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2890 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2892 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2893 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2894 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2895 int dst2_x = VX, dst2_y = VY;
2896 int width = VXSIZE, height = i;
2898 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2899 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2902 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2903 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2906 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2908 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2910 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2911 BlitBitmapMasked(bitmap, drawto,
2912 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2913 VX + VXSIZE - i, VY + j);
2914 SetClipOrigin(bitmap, gc,
2915 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2916 BlitBitmapMasked(bitmap, drawto,
2917 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2920 BlitBitmapMasked(bitmap, drawto,
2921 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2922 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2923 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2924 BlitBitmapMasked(bitmap, drawto,
2925 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2927 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2930 redraw_mask |= REDRAW_DOOR_2;
2931 door_2_done = (a == VXSIZE);
2934 if (!(door_state & DOOR_NO_DELAY))
2938 if (game_status == GAME_MODE_MAIN)
2941 WaitUntilDelayReached(&door_delay, door_delay_value);
2946 if (door_state & DOOR_ACTION_1)
2947 door1 = door_state & DOOR_ACTION_1;
2948 if (door_state & DOOR_ACTION_2)
2949 door2 = door_state & DOOR_ACTION_2;
2951 return (door1 | door2);
2954 void DrawSpecialEditorDoor()
2956 /* draw bigger toolbox window */
2957 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2958 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2960 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2961 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2964 redraw_mask |= REDRAW_ALL;
2967 void UndrawSpecialEditorDoor()
2969 /* draw normal tape recorder window */
2970 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2971 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2974 redraw_mask |= REDRAW_ALL;
2978 /* ---------- new tool button stuff ---------------------------------------- */
2980 /* graphic position values for tool buttons */
2981 #define TOOL_BUTTON_YES_XPOS 2
2982 #define TOOL_BUTTON_YES_YPOS 250
2983 #define TOOL_BUTTON_YES_GFX_YPOS 0
2984 #define TOOL_BUTTON_YES_XSIZE 46
2985 #define TOOL_BUTTON_YES_YSIZE 28
2986 #define TOOL_BUTTON_NO_XPOS 52
2987 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2988 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2989 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2990 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2991 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2992 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2993 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2994 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2995 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2996 #define TOOL_BUTTON_PLAYER_XSIZE 30
2997 #define TOOL_BUTTON_PLAYER_YSIZE 30
2998 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2999 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3000 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3001 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3002 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3003 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3004 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3005 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3006 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3007 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3008 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3009 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3010 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3011 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3012 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3013 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3014 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3015 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3016 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3017 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3026 } toolbutton_info[NUM_TOOL_BUTTONS] =
3029 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3030 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3031 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3036 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3037 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3038 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3043 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3044 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3045 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3046 TOOL_CTRL_ID_CONFIRM,
3050 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3051 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3052 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3053 TOOL_CTRL_ID_PLAYER_1,
3057 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3058 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3059 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3060 TOOL_CTRL_ID_PLAYER_2,
3064 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3065 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3066 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3067 TOOL_CTRL_ID_PLAYER_3,
3071 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3072 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3073 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3074 TOOL_CTRL_ID_PLAYER_4,
3079 void CreateToolButtons()
3083 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3085 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3086 Bitmap *deco_bitmap = None;
3087 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3088 struct GadgetInfo *gi;
3089 unsigned long event_mask;
3090 int gd_xoffset, gd_yoffset;
3091 int gd_x1, gd_x2, gd_y;
3094 event_mask = GD_EVENT_RELEASED;
3096 gd_xoffset = toolbutton_info[i].xpos;
3097 gd_yoffset = toolbutton_info[i].ypos;
3098 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3099 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3100 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3102 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3104 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3106 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3107 &deco_bitmap, &deco_x, &deco_y);
3108 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3109 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3112 gi = CreateGadget(GDI_CUSTOM_ID, id,
3113 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3114 GDI_X, DX + toolbutton_info[i].x,
3115 GDI_Y, DY + toolbutton_info[i].y,
3116 GDI_WIDTH, toolbutton_info[i].width,
3117 GDI_HEIGHT, toolbutton_info[i].height,
3118 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3119 GDI_STATE, GD_BUTTON_UNPRESSED,
3120 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3121 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3122 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3123 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3124 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3125 GDI_DECORATION_SHIFTING, 1, 1,
3126 GDI_EVENT_MASK, event_mask,
3127 GDI_CALLBACK_ACTION, HandleToolButtons,
3131 Error(ERR_EXIT, "cannot create gadget");
3133 tool_gadget[id] = gi;
3137 void FreeToolButtons()
3141 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3142 FreeGadget(tool_gadget[i]);
3145 static void UnmapToolButtons()
3149 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3150 UnmapGadget(tool_gadget[i]);
3153 static void HandleToolButtons(struct GadgetInfo *gi)
3155 request_gadget_id = gi->custom_id;
3158 static struct Mapping_EM_to_RND_object
3161 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3162 boolean is_backside; /* backside of moving element */
3168 em_object_mapping_list[] =
3171 Xblank, TRUE, FALSE,
3175 Yacid_splash_eB, FALSE, FALSE,
3176 EL_ACID_SPLASH_RIGHT, -1, -1
3179 Yacid_splash_wB, FALSE, FALSE,
3180 EL_ACID_SPLASH_LEFT, -1, -1
3183 #ifdef EM_ENGINE_BAD_ROLL
3185 Xstone_force_e, FALSE, FALSE,
3186 EL_ROCK, -1, MV_BIT_RIGHT
3189 Xstone_force_w, FALSE, FALSE,
3190 EL_ROCK, -1, MV_BIT_LEFT
3193 Xnut_force_e, FALSE, FALSE,
3194 EL_NUT, -1, MV_BIT_RIGHT
3197 Xnut_force_w, FALSE, FALSE,
3198 EL_NUT, -1, MV_BIT_LEFT
3201 Xspring_force_e, FALSE, FALSE,
3202 EL_SPRING, -1, MV_BIT_RIGHT
3205 Xspring_force_w, FALSE, FALSE,
3206 EL_SPRING, -1, MV_BIT_LEFT
3209 Xemerald_force_e, FALSE, FALSE,
3210 EL_EMERALD, -1, MV_BIT_RIGHT
3213 Xemerald_force_w, FALSE, FALSE,
3214 EL_EMERALD, -1, MV_BIT_LEFT
3217 Xdiamond_force_e, FALSE, FALSE,
3218 EL_DIAMOND, -1, MV_BIT_RIGHT
3221 Xdiamond_force_w, FALSE, FALSE,
3222 EL_DIAMOND, -1, MV_BIT_LEFT
3225 Xbomb_force_e, FALSE, FALSE,
3226 EL_BOMB, -1, MV_BIT_RIGHT
3229 Xbomb_force_w, FALSE, FALSE,
3230 EL_BOMB, -1, MV_BIT_LEFT
3232 #endif /* EM_ENGINE_BAD_ROLL */
3235 Xstone, TRUE, FALSE,
3239 Xstone_pause, FALSE, FALSE,
3243 Xstone_fall, FALSE, FALSE,
3247 Ystone_s, FALSE, FALSE,
3248 EL_ROCK, ACTION_FALLING, -1
3251 Ystone_sB, FALSE, TRUE,
3252 EL_ROCK, ACTION_FALLING, -1
3255 Ystone_e, FALSE, FALSE,
3256 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3259 Ystone_eB, FALSE, TRUE,
3260 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3263 Ystone_w, FALSE, FALSE,
3264 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3267 Ystone_wB, FALSE, TRUE,
3268 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3275 Xnut_pause, FALSE, FALSE,
3279 Xnut_fall, FALSE, FALSE,
3283 Ynut_s, FALSE, FALSE,
3284 EL_NUT, ACTION_FALLING, -1
3287 Ynut_sB, FALSE, TRUE,
3288 EL_NUT, ACTION_FALLING, -1
3291 Ynut_e, FALSE, FALSE,
3292 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3295 Ynut_eB, FALSE, TRUE,
3296 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3299 Ynut_w, FALSE, FALSE,
3300 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3303 Ynut_wB, FALSE, TRUE,
3304 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3307 Xbug_n, TRUE, FALSE,
3311 Xbug_e, TRUE, FALSE,
3312 EL_BUG_RIGHT, -1, -1
3315 Xbug_s, TRUE, FALSE,
3319 Xbug_w, TRUE, FALSE,
3323 Xbug_gon, FALSE, FALSE,
3327 Xbug_goe, FALSE, FALSE,
3328 EL_BUG_RIGHT, -1, -1
3331 Xbug_gos, FALSE, FALSE,
3335 Xbug_gow, FALSE, FALSE,
3339 Ybug_n, FALSE, FALSE,
3340 EL_BUG, ACTION_MOVING, MV_BIT_UP
3343 Ybug_nB, FALSE, TRUE,
3344 EL_BUG, ACTION_MOVING, MV_BIT_UP
3347 Ybug_e, FALSE, FALSE,
3348 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3351 Ybug_eB, FALSE, TRUE,
3352 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3355 Ybug_s, FALSE, FALSE,
3356 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3359 Ybug_sB, FALSE, TRUE,
3360 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3363 Ybug_w, FALSE, FALSE,
3364 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3367 Ybug_wB, FALSE, TRUE,
3368 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3371 Ybug_w_n, FALSE, FALSE,
3372 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3375 Ybug_n_e, FALSE, FALSE,
3376 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3379 Ybug_e_s, FALSE, FALSE,
3380 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3383 Ybug_s_w, FALSE, FALSE,
3384 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3387 Ybug_e_n, FALSE, FALSE,
3388 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3391 Ybug_s_e, FALSE, FALSE,
3392 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3395 Ybug_w_s, FALSE, FALSE,
3396 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3399 Ybug_n_w, FALSE, FALSE,
3400 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3403 Ybug_stone, FALSE, FALSE,
3404 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3407 Ybug_spring, FALSE, FALSE,
3408 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3411 Xtank_n, TRUE, FALSE,
3412 EL_SPACESHIP_UP, -1, -1
3415 Xtank_e, TRUE, FALSE,
3416 EL_SPACESHIP_RIGHT, -1, -1
3419 Xtank_s, TRUE, FALSE,
3420 EL_SPACESHIP_DOWN, -1, -1
3423 Xtank_w, TRUE, FALSE,
3424 EL_SPACESHIP_LEFT, -1, -1
3427 Xtank_gon, FALSE, FALSE,
3428 EL_SPACESHIP_UP, -1, -1
3431 Xtank_goe, FALSE, FALSE,
3432 EL_SPACESHIP_RIGHT, -1, -1
3435 Xtank_gos, FALSE, FALSE,
3436 EL_SPACESHIP_DOWN, -1, -1
3439 Xtank_gow, FALSE, FALSE,
3440 EL_SPACESHIP_LEFT, -1, -1
3443 Ytank_n, FALSE, FALSE,
3444 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3447 Ytank_nB, FALSE, TRUE,
3448 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3451 Ytank_e, FALSE, FALSE,
3452 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3455 Ytank_eB, FALSE, TRUE,
3456 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3459 Ytank_s, FALSE, FALSE,
3460 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3463 Ytank_sB, FALSE, TRUE,
3464 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3467 Ytank_w, FALSE, FALSE,
3468 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3471 Ytank_wB, FALSE, TRUE,
3472 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3475 Ytank_w_n, FALSE, FALSE,
3476 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3479 Ytank_n_e, FALSE, FALSE,
3480 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3483 Ytank_e_s, FALSE, FALSE,
3484 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3487 Ytank_s_w, FALSE, FALSE,
3488 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3491 Ytank_e_n, FALSE, FALSE,
3492 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3495 Ytank_s_e, FALSE, FALSE,
3496 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3499 Ytank_w_s, FALSE, FALSE,
3500 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3503 Ytank_n_w, FALSE, FALSE,
3504 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3507 Ytank_stone, FALSE, FALSE,
3508 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3511 Ytank_spring, FALSE, FALSE,
3512 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3515 Xandroid, TRUE, FALSE,
3516 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3519 Xandroid_1_n, FALSE, FALSE,
3520 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3523 Xandroid_2_n, FALSE, FALSE,
3524 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3527 Xandroid_1_e, FALSE, FALSE,
3528 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3531 Xandroid_2_e, FALSE, FALSE,
3532 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3535 Xandroid_1_w, FALSE, FALSE,
3536 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3539 Xandroid_2_w, FALSE, FALSE,
3540 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3543 Xandroid_1_s, FALSE, FALSE,
3544 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3547 Xandroid_2_s, FALSE, FALSE,
3548 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3551 Yandroid_n, FALSE, FALSE,
3552 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3555 Yandroid_nB, FALSE, TRUE,
3556 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3559 Yandroid_ne, FALSE, FALSE,
3560 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3563 Yandroid_neB, FALSE, TRUE,
3564 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3567 Yandroid_e, FALSE, FALSE,
3568 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3571 Yandroid_eB, FALSE, TRUE,
3572 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3575 Yandroid_se, FALSE, FALSE,
3576 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3579 Yandroid_seB, FALSE, TRUE,
3580 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3583 Yandroid_s, FALSE, FALSE,
3584 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3587 Yandroid_sB, FALSE, TRUE,
3588 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3591 Yandroid_sw, FALSE, FALSE,
3592 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3595 Yandroid_swB, FALSE, TRUE,
3596 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3599 Yandroid_w, FALSE, FALSE,
3600 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3603 Yandroid_wB, FALSE, TRUE,
3604 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3607 Yandroid_nw, FALSE, FALSE,
3608 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3611 Yandroid_nwB, FALSE, TRUE,
3612 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3615 Xspring, TRUE, FALSE,
3619 Xspring_pause, FALSE, FALSE,
3623 Xspring_e, FALSE, FALSE,
3627 Xspring_w, FALSE, FALSE,
3631 Xspring_fall, FALSE, FALSE,
3635 Yspring_s, FALSE, FALSE,
3636 EL_SPRING, ACTION_FALLING, -1
3639 Yspring_sB, FALSE, TRUE,
3640 EL_SPRING, ACTION_FALLING, -1
3643 Yspring_e, FALSE, FALSE,
3644 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3647 Yspring_eB, FALSE, TRUE,
3648 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3651 Yspring_w, FALSE, FALSE,
3652 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3655 Yspring_wB, FALSE, TRUE,
3656 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3659 Yspring_kill_e, FALSE, FALSE,
3660 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3663 Yspring_kill_eB, FALSE, TRUE,
3664 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3667 Yspring_kill_w, FALSE, FALSE,
3668 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3671 Yspring_kill_wB, FALSE, TRUE,
3672 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3675 Xeater_n, TRUE, FALSE,
3676 EL_YAMYAM_UP, -1, -1
3679 Xeater_e, TRUE, FALSE,
3680 EL_YAMYAM_RIGHT, -1, -1
3683 Xeater_w, TRUE, FALSE,
3684 EL_YAMYAM_LEFT, -1, -1
3687 Xeater_s, TRUE, FALSE,
3688 EL_YAMYAM_DOWN, -1, -1
3691 Yeater_n, FALSE, FALSE,
3692 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3695 Yeater_nB, FALSE, TRUE,
3696 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3699 Yeater_e, FALSE, FALSE,
3700 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3703 Yeater_eB, FALSE, TRUE,
3704 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3707 Yeater_s, FALSE, FALSE,
3708 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3711 Yeater_sB, FALSE, TRUE,
3712 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3715 Yeater_w, FALSE, FALSE,
3716 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3719 Yeater_wB, FALSE, TRUE,
3720 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3723 Yeater_stone, FALSE, FALSE,
3724 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3727 Yeater_spring, FALSE, FALSE,
3728 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3731 Xalien, TRUE, FALSE,
3735 Xalien_pause, FALSE, FALSE,
3739 Yalien_n, FALSE, FALSE,
3740 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3743 Yalien_nB, FALSE, TRUE,
3744 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3747 Yalien_e, FALSE, FALSE,
3748 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3751 Yalien_eB, FALSE, TRUE,
3752 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3755 Yalien_s, FALSE, FALSE,
3756 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3759 Yalien_sB, FALSE, TRUE,
3760 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3763 Yalien_w, FALSE, FALSE,
3764 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3767 Yalien_wB, FALSE, TRUE,
3768 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3771 Yalien_stone, FALSE, FALSE,
3772 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3775 Yalien_spring, FALSE, FALSE,
3776 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3779 Xemerald, TRUE, FALSE,
3783 Xemerald_pause, FALSE, FALSE,
3787 Xemerald_fall, FALSE, FALSE,
3791 Xemerald_shine, FALSE, FALSE,
3792 EL_EMERALD, ACTION_TWINKLING, -1
3795 Yemerald_s, FALSE, FALSE,
3796 EL_EMERALD, ACTION_FALLING, -1
3799 Yemerald_sB, FALSE, TRUE,
3800 EL_EMERALD, ACTION_FALLING, -1
3803 Yemerald_e, FALSE, FALSE,
3804 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3807 Yemerald_eB, FALSE, TRUE,
3808 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3811 Yemerald_w, FALSE, FALSE,
3812 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3815 Yemerald_wB, FALSE, TRUE,
3816 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3819 Yemerald_eat, FALSE, FALSE,
3820 EL_EMERALD, ACTION_COLLECTING, -1
3823 Yemerald_stone, FALSE, FALSE,
3824 EL_NUT, ACTION_BREAKING, -1
3827 Xdiamond, TRUE, FALSE,
3831 Xdiamond_pause, FALSE, FALSE,
3835 Xdiamond_fall, FALSE, FALSE,
3839 Xdiamond_shine, FALSE, FALSE,
3840 EL_DIAMOND, ACTION_TWINKLING, -1
3843 Ydiamond_s, FALSE, FALSE,
3844 EL_DIAMOND, ACTION_FALLING, -1
3847 Ydiamond_sB, FALSE, TRUE,
3848 EL_DIAMOND, ACTION_FALLING, -1
3851 Ydiamond_e, FALSE, FALSE,
3852 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3855 Ydiamond_eB, FALSE, TRUE,
3856 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3859 Ydiamond_w, FALSE, FALSE,
3860 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3863 Ydiamond_wB, FALSE, TRUE,
3864 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3867 Ydiamond_eat, FALSE, FALSE,
3868 EL_DIAMOND, ACTION_COLLECTING, -1
3871 Ydiamond_stone, FALSE, FALSE,
3872 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3875 Xdrip_fall, TRUE, FALSE,
3876 EL_AMOEBA_DROP, -1, -1
3879 Xdrip_stretch, FALSE, FALSE,
3880 EL_AMOEBA_DROP, ACTION_FALLING, -1
3883 Xdrip_stretchB, FALSE, TRUE,
3884 EL_AMOEBA_DROP, ACTION_FALLING, -1
3887 Xdrip_eat, FALSE, FALSE,
3888 EL_AMOEBA_DROP, ACTION_GROWING, -1
3891 Ydrip_s1, FALSE, FALSE,
3892 EL_AMOEBA_DROP, ACTION_FALLING, -1
3895 Ydrip_s1B, FALSE, TRUE,
3896 EL_AMOEBA_DROP, ACTION_FALLING, -1
3899 Ydrip_s2, FALSE, FALSE,
3900 EL_AMOEBA_DROP, ACTION_FALLING, -1
3903 Ydrip_s2B, FALSE, TRUE,
3904 EL_AMOEBA_DROP, ACTION_FALLING, -1
3911 Xbomb_pause, FALSE, FALSE,
3915 Xbomb_fall, FALSE, FALSE,
3919 Ybomb_s, FALSE, FALSE,
3920 EL_BOMB, ACTION_FALLING, -1
3923 Ybomb_sB, FALSE, TRUE,
3924 EL_BOMB, ACTION_FALLING, -1
3927 Ybomb_e, FALSE, FALSE,
3928 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3931 Ybomb_eB, FALSE, TRUE,
3932 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3935 Ybomb_w, FALSE, FALSE,
3936 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3939 Ybomb_wB, FALSE, TRUE,
3940 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3943 Ybomb_eat, FALSE, FALSE,
3944 EL_BOMB, ACTION_ACTIVATING, -1
3947 Xballoon, TRUE, FALSE,
3951 Yballoon_n, FALSE, FALSE,
3952 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3955 Yballoon_nB, FALSE, TRUE,
3956 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3959 Yballoon_e, FALSE, FALSE,
3960 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3963 Yballoon_eB, FALSE, TRUE,
3964 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3967 Yballoon_s, FALSE, FALSE,
3968 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3971 Yballoon_sB, FALSE, TRUE,
3972 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3975 Yballoon_w, FALSE, FALSE,
3976 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3979 Yballoon_wB, FALSE, TRUE,
3980 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3983 Xgrass, TRUE, FALSE,
3984 EL_EMC_GRASS, -1, -1
3987 Ygrass_nB, FALSE, FALSE,
3988 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3991 Ygrass_eB, FALSE, FALSE,
3992 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3995 Ygrass_sB, FALSE, FALSE,
3996 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3999 Ygrass_wB, FALSE, FALSE,
4000 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4007 Ydirt_nB, FALSE, FALSE,
4008 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4011 Ydirt_eB, FALSE, FALSE,
4012 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4015 Ydirt_sB, FALSE, FALSE,
4016 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4019 Ydirt_wB, FALSE, FALSE,
4020 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4023 Xacid_ne, TRUE, FALSE,
4024 EL_ACID_POOL_TOPRIGHT, -1, -1
4027 Xacid_se, TRUE, FALSE,
4028 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4031 Xacid_s, TRUE, FALSE,
4032 EL_ACID_POOL_BOTTOM, -1, -1
4035 Xacid_sw, TRUE, FALSE,
4036 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4039 Xacid_nw, TRUE, FALSE,
4040 EL_ACID_POOL_TOPLEFT, -1, -1
4043 Xacid_1, TRUE, FALSE,
4047 Xacid_2, FALSE, FALSE,
4051 Xacid_3, FALSE, FALSE,
4055 Xacid_4, FALSE, FALSE,
4059 Xacid_5, FALSE, FALSE,
4063 Xacid_6, FALSE, FALSE,
4067 Xacid_7, FALSE, FALSE,
4071 Xacid_8, FALSE, FALSE,
4075 Xball_1, TRUE, FALSE,
4076 EL_EMC_MAGIC_BALL, -1, -1
4079 Xball_1B, FALSE, FALSE,
4080 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4083 Xball_2, FALSE, FALSE,
4084 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4087 Xball_2B, FALSE, FALSE,
4088 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4091 Yball_eat, FALSE, FALSE,
4092 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4095 Ykey_1_eat, FALSE, FALSE,
4096 EL_EM_KEY_1, ACTION_COLLECTING, -1
4099 Ykey_2_eat, FALSE, FALSE,
4100 EL_EM_KEY_2, ACTION_COLLECTING, -1
4103 Ykey_3_eat, FALSE, FALSE,
4104 EL_EM_KEY_3, ACTION_COLLECTING, -1
4107 Ykey_4_eat, FALSE, FALSE,
4108 EL_EM_KEY_4, ACTION_COLLECTING, -1
4111 Ykey_5_eat, FALSE, FALSE,
4112 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4115 Ykey_6_eat, FALSE, FALSE,
4116 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4119 Ykey_7_eat, FALSE, FALSE,
4120 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4123 Ykey_8_eat, FALSE, FALSE,
4124 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4127 Ylenses_eat, FALSE, FALSE,
4128 EL_EMC_LENSES, ACTION_COLLECTING, -1
4131 Ymagnify_eat, FALSE, FALSE,
4132 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4135 Ygrass_eat, FALSE, FALSE,
4136 EL_EMC_GRASS, ACTION_SNAPPING, -1
4139 Ydirt_eat, FALSE, FALSE,
4140 EL_SAND, ACTION_SNAPPING, -1
4143 Xgrow_ns, TRUE, FALSE,
4144 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4147 Ygrow_ns_eat, FALSE, FALSE,
4148 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4151 Xgrow_ew, TRUE, FALSE,
4152 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4155 Ygrow_ew_eat, FALSE, FALSE,
4156 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4159 Xwonderwall, TRUE, FALSE,
4160 EL_MAGIC_WALL, -1, -1
4163 XwonderwallB, FALSE, FALSE,
4164 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4167 Xamoeba_1, TRUE, FALSE,
4168 EL_AMOEBA_DRY, ACTION_OTHER, -1
4171 Xamoeba_2, FALSE, FALSE,
4172 EL_AMOEBA_DRY, ACTION_OTHER, -1
4175 Xamoeba_3, FALSE, FALSE,
4176 EL_AMOEBA_DRY, ACTION_OTHER, -1
4179 Xamoeba_4, FALSE, FALSE,
4180 EL_AMOEBA_DRY, ACTION_OTHER, -1
4183 Xamoeba_5, TRUE, FALSE,
4184 EL_AMOEBA_WET, ACTION_OTHER, -1
4187 Xamoeba_6, FALSE, FALSE,
4188 EL_AMOEBA_WET, ACTION_OTHER, -1
4191 Xamoeba_7, FALSE, FALSE,
4192 EL_AMOEBA_WET, ACTION_OTHER, -1
4195 Xamoeba_8, FALSE, FALSE,
4196 EL_AMOEBA_WET, ACTION_OTHER, -1
4199 Xdoor_1, TRUE, FALSE,
4200 EL_EM_GATE_1, -1, -1
4203 Xdoor_2, TRUE, FALSE,
4204 EL_EM_GATE_2, -1, -1
4207 Xdoor_3, TRUE, FALSE,
4208 EL_EM_GATE_3, -1, -1
4211 Xdoor_4, TRUE, FALSE,
4212 EL_EM_GATE_4, -1, -1
4215 Xdoor_5, TRUE, FALSE,
4216 EL_EMC_GATE_5, -1, -1
4219 Xdoor_6, TRUE, FALSE,
4220 EL_EMC_GATE_6, -1, -1
4223 Xdoor_7, TRUE, FALSE,
4224 EL_EMC_GATE_7, -1, -1
4227 Xdoor_8, TRUE, FALSE,
4228 EL_EMC_GATE_8, -1, -1
4231 Xkey_1, TRUE, FALSE,
4235 Xkey_2, TRUE, FALSE,
4239 Xkey_3, TRUE, FALSE,
4243 Xkey_4, TRUE, FALSE,
4247 Xkey_5, TRUE, FALSE,
4248 EL_EMC_KEY_5, -1, -1
4251 Xkey_6, TRUE, FALSE,
4252 EL_EMC_KEY_6, -1, -1
4255 Xkey_7, TRUE, FALSE,
4256 EL_EMC_KEY_7, -1, -1
4259 Xkey_8, TRUE, FALSE,
4260 EL_EMC_KEY_8, -1, -1
4263 Xwind_n, TRUE, FALSE,
4264 EL_BALLOON_SWITCH_UP, -1, -1
4267 Xwind_e, TRUE, FALSE,
4268 EL_BALLOON_SWITCH_RIGHT, -1, -1
4271 Xwind_s, TRUE, FALSE,
4272 EL_BALLOON_SWITCH_DOWN, -1, -1
4275 Xwind_w, TRUE, FALSE,
4276 EL_BALLOON_SWITCH_LEFT, -1, -1
4279 Xwind_nesw, TRUE, FALSE,
4280 EL_BALLOON_SWITCH_ANY, -1, -1
4283 Xwind_stop, TRUE, FALSE,
4284 EL_BALLOON_SWITCH_NONE, -1, -1
4288 EL_EXIT_CLOSED, -1, -1
4291 Xexit_1, TRUE, FALSE,
4292 EL_EXIT_OPEN, -1, -1
4295 Xexit_2, FALSE, FALSE,
4296 EL_EXIT_OPEN, -1, -1
4299 Xexit_3, FALSE, FALSE,
4300 EL_EXIT_OPEN, -1, -1
4303 Xdynamite, TRUE, FALSE,
4304 EL_EM_DYNAMITE, -1, -1
4307 Ydynamite_eat, FALSE, FALSE,
4308 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4311 Xdynamite_1, TRUE, FALSE,
4312 EL_EM_DYNAMITE_ACTIVE, -1, -1
4315 Xdynamite_2, FALSE, FALSE,
4316 EL_EM_DYNAMITE_ACTIVE, -1, -1
4319 Xdynamite_3, FALSE, FALSE,
4320 EL_EM_DYNAMITE_ACTIVE, -1, -1
4323 Xdynamite_4, FALSE, FALSE,
4324 EL_EM_DYNAMITE_ACTIVE, -1, -1
4327 Xbumper, TRUE, FALSE,
4328 EL_EMC_SPRING_BUMPER, -1, -1
4331 XbumperB, FALSE, FALSE,
4332 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4335 Xwheel, TRUE, FALSE,
4336 EL_ROBOT_WHEEL, -1, -1
4339 XwheelB, FALSE, FALSE,
4340 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4343 Xswitch, TRUE, FALSE,
4344 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4347 XswitchB, FALSE, FALSE,
4348 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4352 EL_QUICKSAND_EMPTY, -1, -1
4355 Xsand_stone, TRUE, FALSE,
4356 EL_QUICKSAND_FULL, -1, -1
4359 Xsand_stonein_1, FALSE, TRUE,
4360 EL_ROCK, ACTION_FILLING, -1
4363 Xsand_stonein_2, FALSE, TRUE,
4364 EL_ROCK, ACTION_FILLING, -1
4367 Xsand_stonein_3, FALSE, TRUE,
4368 EL_ROCK, ACTION_FILLING, -1
4371 Xsand_stonein_4, FALSE, TRUE,
4372 EL_ROCK, ACTION_FILLING, -1
4375 Xsand_stonesand_1, FALSE, FALSE,
4376 EL_QUICKSAND_FULL, -1, -1
4379 Xsand_stonesand_2, FALSE, FALSE,
4380 EL_QUICKSAND_FULL, -1, -1
4383 Xsand_stonesand_3, FALSE, FALSE,
4384 EL_QUICKSAND_FULL, -1, -1
4387 Xsand_stonesand_4, FALSE, FALSE,
4388 EL_QUICKSAND_FULL, -1, -1
4391 Xsand_stoneout_1, FALSE, FALSE,
4392 EL_ROCK, ACTION_EMPTYING, -1
4395 Xsand_stoneout_2, FALSE, FALSE,
4396 EL_ROCK, ACTION_EMPTYING, -1
4399 Xsand_sandstone_1, FALSE, FALSE,
4400 EL_QUICKSAND_FULL, -1, -1
4403 Xsand_sandstone_2, FALSE, FALSE,
4404 EL_QUICKSAND_FULL, -1, -1
4407 Xsand_sandstone_3, FALSE, FALSE,
4408 EL_QUICKSAND_FULL, -1, -1
4411 Xsand_sandstone_4, FALSE, FALSE,
4412 EL_QUICKSAND_FULL, -1, -1
4415 Xplant, TRUE, FALSE,
4416 EL_EMC_PLANT, -1, -1
4419 Yplant, FALSE, FALSE,
4420 EL_EMC_PLANT, -1, -1
4423 Xlenses, TRUE, FALSE,
4424 EL_EMC_LENSES, -1, -1
4427 Xmagnify, TRUE, FALSE,
4428 EL_EMC_MAGNIFIER, -1, -1
4431 Xdripper, TRUE, FALSE,
4432 EL_EMC_DRIPPER, -1, -1
4435 XdripperB, FALSE, FALSE,
4436 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4439 Xfake_blank, TRUE, FALSE,
4440 EL_INVISIBLE_WALL, -1, -1
4443 Xfake_blankB, FALSE, FALSE,
4444 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4447 Xfake_grass, TRUE, FALSE,
4448 EL_EMC_FAKE_GRASS, -1, -1
4451 Xfake_grassB, FALSE, FALSE,
4452 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4455 Xfake_door_1, TRUE, FALSE,
4456 EL_EM_GATE_1_GRAY, -1, -1
4459 Xfake_door_2, TRUE, FALSE,
4460 EL_EM_GATE_2_GRAY, -1, -1
4463 Xfake_door_3, TRUE, FALSE,
4464 EL_EM_GATE_3_GRAY, -1, -1
4467 Xfake_door_4, TRUE, FALSE,
4468 EL_EM_GATE_4_GRAY, -1, -1
4471 Xfake_door_5, TRUE, FALSE,
4472 EL_EMC_GATE_5_GRAY, -1, -1
4475 Xfake_door_6, TRUE, FALSE,
4476 EL_EMC_GATE_6_GRAY, -1, -1
4479 Xfake_door_7, TRUE, FALSE,
4480 EL_EMC_GATE_7_GRAY, -1, -1
4483 Xfake_door_8, TRUE, FALSE,
4484 EL_EMC_GATE_8_GRAY, -1, -1
4487 Xfake_acid_1, TRUE, FALSE,
4488 EL_EMC_FAKE_ACID, -1, -1
4491 Xfake_acid_2, FALSE, FALSE,
4492 EL_EMC_FAKE_ACID, -1, -1
4495 Xfake_acid_3, FALSE, FALSE,
4496 EL_EMC_FAKE_ACID, -1, -1
4499 Xfake_acid_4, FALSE, FALSE,
4500 EL_EMC_FAKE_ACID, -1, -1
4503 Xfake_acid_5, FALSE, FALSE,
4504 EL_EMC_FAKE_ACID, -1, -1
4507 Xfake_acid_6, FALSE, FALSE,
4508 EL_EMC_FAKE_ACID, -1, -1
4511 Xfake_acid_7, FALSE, FALSE,
4512 EL_EMC_FAKE_ACID, -1, -1
4515 Xfake_acid_8, FALSE, FALSE,
4516 EL_EMC_FAKE_ACID, -1, -1
4519 Xsteel_1, TRUE, FALSE,
4520 EL_STEELWALL, -1, -1
4523 Xsteel_2, TRUE, FALSE,
4524 EL_EMC_STEELWALL_2, -1, -1
4527 Xsteel_3, TRUE, FALSE,
4528 EL_EMC_STEELWALL_3, -1, -1
4531 Xsteel_4, TRUE, FALSE,
4532 EL_EMC_STEELWALL_4, -1, -1
4535 Xwall_1, TRUE, FALSE,
4539 Xwall_2, TRUE, FALSE,
4540 EL_EMC_WALL_14, -1, -1
4543 Xwall_3, TRUE, FALSE,
4544 EL_EMC_WALL_15, -1, -1
4547 Xwall_4, TRUE, FALSE,
4548 EL_EMC_WALL_16, -1, -1
4551 Xround_wall_1, TRUE, FALSE,
4552 EL_WALL_SLIPPERY, -1, -1
4555 Xround_wall_2, TRUE, FALSE,
4556 EL_EMC_WALL_SLIPPERY_2, -1, -1
4559 Xround_wall_3, TRUE, FALSE,
4560 EL_EMC_WALL_SLIPPERY_3, -1, -1
4563 Xround_wall_4, TRUE, FALSE,
4564 EL_EMC_WALL_SLIPPERY_4, -1, -1
4567 Xdecor_1, TRUE, FALSE,
4568 EL_EMC_WALL_8, -1, -1
4571 Xdecor_2, TRUE, FALSE,
4572 EL_EMC_WALL_6, -1, -1
4575 Xdecor_3, TRUE, FALSE,
4576 EL_EMC_WALL_4, -1, -1
4579 Xdecor_4, TRUE, FALSE,
4580 EL_EMC_WALL_7, -1, -1
4583 Xdecor_5, TRUE, FALSE,
4584 EL_EMC_WALL_5, -1, -1
4587 Xdecor_6, TRUE, FALSE,
4588 EL_EMC_WALL_9, -1, -1
4591 Xdecor_7, TRUE, FALSE,
4592 EL_EMC_WALL_10, -1, -1
4595 Xdecor_8, TRUE, FALSE,
4596 EL_EMC_WALL_1, -1, -1
4599 Xdecor_9, TRUE, FALSE,
4600 EL_EMC_WALL_2, -1, -1
4603 Xdecor_10, TRUE, FALSE,
4604 EL_EMC_WALL_3, -1, -1
4607 Xdecor_11, TRUE, FALSE,
4608 EL_EMC_WALL_11, -1, -1
4611 Xdecor_12, TRUE, FALSE,
4612 EL_EMC_WALL_12, -1, -1
4615 Xalpha_0, TRUE, FALSE,
4616 EL_CHAR('0'), -1, -1
4619 Xalpha_1, TRUE, FALSE,
4620 EL_CHAR('1'), -1, -1
4623 Xalpha_2, TRUE, FALSE,
4624 EL_CHAR('2'), -1, -1
4627 Xalpha_3, TRUE, FALSE,
4628 EL_CHAR('3'), -1, -1
4631 Xalpha_4, TRUE, FALSE,
4632 EL_CHAR('4'), -1, -1
4635 Xalpha_5, TRUE, FALSE,
4636 EL_CHAR('5'), -1, -1
4639 Xalpha_6, TRUE, FALSE,
4640 EL_CHAR('6'), -1, -1
4643 Xalpha_7, TRUE, FALSE,
4644 EL_CHAR('7'), -1, -1
4647 Xalpha_8, TRUE, FALSE,
4648 EL_CHAR('8'), -1, -1
4651 Xalpha_9, TRUE, FALSE,
4652 EL_CHAR('9'), -1, -1
4655 Xalpha_excla, TRUE, FALSE,
4656 EL_CHAR('!'), -1, -1
4659 Xalpha_quote, TRUE, FALSE,
4660 EL_CHAR('"'), -1, -1
4663 Xalpha_comma, TRUE, FALSE,
4664 EL_CHAR(','), -1, -1
4667 Xalpha_minus, TRUE, FALSE,
4668 EL_CHAR('-'), -1, -1
4671 Xalpha_perio, TRUE, FALSE,
4672 EL_CHAR('.'), -1, -1
4675 Xalpha_colon, TRUE, FALSE,
4676 EL_CHAR(':'), -1, -1
4679 Xalpha_quest, TRUE, FALSE,
4680 EL_CHAR('?'), -1, -1
4683 Xalpha_a, TRUE, FALSE,
4684 EL_CHAR('A'), -1, -1
4687 Xalpha_b, TRUE, FALSE,
4688 EL_CHAR('B'), -1, -1
4691 Xalpha_c, TRUE, FALSE,
4692 EL_CHAR('C'), -1, -1
4695 Xalpha_d, TRUE, FALSE,
4696 EL_CHAR('D'), -1, -1
4699 Xalpha_e, TRUE, FALSE,
4700 EL_CHAR('E'), -1, -1
4703 Xalpha_f, TRUE, FALSE,
4704 EL_CHAR('F'), -1, -1
4707 Xalpha_g, TRUE, FALSE,
4708 EL_CHAR('G'), -1, -1
4711 Xalpha_h, TRUE, FALSE,
4712 EL_CHAR('H'), -1, -1
4715 Xalpha_i, TRUE, FALSE,
4716 EL_CHAR('I'), -1, -1
4719 Xalpha_j, TRUE, FALSE,
4720 EL_CHAR('J'), -1, -1
4723 Xalpha_k, TRUE, FALSE,
4724 EL_CHAR('K'), -1, -1
4727 Xalpha_l, TRUE, FALSE,
4728 EL_CHAR('L'), -1, -1
4731 Xalpha_m, TRUE, FALSE,
4732 EL_CHAR('M'), -1, -1
4735 Xalpha_n, TRUE, FALSE,
4736 EL_CHAR('N'), -1, -1
4739 Xalpha_o, TRUE, FALSE,
4740 EL_CHAR('O'), -1, -1
4743 Xalpha_p, TRUE, FALSE,
4744 EL_CHAR('P'), -1, -1
4747 Xalpha_q, TRUE, FALSE,
4748 EL_CHAR('Q'), -1, -1
4751 Xalpha_r, TRUE, FALSE,
4752 EL_CHAR('R'), -1, -1
4755 Xalpha_s, TRUE, FALSE,
4756 EL_CHAR('S'), -1, -1
4759 Xalpha_t, TRUE, FALSE,
4760 EL_CHAR('T'), -1, -1
4763 Xalpha_u, TRUE, FALSE,
4764 EL_CHAR('U'), -1, -1
4767 Xalpha_v, TRUE, FALSE,
4768 EL_CHAR('V'), -1, -1
4771 Xalpha_w, TRUE, FALSE,
4772 EL_CHAR('W'), -1, -1
4775 Xalpha_x, TRUE, FALSE,
4776 EL_CHAR('X'), -1, -1
4779 Xalpha_y, TRUE, FALSE,
4780 EL_CHAR('Y'), -1, -1
4783 Xalpha_z, TRUE, FALSE,
4784 EL_CHAR('Z'), -1, -1
4787 Xalpha_arrow_e, TRUE, FALSE,
4788 EL_CHAR('>'), -1, -1
4791 Xalpha_arrow_w, TRUE, FALSE,
4792 EL_CHAR('<'), -1, -1
4795 Xalpha_copyr, TRUE, FALSE,
4796 EL_CHAR('©'), -1, -1
4800 Xboom_bug, FALSE, FALSE,
4801 EL_BUG, ACTION_EXPLODING, -1
4804 Xboom_bomb, FALSE, FALSE,
4805 EL_BOMB, ACTION_EXPLODING, -1
4808 Xboom_android, FALSE, FALSE,
4809 EL_EMC_ANDROID, ACTION_OTHER, -1
4812 Xboom_1, FALSE, FALSE,
4813 EL_DEFAULT, ACTION_EXPLODING, -1
4816 Xboom_2, FALSE, FALSE,
4817 EL_DEFAULT, ACTION_EXPLODING, -1
4820 Znormal, FALSE, FALSE,
4824 Zdynamite, FALSE, FALSE,
4828 Zplayer, FALSE, FALSE,
4832 ZBORDER, FALSE, FALSE,
4842 static struct Mapping_EM_to_RND_player
4851 em_player_mapping_list[] =
4855 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4859 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4863 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4867 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4871 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4875 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4879 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4883 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4887 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4891 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4895 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4899 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4903 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4907 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4911 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4915 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4919 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4923 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4927 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4931 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4935 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4939 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4943 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4947 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4951 EL_PLAYER_1, ACTION_DEFAULT, -1,
4955 EL_PLAYER_2, ACTION_DEFAULT, -1,
4959 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4963 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4967 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4971 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4975 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4979 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4983 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4987 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4991 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4995 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4999 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5003 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5007 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5011 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5015 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5019 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5023 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5027 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5031 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5035 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5039 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5043 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5047 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5051 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5055 EL_PLAYER_3, ACTION_DEFAULT, -1,
5059 EL_PLAYER_4, ACTION_DEFAULT, -1,
5068 int map_element_RND_to_EM(int element_rnd)
5070 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5071 static boolean mapping_initialized = FALSE;
5073 if (!mapping_initialized)
5077 /* return "Xalpha_quest" for all undefined elements in mapping array */
5078 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5079 mapping_RND_to_EM[i] = Xalpha_quest;
5081 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5082 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5083 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5084 em_object_mapping_list[i].element_em;
5086 mapping_initialized = TRUE;
5089 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5090 return mapping_RND_to_EM[element_rnd];
5092 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5097 int map_element_EM_to_RND(int element_em)
5099 static unsigned short mapping_EM_to_RND[TILE_MAX];
5100 static boolean mapping_initialized = FALSE;
5102 if (!mapping_initialized)
5106 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5107 for (i = 0; i < TILE_MAX; i++)
5108 mapping_EM_to_RND[i] = EL_UNKNOWN;
5110 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5111 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5112 em_object_mapping_list[i].element_rnd;
5114 mapping_initialized = TRUE;
5117 if (element_em >= 0 && element_em < TILE_MAX)
5118 return mapping_EM_to_RND[element_em];
5120 Error(ERR_WARN, "invalid EM level element %d", element_em);
5125 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5127 struct LevelInfo_EM *level_em = level->native_em_level;
5128 struct LEVEL *lev = level_em->lev;
5131 for (i = 0; i < TILE_MAX; i++)
5132 lev->android_array[i] = Xblank;
5134 for (i = 0; i < level->num_android_clone_elements; i++)
5136 int element_rnd = level->android_clone_element[i];
5137 int element_em = map_element_RND_to_EM(element_rnd);
5139 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5140 if (em_object_mapping_list[j].element_rnd == element_rnd)
5141 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5145 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5147 struct LevelInfo_EM *level_em = level->native_em_level;
5148 struct LEVEL *lev = level_em->lev;
5151 level->num_android_clone_elements = 0;
5153 for (i = 0; i < TILE_MAX; i++)
5155 int element_em = lev->android_array[i];
5157 boolean element_found = FALSE;
5159 if (element_em == Xblank)
5162 element_rnd = map_element_EM_to_RND(element_em);
5164 for (j = 0; j < level->num_android_clone_elements; j++)
5165 if (level->android_clone_element[j] == element_rnd)
5166 element_found = TRUE;
5170 level->android_clone_element[level->num_android_clone_elements++] =
5173 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5178 if (level->num_android_clone_elements == 0)
5180 level->num_android_clone_elements = 1;
5181 level->android_clone_element[0] = EL_EMPTY;
5185 int map_direction_RND_to_EM(int direction)
5187 return (direction == MV_UP ? 0 :
5188 direction == MV_RIGHT ? 1 :
5189 direction == MV_DOWN ? 2 :
5190 direction == MV_LEFT ? 3 :
5194 int map_direction_EM_to_RND(int direction)
5196 return (direction == 0 ? MV_UP :
5197 direction == 1 ? MV_RIGHT :
5198 direction == 2 ? MV_DOWN :
5199 direction == 3 ? MV_LEFT :
5203 int get_next_element(int element)
5207 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5208 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5209 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5210 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5211 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5212 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5213 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5215 default: return element;
5220 int el_act_dir2img(int element, int action, int direction)
5222 element = GFX_ELEMENT(element);
5224 if (direction == MV_NONE)
5225 return element_info[element].graphic[action];
5227 direction = MV_DIR_TO_BIT(direction);
5229 return element_info[element].direction_graphic[action][direction];
5232 int el_act_dir2img(int element, int action, int direction)
5234 element = GFX_ELEMENT(element);
5235 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5237 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5238 return element_info[element].direction_graphic[action][direction];
5243 static int el_act_dir2crm(int element, int action, int direction)
5245 element = GFX_ELEMENT(element);
5247 if (direction == MV_NONE)
5248 return element_info[element].crumbled[action];
5250 direction = MV_DIR_TO_BIT(direction);
5252 return element_info[element].direction_crumbled[action][direction];
5255 static int el_act_dir2crm(int element, int action, int direction)
5257 element = GFX_ELEMENT(element);
5258 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5260 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5261 return element_info[element].direction_crumbled[action][direction];
5265 int el_act2img(int element, int action)
5267 element = GFX_ELEMENT(element);
5269 return element_info[element].graphic[action];
5272 int el_act2crm(int element, int action)
5274 element = GFX_ELEMENT(element);
5276 return element_info[element].crumbled[action];
5279 int el_dir2img(int element, int direction)
5281 element = GFX_ELEMENT(element);
5283 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5286 int el2baseimg(int element)
5288 return element_info[element].graphic[ACTION_DEFAULT];
5291 int el2img(int element)
5293 element = GFX_ELEMENT(element);
5295 return element_info[element].graphic[ACTION_DEFAULT];
5298 int el2edimg(int element)
5300 element = GFX_ELEMENT(element);
5302 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5305 int el2preimg(int element)
5307 element = GFX_ELEMENT(element);
5309 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5312 int font2baseimg(int font_nr)
5314 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5318 void setCenteredPlayerNr_EM(int centered_player_nr)
5320 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5323 int getCenteredPlayerNr_EM()
5326 if (game.centered_player_nr_next >= 0 &&
5327 !native_em_level.ply[game.centered_player_nr_next]->alive)
5328 game.centered_player_nr_next = game.centered_player_nr;
5331 if (game.centered_player_nr != game.centered_player_nr_next)
5332 game.centered_player_nr = game.centered_player_nr_next;
5334 return game.centered_player_nr;
5337 void setSetCenteredPlayer_EM(boolean set_centered_player)
5339 game.set_centered_player = set_centered_player;
5342 boolean getSetCenteredPlayer_EM()
5344 return game.set_centered_player;
5348 int getNumActivePlayers_EM()
5350 int num_players = 0;
5356 for (i = 0; i < MAX_PLAYERS; i++)
5357 if (tape.player_participates[i])
5364 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5366 int game_frame_delay_value;
5368 game_frame_delay_value =
5369 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5370 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5373 if (tape.playing && tape.warp_forward && !tape.pausing)
5374 game_frame_delay_value = 0;
5376 return game_frame_delay_value;
5380 unsigned int InitRND(long seed)
5382 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5383 return InitEngineRND_EM(seed);
5385 return InitEngineRND(seed);
5388 void InitGraphicInfo_EM(void)
5390 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5391 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5395 int num_em_gfx_errors = 0;
5397 if (graphic_info_em_object[0][0].bitmap == NULL)
5399 /* EM graphics not yet initialized in em_open_all() */
5404 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5407 /* always start with reliable default values */
5408 for (i = 0; i < TILE_MAX; i++)
5410 object_mapping[i].element_rnd = EL_UNKNOWN;
5411 object_mapping[i].is_backside = FALSE;
5412 object_mapping[i].action = ACTION_DEFAULT;
5413 object_mapping[i].direction = MV_NONE;
5416 /* always start with reliable default values */
5417 for (p = 0; p < MAX_PLAYERS; p++)
5419 for (i = 0; i < SPR_MAX; i++)
5421 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5422 player_mapping[p][i].action = ACTION_DEFAULT;
5423 player_mapping[p][i].direction = MV_NONE;
5427 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5429 int e = em_object_mapping_list[i].element_em;
5431 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5432 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5434 if (em_object_mapping_list[i].action != -1)
5435 object_mapping[e].action = em_object_mapping_list[i].action;
5437 if (em_object_mapping_list[i].direction != -1)
5438 object_mapping[e].direction =
5439 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5442 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5444 int a = em_player_mapping_list[i].action_em;
5445 int p = em_player_mapping_list[i].player_nr;
5447 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5449 if (em_player_mapping_list[i].action != -1)
5450 player_mapping[p][a].action = em_player_mapping_list[i].action;
5452 if (em_player_mapping_list[i].direction != -1)
5453 player_mapping[p][a].direction =
5454 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5457 for (i = 0; i < TILE_MAX; i++)
5459 int element = object_mapping[i].element_rnd;
5460 int action = object_mapping[i].action;
5461 int direction = object_mapping[i].direction;
5462 boolean is_backside = object_mapping[i].is_backside;
5463 boolean action_removing = (action == ACTION_DIGGING ||
5464 action == ACTION_SNAPPING ||
5465 action == ACTION_COLLECTING);
5466 boolean action_exploding = ((action == ACTION_EXPLODING ||
5467 action == ACTION_SMASHED_BY_ROCK ||
5468 action == ACTION_SMASHED_BY_SPRING) &&
5469 element != EL_DIAMOND);
5470 boolean action_active = (action == ACTION_ACTIVE);
5471 boolean action_other = (action == ACTION_OTHER);
5473 for (j = 0; j < 8; j++)
5475 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5476 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5478 i == Xdrip_stretch ? element :
5479 i == Xdrip_stretchB ? element :
5480 i == Ydrip_s1 ? element :
5481 i == Ydrip_s1B ? element :
5482 i == Xball_1B ? element :
5483 i == Xball_2 ? element :
5484 i == Xball_2B ? element :
5485 i == Yball_eat ? element :
5486 i == Ykey_1_eat ? element :
5487 i == Ykey_2_eat ? element :
5488 i == Ykey_3_eat ? element :
5489 i == Ykey_4_eat ? element :
5490 i == Ykey_5_eat ? element :
5491 i == Ykey_6_eat ? element :
5492 i == Ykey_7_eat ? element :
5493 i == Ykey_8_eat ? element :
5494 i == Ylenses_eat ? element :
5495 i == Ymagnify_eat ? element :
5496 i == Ygrass_eat ? element :
5497 i == Ydirt_eat ? element :
5498 i == Yemerald_stone ? EL_EMERALD :
5499 i == Ydiamond_stone ? EL_ROCK :
5500 i == Xsand_stonein_1 ? element :
5501 i == Xsand_stonein_2 ? element :
5502 i == Xsand_stonein_3 ? element :
5503 i == Xsand_stonein_4 ? element :
5504 is_backside ? EL_EMPTY :
5505 action_removing ? EL_EMPTY :
5507 int effective_action = (j < 7 ? action :
5508 i == Xdrip_stretch ? action :
5509 i == Xdrip_stretchB ? action :
5510 i == Ydrip_s1 ? action :
5511 i == Ydrip_s1B ? action :
5512 i == Xball_1B ? action :
5513 i == Xball_2 ? action :
5514 i == Xball_2B ? action :
5515 i == Yball_eat ? action :
5516 i == Ykey_1_eat ? action :
5517 i == Ykey_2_eat ? action :
5518 i == Ykey_3_eat ? action :
5519 i == Ykey_4_eat ? action :
5520 i == Ykey_5_eat ? action :
5521 i == Ykey_6_eat ? action :
5522 i == Ykey_7_eat ? action :
5523 i == Ykey_8_eat ? action :
5524 i == Ylenses_eat ? action :
5525 i == Ymagnify_eat ? action :
5526 i == Ygrass_eat ? action :
5527 i == Ydirt_eat ? action :
5528 i == Xsand_stonein_1 ? action :
5529 i == Xsand_stonein_2 ? action :
5530 i == Xsand_stonein_3 ? action :
5531 i == Xsand_stonein_4 ? action :
5532 i == Xsand_stoneout_1 ? action :
5533 i == Xsand_stoneout_2 ? action :
5534 i == Xboom_android ? ACTION_EXPLODING :
5535 action_exploding ? ACTION_EXPLODING :
5536 action_active ? action :
5537 action_other ? action :
5539 int graphic = (el_act_dir2img(effective_element, effective_action,
5541 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5543 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5544 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5545 boolean has_action_graphics = (graphic != base_graphic);
5546 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5547 struct GraphicInfo *g = &graphic_info[graphic];
5548 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5551 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5552 boolean special_animation = (action != ACTION_DEFAULT &&
5553 g->anim_frames == 3 &&
5554 g->anim_delay == 2 &&
5555 g->anim_mode & ANIM_LINEAR);
5556 int sync_frame = (i == Xdrip_stretch ? 7 :
5557 i == Xdrip_stretchB ? 7 :
5558 i == Ydrip_s2 ? j + 8 :
5559 i == Ydrip_s2B ? j + 8 :
5568 i == Xfake_acid_1 ? 0 :
5569 i == Xfake_acid_2 ? 10 :
5570 i == Xfake_acid_3 ? 20 :
5571 i == Xfake_acid_4 ? 30 :
5572 i == Xfake_acid_5 ? 40 :
5573 i == Xfake_acid_6 ? 50 :
5574 i == Xfake_acid_7 ? 60 :
5575 i == Xfake_acid_8 ? 70 :
5577 i == Xball_2B ? j + 8 :
5578 i == Yball_eat ? j + 1 :
5579 i == Ykey_1_eat ? j + 1 :
5580 i == Ykey_2_eat ? j + 1 :
5581 i == Ykey_3_eat ? j + 1 :
5582 i == Ykey_4_eat ? j + 1 :
5583 i == Ykey_5_eat ? j + 1 :
5584 i == Ykey_6_eat ? j + 1 :
5585 i == Ykey_7_eat ? j + 1 :
5586 i == Ykey_8_eat ? j + 1 :
5587 i == Ylenses_eat ? j + 1 :
5588 i == Ymagnify_eat ? j + 1 :
5589 i == Ygrass_eat ? j + 1 :
5590 i == Ydirt_eat ? j + 1 :
5591 i == Xamoeba_1 ? 0 :
5592 i == Xamoeba_2 ? 1 :
5593 i == Xamoeba_3 ? 2 :
5594 i == Xamoeba_4 ? 3 :
5595 i == Xamoeba_5 ? 0 :
5596 i == Xamoeba_6 ? 1 :
5597 i == Xamoeba_7 ? 2 :
5598 i == Xamoeba_8 ? 3 :
5599 i == Xexit_2 ? j + 8 :
5600 i == Xexit_3 ? j + 16 :
5601 i == Xdynamite_1 ? 0 :
5602 i == Xdynamite_2 ? 8 :
5603 i == Xdynamite_3 ? 16 :
5604 i == Xdynamite_4 ? 24 :
5605 i == Xsand_stonein_1 ? j + 1 :
5606 i == Xsand_stonein_2 ? j + 9 :
5607 i == Xsand_stonein_3 ? j + 17 :
5608 i == Xsand_stonein_4 ? j + 25 :
5609 i == Xsand_stoneout_1 && j == 0 ? 0 :
5610 i == Xsand_stoneout_1 && j == 1 ? 0 :
5611 i == Xsand_stoneout_1 && j == 2 ? 1 :
5612 i == Xsand_stoneout_1 && j == 3 ? 2 :
5613 i == Xsand_stoneout_1 && j == 4 ? 2 :
5614 i == Xsand_stoneout_1 && j == 5 ? 3 :
5615 i == Xsand_stoneout_1 && j == 6 ? 4 :
5616 i == Xsand_stoneout_1 && j == 7 ? 4 :
5617 i == Xsand_stoneout_2 && j == 0 ? 5 :
5618 i == Xsand_stoneout_2 && j == 1 ? 6 :
5619 i == Xsand_stoneout_2 && j == 2 ? 7 :
5620 i == Xsand_stoneout_2 && j == 3 ? 8 :
5621 i == Xsand_stoneout_2 && j == 4 ? 9 :
5622 i == Xsand_stoneout_2 && j == 5 ? 11 :
5623 i == Xsand_stoneout_2 && j == 6 ? 13 :
5624 i == Xsand_stoneout_2 && j == 7 ? 15 :
5625 i == Xboom_bug && j == 1 ? 2 :
5626 i == Xboom_bug && j == 2 ? 2 :
5627 i == Xboom_bug && j == 3 ? 4 :
5628 i == Xboom_bug && j == 4 ? 4 :
5629 i == Xboom_bug && j == 5 ? 2 :
5630 i == Xboom_bug && j == 6 ? 2 :
5631 i == Xboom_bug && j == 7 ? 0 :
5632 i == Xboom_bomb && j == 1 ? 2 :
5633 i == Xboom_bomb && j == 2 ? 2 :
5634 i == Xboom_bomb && j == 3 ? 4 :
5635 i == Xboom_bomb && j == 4 ? 4 :
5636 i == Xboom_bomb && j == 5 ? 2 :
5637 i == Xboom_bomb && j == 6 ? 2 :
5638 i == Xboom_bomb && j == 7 ? 0 :
5639 i == Xboom_android && j == 7 ? 6 :
5640 i == Xboom_1 && j == 1 ? 2 :
5641 i == Xboom_1 && j == 2 ? 2 :
5642 i == Xboom_1 && j == 3 ? 4 :
5643 i == Xboom_1 && j == 4 ? 4 :
5644 i == Xboom_1 && j == 5 ? 6 :
5645 i == Xboom_1 && j == 6 ? 6 :
5646 i == Xboom_1 && j == 7 ? 8 :
5647 i == Xboom_2 && j == 0 ? 8 :
5648 i == Xboom_2 && j == 1 ? 8 :
5649 i == Xboom_2 && j == 2 ? 10 :
5650 i == Xboom_2 && j == 3 ? 10 :
5651 i == Xboom_2 && j == 4 ? 10 :
5652 i == Xboom_2 && j == 5 ? 12 :
5653 i == Xboom_2 && j == 6 ? 12 :
5654 i == Xboom_2 && j == 7 ? 12 :
5655 special_animation && j == 4 ? 3 :
5656 effective_action != action ? 0 :
5660 Bitmap *debug_bitmap = g_em->bitmap;
5661 int debug_src_x = g_em->src_x;
5662 int debug_src_y = g_em->src_y;
5665 int frame = getAnimationFrame(g->anim_frames,
5668 g->anim_start_frame,
5671 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5672 g->double_movement && is_backside);
5674 g_em->bitmap = src_bitmap;
5675 g_em->src_x = src_x;
5676 g_em->src_y = src_y;
5677 g_em->src_offset_x = 0;
5678 g_em->src_offset_y = 0;
5679 g_em->dst_offset_x = 0;
5680 g_em->dst_offset_y = 0;
5681 g_em->width = TILEX;
5682 g_em->height = TILEY;
5684 g_em->crumbled_bitmap = NULL;
5685 g_em->crumbled_src_x = 0;
5686 g_em->crumbled_src_y = 0;
5687 g_em->crumbled_border_size = 0;
5689 g_em->has_crumbled_graphics = FALSE;
5690 g_em->preserve_background = FALSE;
5693 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5694 printf("::: empty crumbled: %d [%s], %d, %d\n",
5695 effective_element, element_info[effective_element].token_name,
5696 effective_action, direction);
5699 /* if element can be crumbled, but certain action graphics are just empty
5700 space (like snapping sand with the original R'n'D graphics), do not
5701 treat these empty space graphics as crumbled graphics in EMC engine */
5702 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5704 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5706 g_em->has_crumbled_graphics = TRUE;
5707 g_em->crumbled_bitmap = src_bitmap;
5708 g_em->crumbled_src_x = src_x;
5709 g_em->crumbled_src_y = src_y;
5710 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5714 if (element == EL_ROCK &&
5715 effective_action == ACTION_FILLING)
5716 printf("::: has_action_graphics == %d\n", has_action_graphics);
5719 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5720 effective_action == ACTION_MOVING ||
5721 effective_action == ACTION_PUSHING ||
5722 effective_action == ACTION_EATING)) ||
5723 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5724 effective_action == ACTION_EMPTYING)))
5727 (effective_action == ACTION_FALLING ||
5728 effective_action == ACTION_FILLING ||
5729 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5730 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5731 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5732 int num_steps = (i == Ydrip_s1 ? 16 :
5733 i == Ydrip_s1B ? 16 :
5734 i == Ydrip_s2 ? 16 :
5735 i == Ydrip_s2B ? 16 :
5736 i == Xsand_stonein_1 ? 32 :
5737 i == Xsand_stonein_2 ? 32 :
5738 i == Xsand_stonein_3 ? 32 :
5739 i == Xsand_stonein_4 ? 32 :
5740 i == Xsand_stoneout_1 ? 16 :
5741 i == Xsand_stoneout_2 ? 16 : 8);
5742 int cx = ABS(dx) * (TILEX / num_steps);
5743 int cy = ABS(dy) * (TILEY / num_steps);
5744 int step_frame = (i == Ydrip_s2 ? j + 8 :
5745 i == Ydrip_s2B ? j + 8 :
5746 i == Xsand_stonein_2 ? j + 8 :
5747 i == Xsand_stonein_3 ? j + 16 :
5748 i == Xsand_stonein_4 ? j + 24 :
5749 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5750 int step = (is_backside ? step_frame : num_steps - step_frame);
5752 if (is_backside) /* tile where movement starts */
5754 if (dx < 0 || dy < 0)
5756 g_em->src_offset_x = cx * step;
5757 g_em->src_offset_y = cy * step;
5761 g_em->dst_offset_x = cx * step;
5762 g_em->dst_offset_y = cy * step;
5765 else /* tile where movement ends */
5767 if (dx < 0 || dy < 0)
5769 g_em->dst_offset_x = cx * step;
5770 g_em->dst_offset_y = cy * step;
5774 g_em->src_offset_x = cx * step;
5775 g_em->src_offset_y = cy * step;
5779 g_em->width = TILEX - cx * step;
5780 g_em->height = TILEY - cy * step;
5784 /* create unique graphic identifier to decide if tile must be redrawn */
5785 /* bit 31 - 16 (16 bit): EM style graphic
5786 bit 15 - 12 ( 4 bit): EM style frame
5787 bit 11 - 6 ( 6 bit): graphic width
5788 bit 5 - 0 ( 6 bit): graphic height */
5789 g_em->unique_identifier =
5790 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5792 /* create unique graphic identifier to decide if tile must be redrawn */
5793 /* bit 31 - 16 (16 bit): EM style element
5794 bit 15 - 12 ( 4 bit): EM style frame
5795 bit 11 - 6 ( 6 bit): graphic width
5796 bit 5 - 0 ( 6 bit): graphic height */
5797 g_em->unique_identifier =
5798 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5802 if (effective_element == EL_ROCK)
5803 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5804 effective_action, j, graphic, frame, g_em->unique_identifier);
5810 /* skip check for EMC elements not contained in original EMC artwork */
5811 if (element == EL_EMC_FAKE_ACID)
5815 if (g_em->bitmap != debug_bitmap ||
5816 g_em->src_x != debug_src_x ||
5817 g_em->src_y != debug_src_y ||
5818 g_em->src_offset_x != 0 ||
5819 g_em->src_offset_y != 0 ||
5820 g_em->dst_offset_x != 0 ||
5821 g_em->dst_offset_y != 0 ||
5822 g_em->width != TILEX ||
5823 g_em->height != TILEY)
5825 static int last_i = -1;
5833 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5834 i, element, element_info[element].token_name,
5835 element_action_info[effective_action].suffix, direction);
5837 if (element != effective_element)
5838 printf(" [%d ('%s')]",
5840 element_info[effective_element].token_name);
5844 if (g_em->bitmap != debug_bitmap)
5845 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5846 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5848 if (g_em->src_x != debug_src_x ||
5849 g_em->src_y != debug_src_y)
5850 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5851 j, (is_backside ? 'B' : 'F'),
5852 g_em->src_x, g_em->src_y,
5853 g_em->src_x / 32, g_em->src_y / 32,
5854 debug_src_x, debug_src_y,
5855 debug_src_x / 32, debug_src_y / 32);
5857 if (g_em->src_offset_x != 0 ||
5858 g_em->src_offset_y != 0 ||
5859 g_em->dst_offset_x != 0 ||
5860 g_em->dst_offset_y != 0)
5861 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5863 g_em->src_offset_x, g_em->src_offset_y,
5864 g_em->dst_offset_x, g_em->dst_offset_y);
5866 if (g_em->width != TILEX ||
5867 g_em->height != TILEY)
5868 printf(" %d (%d): size %d,%d should be %d,%d\n",
5870 g_em->width, g_em->height, TILEX, TILEY);
5872 num_em_gfx_errors++;
5879 for (i = 0; i < TILE_MAX; i++)
5881 for (j = 0; j < 8; j++)
5883 int element = object_mapping[i].element_rnd;
5884 int action = object_mapping[i].action;
5885 int direction = object_mapping[i].direction;
5886 boolean is_backside = object_mapping[i].is_backside;
5888 int graphic_action = el_act_dir2img(element, action, direction);
5889 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5891 int graphic_action = element_info[element].graphic[action];
5892 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5895 if ((action == ACTION_SMASHED_BY_ROCK ||
5896 action == ACTION_SMASHED_BY_SPRING ||
5897 action == ACTION_EATING) &&
5898 graphic_action == graphic_default)
5900 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5901 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5902 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5903 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5906 /* no separate animation for "smashed by rock" -- use rock instead */
5907 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5908 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5910 g_em->bitmap = g_xx->bitmap;
5911 g_em->src_x = g_xx->src_x;
5912 g_em->src_y = g_xx->src_y;
5913 g_em->src_offset_x = g_xx->src_offset_x;
5914 g_em->src_offset_y = g_xx->src_offset_y;
5915 g_em->dst_offset_x = g_xx->dst_offset_x;
5916 g_em->dst_offset_y = g_xx->dst_offset_y;
5917 g_em->width = g_xx->width;
5918 g_em->height = g_xx->height;
5920 g_em->unique_identifier = g_xx->unique_identifier;
5924 g_em->preserve_background = TRUE;
5929 for (p = 0; p < MAX_PLAYERS; p++)
5931 for (i = 0; i < SPR_MAX; i++)
5933 int element = player_mapping[p][i].element_rnd;
5934 int action = player_mapping[p][i].action;
5935 int direction = player_mapping[p][i].direction;
5937 for (j = 0; j < 8; j++)
5939 int effective_element = element;
5940 int effective_action = action;
5941 int graphic = (direction == MV_NONE ?
5942 el_act2img(effective_element, effective_action) :
5943 el_act_dir2img(effective_element, effective_action,
5945 struct GraphicInfo *g = &graphic_info[graphic];
5946 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5952 Bitmap *debug_bitmap = g_em->bitmap;
5953 int debug_src_x = g_em->src_x;
5954 int debug_src_y = g_em->src_y;
5957 int frame = getAnimationFrame(g->anim_frames,
5960 g->anim_start_frame,
5963 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5965 g_em->bitmap = src_bitmap;
5966 g_em->src_x = src_x;
5967 g_em->src_y = src_y;
5968 g_em->src_offset_x = 0;
5969 g_em->src_offset_y = 0;
5970 g_em->dst_offset_x = 0;
5971 g_em->dst_offset_y = 0;
5972 g_em->width = TILEX;
5973 g_em->height = TILEY;
5978 /* skip check for EMC elements not contained in original EMC artwork */
5979 if (element == EL_PLAYER_3 ||
5980 element == EL_PLAYER_4)
5984 if (g_em->bitmap != debug_bitmap ||
5985 g_em->src_x != debug_src_x ||
5986 g_em->src_y != debug_src_y)
5988 static int last_i = -1;
5996 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5997 p, i, element, element_info[element].token_name,
5998 element_action_info[effective_action].suffix, direction);
6000 if (element != effective_element)
6001 printf(" [%d ('%s')]",
6003 element_info[effective_element].token_name);
6007 if (g_em->bitmap != debug_bitmap)
6008 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6009 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6011 if (g_em->src_x != debug_src_x ||
6012 g_em->src_y != debug_src_y)
6013 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6015 g_em->src_x, g_em->src_y,
6016 g_em->src_x / 32, g_em->src_y / 32,
6017 debug_src_x, debug_src_y,
6018 debug_src_x / 32, debug_src_y / 32);
6020 num_em_gfx_errors++;
6030 printf("::: [%d errors found]\n", num_em_gfx_errors);
6036 void PlayMenuSound()
6038 int sound = menu.sound[game_status];
6040 if (sound == SND_UNDEFINED)
6043 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6044 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6047 if (IS_LOOP_SOUND(sound))
6048 PlaySoundLoop(sound);
6053 void PlayMenuSoundStereo(int sound, int stereo_position)
6055 if (sound == SND_UNDEFINED)
6058 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6059 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6062 if (IS_LOOP_SOUND(sound))
6063 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6065 PlaySoundStereo(sound, stereo_position);
6068 void PlayMenuSoundIfLoop()
6070 int sound = menu.sound[game_status];
6072 if (sound == SND_UNDEFINED)
6075 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6076 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6079 if (IS_LOOP_SOUND(sound))
6080 PlaySoundLoop(sound);
6083 void PlayMenuMusic()
6085 int music = menu.music[game_status];
6087 if (music == MUS_UNDEFINED)
6093 void ToggleFullscreenIfNeeded()
6095 if (setup.fullscreen != video.fullscreen_enabled ||
6096 setup.fullscreen_mode != video.fullscreen_mode_current)
6098 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6100 /* save backbuffer content which gets lost when toggling fullscreen mode */
6101 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6103 if (setup.fullscreen && video.fullscreen_enabled)
6105 /* keep fullscreen mode, but change screen mode */
6106 video.fullscreen_mode_current = setup.fullscreen_mode;
6107 video.fullscreen_enabled = FALSE;
6110 /* toggle fullscreen */
6111 ChangeVideoModeIfNeeded(setup.fullscreen);
6112 setup.fullscreen = video.fullscreen_enabled;
6114 /* restore backbuffer content from temporary backbuffer backup bitmap */
6115 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6117 FreeBitmap(tmp_backbuffer);
6119 redraw_mask = REDRAW_ALL;