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;
443 if (fade_mode == FADE_MODE_CROSSFADE)
444 BlitBitmap(bitmap, backbuffer, x, y, width, height, x, y);
445 else if (fade_mode == FADE_MODE_FADE_OUT)
446 ClearRectangle(backbuffer, x, y, width, height);
453 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay);
455 redraw_mask &= ~fade_mask;
458 void FadeIn(int fade_mask)
460 FadeExt(fade_mask, FADE_MODE_FADE_IN);
463 void FadeOut(int fade_mask)
465 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
468 void FadeCross(int fade_mask)
470 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
473 void SetMainBackgroundImageIfDefined(int graphic)
475 if (graphic_info[graphic].bitmap)
476 SetMainBackgroundImage(graphic);
479 void SetMainBackgroundImage(int graphic)
481 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
482 graphic_info[graphic].bitmap ?
483 graphic_info[graphic].bitmap :
484 graphic_info[IMG_BACKGROUND].bitmap);
487 void SetDoorBackgroundImage(int graphic)
489 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
490 graphic_info[graphic].bitmap ?
491 graphic_info[graphic].bitmap :
492 graphic_info[IMG_BACKGROUND].bitmap);
495 void SetPanelBackground()
497 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
498 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
500 SetDoorBackgroundBitmap(bitmap_db_panel);
503 void DrawBackground(int dst_x, int dst_y, int width, int height)
506 ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
508 ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
511 redraw_mask |= REDRAW_FIELD;
516 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
518 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
520 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
521 SetDrawtoField(DRAW_BUFFERED);
524 SetDrawtoField(DRAW_BACKBUFFER);
526 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
528 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
529 SetDrawtoField(DRAW_DIRECT);
533 void MarkTileDirty(int x, int y)
535 int xx = redraw_x1 + x;
536 int yy = redraw_y1 + y;
541 redraw[xx][yy] = TRUE;
542 redraw_mask |= REDRAW_TILES;
545 void SetBorderElement()
549 BorderElement = EL_EMPTY;
551 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
553 for (x = 0; x < lev_fieldx; x++)
555 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
556 BorderElement = EL_STEELWALL;
558 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
564 void SetRandomAnimationValue(int x, int y)
566 gfx.anim_random_frame = GfxRandom[x][y];
569 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
571 /* animation synchronized with global frame counter, not move position */
572 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
573 sync_frame = FrameCounter;
576 if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
582 printf("::: FOO!\n");
586 return getAnimationFrame(graphic_info[graphic].anim_frames,
587 graphic_info[graphic].anim_delay,
588 graphic_info[graphic].anim_mode,
589 graphic_info[graphic].anim_start_frame,
593 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
594 int *x, int *y, boolean get_backside)
596 struct GraphicInfo *g = &graphic_info[graphic];
597 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
598 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
602 if (g->offset_y == 0) /* frames are ordered horizontally */
604 int max_width = g->anim_frames_per_line * g->width;
605 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
607 *x = pos % max_width;
608 *y = src_y % g->height + pos / max_width * g->height;
610 else if (g->offset_x == 0) /* frames are ordered vertically */
612 int max_height = g->anim_frames_per_line * g->height;
613 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
615 *x = src_x % g->width + pos / max_height * g->width;
616 *y = pos % max_height;
618 else /* frames are ordered diagonally */
620 *x = src_x + frame * g->offset_x;
621 *y = src_y + frame * g->offset_y;
625 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
627 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
630 void DrawGraphic(int x, int y, int graphic, int frame)
633 if (!IN_SCR_FIELD(x, y))
635 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
636 printf("DrawGraphic(): This should never happen!\n");
641 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
645 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
651 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
652 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
655 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
658 if (!IN_SCR_FIELD(x, y))
660 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
661 printf("DrawGraphicThruMask(): This should never happen!\n");
666 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
671 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
677 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
679 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
680 dst_x - src_x, dst_y - src_y);
681 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
684 void DrawMiniGraphic(int x, int y, int graphic)
686 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
687 MarkTileDirty(x / 2, y / 2);
690 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
692 struct GraphicInfo *g = &graphic_info[graphic];
694 int mini_starty = g->bitmap->height * 2 / 3;
697 *x = mini_startx + g->src_x / 2;
698 *y = mini_starty + g->src_y / 2;
701 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
706 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
707 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
710 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
711 int graphic, int frame,
712 int cut_mode, int mask_mode)
717 int width = TILEX, height = TILEY;
720 if (dx || dy) /* shifted graphic */
722 if (x < BX1) /* object enters playfield from the left */
729 else if (x > BX2) /* object enters playfield from the right */
735 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
741 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
743 else if (dx) /* general horizontal movement */
744 MarkTileDirty(x + SIGN(dx), y);
746 if (y < BY1) /* object enters playfield from the top */
748 if (cut_mode==CUT_BELOW) /* object completely above top border */
756 else if (y > BY2) /* object enters playfield from the bottom */
762 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
768 else if (dy > 0 && cut_mode == CUT_ABOVE)
770 if (y == BY2) /* object completely above bottom border */
776 MarkTileDirty(x, y + 1);
777 } /* object leaves playfield to the bottom */
778 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
780 else if (dy) /* general vertical movement */
781 MarkTileDirty(x, y + SIGN(dy));
785 if (!IN_SCR_FIELD(x, y))
787 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
788 printf("DrawGraphicShifted(): This should never happen!\n");
793 if (width > 0 && height > 0)
795 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
800 dst_x = FX + x * TILEX + dx;
801 dst_y = FY + y * TILEY + dy;
803 if (mask_mode == USE_MASKING)
805 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
806 dst_x - src_x, dst_y - src_y);
807 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
811 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
818 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
819 int graphic, int frame,
820 int cut_mode, int mask_mode)
825 int width = TILEX, height = TILEY;
828 int x2 = x + SIGN(dx);
829 int y2 = y + SIGN(dy);
830 int anim_frames = graphic_info[graphic].anim_frames;
831 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
832 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
833 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
835 /* re-calculate animation frame for two-tile movement animation */
836 frame = getGraphicAnimationFrame(graphic, sync_frame);
838 /* check if movement start graphic inside screen area and should be drawn */
839 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
841 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
843 dst_x = FX + x1 * TILEX;
844 dst_y = FY + y1 * TILEY;
846 if (mask_mode == USE_MASKING)
848 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
849 dst_x - src_x, dst_y - src_y);
850 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
854 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
857 MarkTileDirty(x1, y1);
860 /* check if movement end graphic inside screen area and should be drawn */
861 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
863 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
865 dst_x = FX + x2 * TILEX;
866 dst_y = FY + y2 * TILEY;
868 if (mask_mode == USE_MASKING)
870 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
871 dst_x - src_x, dst_y - src_y);
872 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
876 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
879 MarkTileDirty(x2, y2);
883 static void DrawGraphicShifted(int x, int y, int dx, int dy,
884 int graphic, int frame,
885 int cut_mode, int mask_mode)
889 DrawGraphic(x, y, graphic, frame);
894 if (graphic_info[graphic].double_movement) /* EM style movement images */
895 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
897 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
900 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
901 int frame, int cut_mode)
903 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
906 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
907 int cut_mode, int mask_mode)
909 int lx = LEVELX(x), ly = LEVELY(y);
913 if (IN_LEV_FIELD(lx, ly))
915 SetRandomAnimationValue(lx, ly);
917 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
918 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
920 /* do not use double (EM style) movement graphic when not moving */
921 if (graphic_info[graphic].double_movement && !dx && !dy)
923 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
924 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
927 else /* border element */
929 graphic = el2img(element);
930 frame = getGraphicAnimationFrame(graphic, -1);
933 if (element == EL_EXPANDABLE_WALL)
935 boolean left_stopped = FALSE, right_stopped = FALSE;
937 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
939 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
940 right_stopped = TRUE;
942 if (left_stopped && right_stopped)
944 else if (left_stopped)
946 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
947 frame = graphic_info[graphic].anim_frames - 1;
949 else if (right_stopped)
951 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
952 frame = graphic_info[graphic].anim_frames - 1;
957 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
958 else if (mask_mode == USE_MASKING)
959 DrawGraphicThruMask(x, y, graphic, frame);
961 DrawGraphic(x, y, graphic, frame);
964 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
965 int cut_mode, int mask_mode)
967 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
968 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
969 cut_mode, mask_mode);
972 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
975 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
978 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
981 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
984 void DrawLevelElementThruMask(int x, int y, int element)
986 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
989 void DrawLevelFieldThruMask(int x, int y)
991 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
994 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
998 int sx = SCREENX(x), sy = SCREENY(y);
1000 int width, height, cx, cy, i;
1001 int crumbled_border_size = graphic_info[graphic].border_size;
1002 static int xy[4][2] =
1010 if (!IN_LEV_FIELD(x, y))
1013 element = TILE_GFX_ELEMENT(x, y);
1015 /* crumble field itself */
1016 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1018 if (!IN_SCR_FIELD(sx, sy))
1021 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1023 for (i = 0; i < 4; i++)
1025 int xx = x + xy[i][0];
1026 int yy = y + xy[i][1];
1028 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1031 /* check if neighbour field is of same type */
1032 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1035 if (i == 1 || i == 2)
1037 width = crumbled_border_size;
1039 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1045 height = crumbled_border_size;
1047 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1050 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1051 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1054 MarkTileDirty(sx, sy);
1056 else /* crumble neighbour fields */
1058 for (i = 0; i < 4; i++)
1060 int xx = x + xy[i][0];
1061 int yy = y + xy[i][1];
1062 int sxx = sx + xy[i][0];
1063 int syy = sy + xy[i][1];
1066 if (!IN_LEV_FIELD(xx, yy) ||
1067 !IN_SCR_FIELD(sxx, syy) ||
1072 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1076 element = TILE_GFX_ELEMENT(xx, yy);
1078 if (!GFX_CRUMBLED(element))
1081 if (!IN_LEV_FIELD(xx, yy) ||
1082 !IN_SCR_FIELD(sxx, syy) ||
1083 !GFX_CRUMBLED(Feld[xx][yy]) ||
1089 graphic = el_act2crm(element, ACTION_DEFAULT);
1091 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1093 crumbled_border_size = graphic_info[graphic].border_size;
1095 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1097 if (i == 1 || i == 2)
1099 width = crumbled_border_size;
1101 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1107 height = crumbled_border_size;
1109 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1112 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1113 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1115 MarkTileDirty(sxx, syy);
1120 void DrawLevelFieldCrumbledSand(int x, int y)
1124 if (!IN_LEV_FIELD(x, y))
1128 /* !!! CHECK THIS !!! */
1131 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1132 GFX_CRUMBLED(GfxElement[x][y]))
1135 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1136 GfxElement[x][y] != EL_UNDEFINED &&
1137 GFX_CRUMBLED(GfxElement[x][y]))
1139 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1146 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1148 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1151 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1154 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1157 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1158 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1159 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1160 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1161 int sx = SCREENX(x), sy = SCREENY(y);
1163 DrawGraphic(sx, sy, graphic1, frame1);
1164 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1167 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1169 int sx = SCREENX(x), sy = SCREENY(y);
1170 static int xy[4][2] =
1179 for (i = 0; i < 4; i++)
1181 int xx = x + xy[i][0];
1182 int yy = y + xy[i][1];
1183 int sxx = sx + xy[i][0];
1184 int syy = sy + xy[i][1];
1186 if (!IN_LEV_FIELD(xx, yy) ||
1187 !IN_SCR_FIELD(sxx, syy) ||
1188 !GFX_CRUMBLED(Feld[xx][yy]) ||
1192 DrawLevelField(xx, yy);
1196 static int getBorderElement(int x, int y)
1200 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1201 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1202 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1203 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1204 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1205 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1206 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1208 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1209 int steel_position = (x == -1 && y == -1 ? 0 :
1210 x == lev_fieldx && y == -1 ? 1 :
1211 x == -1 && y == lev_fieldy ? 2 :
1212 x == lev_fieldx && y == lev_fieldy ? 3 :
1213 x == -1 || x == lev_fieldx ? 4 :
1214 y == -1 || y == lev_fieldy ? 5 : 6);
1216 return border[steel_position][steel_type];
1219 void DrawScreenElement(int x, int y, int element)
1221 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1222 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1225 void DrawLevelElement(int x, int y, int element)
1227 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1228 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1231 void DrawScreenField(int x, int y)
1233 int lx = LEVELX(x), ly = LEVELY(y);
1234 int element, content;
1236 if (!IN_LEV_FIELD(lx, ly))
1238 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1241 element = getBorderElement(lx, ly);
1243 DrawScreenElement(x, y, element);
1247 element = Feld[lx][ly];
1248 content = Store[lx][ly];
1250 if (IS_MOVING(lx, ly))
1252 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1253 boolean cut_mode = NO_CUTTING;
1255 if (element == EL_QUICKSAND_EMPTYING ||
1256 element == EL_MAGIC_WALL_EMPTYING ||
1257 element == EL_BD_MAGIC_WALL_EMPTYING ||
1258 element == EL_AMOEBA_DROPPING)
1259 cut_mode = CUT_ABOVE;
1260 else if (element == EL_QUICKSAND_FILLING ||
1261 element == EL_MAGIC_WALL_FILLING ||
1262 element == EL_BD_MAGIC_WALL_FILLING)
1263 cut_mode = CUT_BELOW;
1265 if (cut_mode == CUT_ABOVE)
1266 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1268 DrawScreenElement(x, y, EL_EMPTY);
1271 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1272 else if (cut_mode == NO_CUTTING)
1273 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1275 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1277 if (content == EL_ACID)
1279 int dir = MovDir[lx][ly];
1280 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1281 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1283 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1286 else if (IS_BLOCKED(lx, ly))
1291 boolean cut_mode = NO_CUTTING;
1292 int element_old, content_old;
1294 Blocked2Moving(lx, ly, &oldx, &oldy);
1297 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1298 MovDir[oldx][oldy] == MV_RIGHT);
1300 element_old = Feld[oldx][oldy];
1301 content_old = Store[oldx][oldy];
1303 if (element_old == EL_QUICKSAND_EMPTYING ||
1304 element_old == EL_MAGIC_WALL_EMPTYING ||
1305 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1306 element_old == EL_AMOEBA_DROPPING)
1307 cut_mode = CUT_ABOVE;
1309 DrawScreenElement(x, y, EL_EMPTY);
1312 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1314 else if (cut_mode == NO_CUTTING)
1315 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1318 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1321 else if (IS_DRAWABLE(element))
1322 DrawScreenElement(x, y, element);
1324 DrawScreenElement(x, y, EL_EMPTY);
1327 void DrawLevelField(int x, int y)
1329 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1330 DrawScreenField(SCREENX(x), SCREENY(y));
1331 else if (IS_MOVING(x, y))
1335 Moving2Blocked(x, y, &newx, &newy);
1336 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1337 DrawScreenField(SCREENX(newx), SCREENY(newy));
1339 else if (IS_BLOCKED(x, y))
1343 Blocked2Moving(x, y, &oldx, &oldy);
1344 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1345 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1349 void DrawMiniElement(int x, int y, int element)
1353 graphic = el2edimg(element);
1354 DrawMiniGraphic(x, y, graphic);
1357 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1359 int x = sx + scroll_x, y = sy + scroll_y;
1361 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1362 DrawMiniElement(sx, sy, EL_EMPTY);
1363 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1364 DrawMiniElement(sx, sy, Feld[x][y]);
1366 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1369 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1370 int x, int y, int xsize, int ysize, int font_nr)
1372 int font_width = getFontWidth(font_nr);
1373 int font_height = getFontHeight(font_nr);
1374 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1377 int dst_x = SX + startx + x * font_width;
1378 int dst_y = SY + starty + y * font_height;
1379 int width = graphic_info[graphic].width;
1380 int height = graphic_info[graphic].height;
1381 int inner_width = MAX(width - 2 * font_width, font_width);
1382 int inner_height = MAX(height - 2 * font_height, font_height);
1383 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1384 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1385 boolean draw_masked = graphic_info[graphic].draw_masked;
1387 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1389 if (src_bitmap == NULL || width < font_width || height < font_height)
1391 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1395 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1396 inner_sx + (x - 1) * font_width % inner_width);
1397 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1398 inner_sy + (y - 1) * font_height % inner_height);
1402 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1403 dst_x - src_x, dst_y - src_y);
1404 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1408 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1412 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1414 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1415 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1416 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1417 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1418 boolean no_delay = (tape.warp_forward);
1419 unsigned long anim_delay = 0;
1420 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1421 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1422 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1423 int font_width = getFontWidth(font_nr);
1424 int font_height = getFontHeight(font_nr);
1425 int max_xsize = level.envelope[envelope_nr].xsize;
1426 int max_ysize = level.envelope[envelope_nr].ysize;
1427 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1428 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1429 int xend = max_xsize;
1430 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1431 int xstep = (xstart < xend ? 1 : 0);
1432 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1435 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1437 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1438 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1439 int sx = (SXSIZE - xsize * font_width) / 2;
1440 int sy = (SYSIZE - ysize * font_height) / 2;
1443 SetDrawtoField(DRAW_BUFFERED);
1445 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1447 SetDrawtoField(DRAW_BACKBUFFER);
1449 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1450 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1452 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1453 level.envelope[envelope_nr].text, font_nr, max_xsize,
1454 xsize - 2, ysize - 2, mask_mode);
1456 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1459 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1463 void ShowEnvelope(int envelope_nr)
1465 int element = EL_ENVELOPE_1 + envelope_nr;
1466 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1467 int sound_opening = element_info[element].sound[ACTION_OPENING];
1468 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1469 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1470 boolean no_delay = (tape.warp_forward);
1471 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1472 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1473 int anim_mode = graphic_info[graphic].anim_mode;
1474 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1475 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1477 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1479 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1481 if (anim_mode == ANIM_DEFAULT)
1482 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1484 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1487 Delay(wait_delay_value);
1489 WaitForEventToContinue();
1491 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1493 if (anim_mode != ANIM_NONE)
1494 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1496 if (anim_mode == ANIM_DEFAULT)
1497 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1499 game.envelope_active = FALSE;
1501 SetDrawtoField(DRAW_BUFFERED);
1503 redraw_mask |= REDRAW_FIELD;
1507 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1512 int width_mult, width_div;
1513 int height_mult, height_div;
1521 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1522 5 - log_2(tilesize));
1523 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1524 int width_mult = offset_calc[offset_calc_pos].width_mult;
1525 int width_div = offset_calc[offset_calc_pos].width_div;
1526 int height_mult = offset_calc[offset_calc_pos].height_mult;
1527 int height_div = offset_calc[offset_calc_pos].height_div;
1528 int mini_startx = src_bitmap->width * width_mult / width_div;
1529 int mini_starty = src_bitmap->height * height_mult / height_div;
1530 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1531 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1533 *bitmap = src_bitmap;
1538 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1542 int graphic = el2preimg(element);
1544 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1545 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1552 SetDrawBackgroundMask(REDRAW_NONE);
1555 for (x = BX1; x <= BX2; x++)
1556 for (y = BY1; y <= BY2; y++)
1557 DrawScreenField(x, y);
1559 redraw_mask |= REDRAW_FIELD;
1562 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1566 for (x = 0; x < size_x; x++)
1567 for (y = 0; y < size_y; y++)
1568 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1570 redraw_mask |= REDRAW_FIELD;
1573 static void DrawPreviewLevelExt(int from_x, int from_y)
1575 boolean show_level_border = (BorderElement != EL_EMPTY);
1576 int dst_x = preview.x;
1577 int dst_y = preview.y;
1578 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1579 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1580 int tile_size = preview.tile_size;
1581 int preview_width = preview.xsize * tile_size;
1582 int preview_height = preview.ysize * tile_size;
1583 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1584 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1587 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1589 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1590 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1592 for (x = 0; x < real_preview_xsize; x++)
1594 for (y = 0; y < real_preview_ysize; y++)
1596 int lx = from_x + x + (show_level_border ? -1 : 0);
1597 int ly = from_y + y + (show_level_border ? -1 : 0);
1598 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1599 getBorderElement(lx, ly));
1601 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1602 element, tile_size);
1606 redraw_mask |= REDRAW_MICROLEVEL;
1609 #define MICROLABEL_EMPTY 0
1610 #define MICROLABEL_LEVEL_NAME 1
1611 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1612 #define MICROLABEL_LEVEL_AUTHOR 3
1613 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1614 #define MICROLABEL_IMPORTED_FROM 5
1615 #define MICROLABEL_IMPORTED_BY_HEAD 6
1616 #define MICROLABEL_IMPORTED_BY 7
1618 static void DrawPreviewLevelLabelExt(int mode)
1620 char label_text[MAX_OUTPUT_LINESIZE + 1];
1621 int max_len_label_text;
1622 int font_nr = FONT_TEXT_2;
1625 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1626 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1627 mode == MICROLABEL_IMPORTED_BY_HEAD)
1628 font_nr = FONT_TEXT_3;
1630 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1632 for (i = 0; i < max_len_label_text; i++)
1633 label_text[i] = ' ';
1634 label_text[max_len_label_text] = '\0';
1636 if (strlen(label_text) > 0)
1638 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1639 int lypos = MICROLABEL2_YPOS;
1641 DrawText(lxpos, lypos, label_text, font_nr);
1645 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1646 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1647 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1648 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1649 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1650 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1651 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1652 max_len_label_text);
1653 label_text[max_len_label_text] = '\0';
1655 if (strlen(label_text) > 0)
1657 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1658 int lypos = MICROLABEL2_YPOS;
1660 DrawText(lxpos, lypos, label_text, font_nr);
1663 redraw_mask |= REDRAW_MICROLEVEL;
1666 void DrawPreviewLevel(boolean restart)
1668 static unsigned long scroll_delay = 0;
1669 static unsigned long label_delay = 0;
1670 static int from_x, from_y, scroll_direction;
1671 static int label_state, label_counter;
1672 unsigned long scroll_delay_value = preview.step_delay;
1673 boolean show_level_border = (BorderElement != EL_EMPTY);
1674 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1675 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1676 int last_game_status = game_status; /* save current game status */
1678 /* force PREVIEW font on preview level */
1679 game_status = GAME_MODE_PSEUDO_PREVIEW;
1683 from_x = from_y = 0;
1684 scroll_direction = MV_RIGHT;
1688 DrawPreviewLevelExt(from_x, from_y);
1689 DrawPreviewLevelLabelExt(label_state);
1691 /* initialize delay counters */
1692 DelayReached(&scroll_delay, 0);
1693 DelayReached(&label_delay, 0);
1695 if (leveldir_current->name)
1697 char label_text[MAX_OUTPUT_LINESIZE + 1];
1698 int font_nr = FONT_TEXT_1;
1699 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1702 strncpy(label_text, leveldir_current->name, max_len_label_text);
1703 label_text[max_len_label_text] = '\0';
1705 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1706 lypos = SY + MICROLABEL1_YPOS;
1708 DrawText(lxpos, lypos, label_text, font_nr);
1711 game_status = last_game_status; /* restore current game status */
1716 /* scroll preview level, if needed */
1717 if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1718 DelayReached(&scroll_delay, scroll_delay_value))
1720 switch (scroll_direction)
1725 from_x -= preview.step_offset;
1726 from_x = (from_x < 0 ? 0 : from_x);
1729 scroll_direction = MV_UP;
1733 if (from_x < level_xsize - preview.xsize)
1735 from_x += preview.step_offset;
1736 from_x = (from_x > level_xsize - preview.xsize ?
1737 level_xsize - preview.xsize : from_x);
1740 scroll_direction = MV_DOWN;
1746 from_y -= preview.step_offset;
1747 from_y = (from_y < 0 ? 0 : from_y);
1750 scroll_direction = MV_RIGHT;
1754 if (from_y < level_ysize - preview.ysize)
1756 from_y += preview.step_offset;
1757 from_y = (from_y > level_ysize - preview.ysize ?
1758 level_ysize - preview.ysize : from_y);
1761 scroll_direction = MV_LEFT;
1768 DrawPreviewLevelExt(from_x, from_y);
1771 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1772 /* redraw micro level label, if needed */
1773 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1774 !strEqual(level.author, ANONYMOUS_NAME) &&
1775 !strEqual(level.author, leveldir_current->name) &&
1776 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1778 int max_label_counter = 23;
1780 if (leveldir_current->imported_from != NULL &&
1781 strlen(leveldir_current->imported_from) > 0)
1782 max_label_counter += 14;
1783 if (leveldir_current->imported_by != NULL &&
1784 strlen(leveldir_current->imported_by) > 0)
1785 max_label_counter += 14;
1787 label_counter = (label_counter + 1) % max_label_counter;
1788 label_state = (label_counter >= 0 && label_counter <= 7 ?
1789 MICROLABEL_LEVEL_NAME :
1790 label_counter >= 9 && label_counter <= 12 ?
1791 MICROLABEL_LEVEL_AUTHOR_HEAD :
1792 label_counter >= 14 && label_counter <= 21 ?
1793 MICROLABEL_LEVEL_AUTHOR :
1794 label_counter >= 23 && label_counter <= 26 ?
1795 MICROLABEL_IMPORTED_FROM_HEAD :
1796 label_counter >= 28 && label_counter <= 35 ?
1797 MICROLABEL_IMPORTED_FROM :
1798 label_counter >= 37 && label_counter <= 40 ?
1799 MICROLABEL_IMPORTED_BY_HEAD :
1800 label_counter >= 42 && label_counter <= 49 ?
1801 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1803 if (leveldir_current->imported_from == NULL &&
1804 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1805 label_state == MICROLABEL_IMPORTED_FROM))
1806 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1807 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1809 DrawPreviewLevelLabelExt(label_state);
1812 game_status = last_game_status; /* restore current game status */
1815 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1816 int graphic, int sync_frame, int mask_mode)
1818 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1820 if (mask_mode == USE_MASKING)
1821 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1823 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1826 inline void DrawGraphicAnimation(int x, int y, int graphic)
1828 int lx = LEVELX(x), ly = LEVELY(y);
1830 if (!IN_SCR_FIELD(x, y))
1833 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1834 graphic, GfxFrame[lx][ly], NO_MASKING);
1835 MarkTileDirty(x, y);
1838 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1840 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1843 void DrawLevelElementAnimation(int x, int y, int element)
1845 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1847 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1850 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1852 int sx = SCREENX(x), sy = SCREENY(y);
1854 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1857 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1860 DrawGraphicAnimation(sx, sy, graphic);
1863 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1864 DrawLevelFieldCrumbledSand(x, y);
1866 if (GFX_CRUMBLED(Feld[x][y]))
1867 DrawLevelFieldCrumbledSand(x, y);
1871 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1873 int sx = SCREENX(x), sy = SCREENY(y);
1876 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1879 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1881 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1884 DrawGraphicAnimation(sx, sy, graphic);
1886 if (GFX_CRUMBLED(element))
1887 DrawLevelFieldCrumbledSand(x, y);
1890 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1892 if (player->use_murphy)
1894 /* this works only because currently only one player can be "murphy" ... */
1895 static int last_horizontal_dir = MV_LEFT;
1896 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1898 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1899 last_horizontal_dir = move_dir;
1901 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
1903 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1905 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1911 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1914 static boolean equalGraphics(int graphic1, int graphic2)
1916 struct GraphicInfo *g1 = &graphic_info[graphic1];
1917 struct GraphicInfo *g2 = &graphic_info[graphic2];
1919 return (g1->bitmap == g2->bitmap &&
1920 g1->src_x == g2->src_x &&
1921 g1->src_y == g2->src_y &&
1922 g1->anim_frames == g2->anim_frames &&
1923 g1->anim_delay == g2->anim_delay &&
1924 g1->anim_mode == g2->anim_mode);
1927 void DrawAllPlayers()
1931 for (i = 0; i < MAX_PLAYERS; i++)
1932 if (stored_player[i].active)
1933 DrawPlayer(&stored_player[i]);
1936 void DrawPlayerField(int x, int y)
1938 if (!IS_PLAYER(x, y))
1941 DrawPlayer(PLAYERINFO(x, y));
1944 void DrawPlayer(struct PlayerInfo *player)
1946 int jx = player->jx;
1947 int jy = player->jy;
1948 int move_dir = player->MovDir;
1949 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1950 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
1951 int last_jx = (player->is_moving ? jx - dx : jx);
1952 int last_jy = (player->is_moving ? jy - dy : jy);
1953 int next_jx = jx + dx;
1954 int next_jy = jy + dy;
1955 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1956 boolean player_is_opaque = FALSE;
1957 int sx = SCREENX(jx), sy = SCREENY(jy);
1958 int sxx = 0, syy = 0;
1959 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1961 int action = ACTION_DEFAULT;
1962 int last_player_graphic = getPlayerGraphic(player, move_dir);
1963 int last_player_frame = player->Frame;
1967 /* GfxElement[][] is set to the element the player is digging or collecting;
1968 remove also for off-screen player if the player is not moving anymore */
1969 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1970 GfxElement[jx][jy] = EL_UNDEFINED;
1973 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1977 if (!IN_LEV_FIELD(jx, jy))
1979 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1980 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1981 printf("DrawPlayerField(): This should never happen!\n");
1986 if (element == EL_EXPLOSION)
1989 action = (player->is_pushing ? ACTION_PUSHING :
1990 player->is_digging ? ACTION_DIGGING :
1991 player->is_collecting ? ACTION_COLLECTING :
1992 player->is_moving ? ACTION_MOVING :
1993 player->is_snapping ? ACTION_SNAPPING :
1994 player->is_dropping ? ACTION_DROPPING :
1995 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
1998 if (player->is_waiting)
1999 move_dir = player->dir_waiting;
2002 InitPlayerGfxAnimation(player, action, move_dir);
2004 /* ----------------------------------------------------------------------- */
2005 /* draw things in the field the player is leaving, if needed */
2006 /* ----------------------------------------------------------------------- */
2008 if (player->is_moving)
2010 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2012 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2014 if (last_element == EL_DYNAMITE_ACTIVE ||
2015 last_element == EL_EM_DYNAMITE_ACTIVE ||
2016 last_element == EL_SP_DISK_RED_ACTIVE)
2017 DrawDynamite(last_jx, last_jy);
2019 DrawLevelFieldThruMask(last_jx, last_jy);
2021 else if (last_element == EL_DYNAMITE_ACTIVE ||
2022 last_element == EL_EM_DYNAMITE_ACTIVE ||
2023 last_element == EL_SP_DISK_RED_ACTIVE)
2024 DrawDynamite(last_jx, last_jy);
2026 /* !!! this is not enough to prevent flickering of players which are
2027 moving next to each others without a free tile between them -- this
2028 can only be solved by drawing all players layer by layer (first the
2029 background, then the foreground etc.) !!! => TODO */
2030 else if (!IS_PLAYER(last_jx, last_jy))
2031 DrawLevelField(last_jx, last_jy);
2034 DrawLevelField(last_jx, last_jy);
2037 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2038 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2041 if (!IN_SCR_FIELD(sx, sy))
2044 if (setup.direct_draw)
2045 SetDrawtoField(DRAW_BUFFERED);
2047 /* ----------------------------------------------------------------------- */
2048 /* draw things behind the player, if needed */
2049 /* ----------------------------------------------------------------------- */
2052 DrawLevelElement(jx, jy, Back[jx][jy]);
2053 else if (IS_ACTIVE_BOMB(element))
2054 DrawLevelElement(jx, jy, EL_EMPTY);
2057 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2059 int old_element = GfxElement[jx][jy];
2060 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2061 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2063 if (GFX_CRUMBLED(old_element))
2064 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2066 DrawGraphic(sx, sy, old_graphic, frame);
2068 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2069 player_is_opaque = TRUE;
2073 GfxElement[jx][jy] = EL_UNDEFINED;
2075 /* make sure that pushed elements are drawn with correct frame rate */
2077 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2079 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2080 GfxFrame[jx][jy] = player->StepFrame;
2082 if (player->is_pushing && player->is_moving)
2083 GfxFrame[jx][jy] = player->StepFrame;
2086 DrawLevelField(jx, jy);
2090 /* ----------------------------------------------------------------------- */
2091 /* draw player himself */
2092 /* ----------------------------------------------------------------------- */
2094 graphic = getPlayerGraphic(player, move_dir);
2096 /* in the case of changed player action or direction, prevent the current
2097 animation frame from being restarted for identical animations */
2098 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2099 player->Frame = last_player_frame;
2101 frame = getGraphicAnimationFrame(graphic, player->Frame);
2105 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2106 sxx = player->GfxPos;
2108 syy = player->GfxPos;
2111 if (!setup.soft_scrolling && ScreenMovPos)
2114 if (player_is_opaque)
2115 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2117 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2119 if (SHIELD_ON(player))
2121 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2122 IMG_SHIELD_NORMAL_ACTIVE);
2123 int frame = getGraphicAnimationFrame(graphic, -1);
2125 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2128 /* ----------------------------------------------------------------------- */
2129 /* draw things the player is pushing, if needed */
2130 /* ----------------------------------------------------------------------- */
2133 printf("::: %d, %d [%d, %d] [%d]\n",
2134 player->is_pushing, player_is_moving, player->GfxAction,
2135 player->is_moving, player_is_moving);
2139 if (player->is_pushing && player->is_moving)
2141 int px = SCREENX(jx), py = SCREENY(jy);
2142 int pxx = (TILEX - ABS(sxx)) * dx;
2143 int pyy = (TILEY - ABS(syy)) * dy;
2144 int gfx_frame = GfxFrame[jx][jy];
2150 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2152 element = Feld[next_jx][next_jy];
2153 gfx_frame = GfxFrame[next_jx][next_jy];
2156 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2159 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2160 frame = getGraphicAnimationFrame(graphic, sync_frame);
2162 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2165 /* draw background element under pushed element (like the Sokoban field) */
2166 if (Back[next_jx][next_jy])
2167 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2169 /* masked drawing is needed for EMC style (double) movement graphics */
2170 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2174 /* ----------------------------------------------------------------------- */
2175 /* draw things in front of player (active dynamite or dynabombs) */
2176 /* ----------------------------------------------------------------------- */
2178 if (IS_ACTIVE_BOMB(element))
2180 graphic = el2img(element);
2181 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2183 if (game.emulation == EMU_SUPAPLEX)
2184 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2186 DrawGraphicThruMask(sx, sy, graphic, frame);
2189 if (player_is_moving && last_element == EL_EXPLOSION)
2191 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2192 GfxElement[last_jx][last_jy] : EL_EMPTY);
2193 int graphic = el_act2img(element, ACTION_EXPLODING);
2194 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2195 int phase = ExplodePhase[last_jx][last_jy] - 1;
2196 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2199 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2202 /* ----------------------------------------------------------------------- */
2203 /* draw elements the player is just walking/passing through/under */
2204 /* ----------------------------------------------------------------------- */
2206 if (player_is_moving)
2208 /* handle the field the player is leaving ... */
2209 if (IS_ACCESSIBLE_INSIDE(last_element))
2210 DrawLevelField(last_jx, last_jy);
2211 else if (IS_ACCESSIBLE_UNDER(last_element))
2212 DrawLevelFieldThruMask(last_jx, last_jy);
2215 /* do not redraw accessible elements if the player is just pushing them */
2216 if (!player_is_moving || !player->is_pushing)
2218 /* ... and the field the player is entering */
2219 if (IS_ACCESSIBLE_INSIDE(element))
2220 DrawLevelField(jx, jy);
2221 else if (IS_ACCESSIBLE_UNDER(element))
2222 DrawLevelFieldThruMask(jx, jy);
2225 if (setup.direct_draw)
2227 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2228 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2229 int x_size = TILEX * (1 + ABS(jx - last_jx));
2230 int y_size = TILEY * (1 + ABS(jy - last_jy));
2232 BlitBitmap(drawto_field, window,
2233 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2234 SetDrawtoField(DRAW_DIRECT);
2237 MarkTileDirty(sx, sy);
2240 /* ------------------------------------------------------------------------- */
2242 void WaitForEventToContinue()
2244 boolean still_wait = TRUE;
2246 /* simulate releasing mouse button over last gadget, if still pressed */
2248 HandleGadgets(-1, -1, 0);
2250 button_status = MB_RELEASED;
2262 case EVENT_BUTTONPRESS:
2263 case EVENT_KEYPRESS:
2267 case EVENT_KEYRELEASE:
2268 ClearPlayerAction();
2272 HandleOtherEvents(&event);
2276 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2283 /* don't eat all CPU time */
2288 #define MAX_REQUEST_LINES 13
2289 #define MAX_REQUEST_LINE_FONT1_LEN 7
2290 #define MAX_REQUEST_LINE_FONT2_LEN 10
2292 boolean Request(char *text, unsigned int req_state)
2294 int mx, my, ty, result = -1;
2295 unsigned int old_door_state;
2296 int last_game_status = game_status; /* save current game status */
2297 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2298 int font_nr = FONT_TEXT_2;
2299 int max_word_len = 0;
2302 for (text_ptr = text; *text_ptr; text_ptr++)
2304 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2306 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2308 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2309 font_nr = FONT_LEVEL_NUMBER;
2315 if (game_status == GAME_MODE_PLAYING &&
2316 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2317 BlitScreenToBitmap_EM(backbuffer);
2319 /* disable deactivated drawing when quick-loading level tape recording */
2320 if (tape.playing && tape.deactivate_display)
2321 TapeDeactivateDisplayOff(TRUE);
2323 SetMouseCursor(CURSOR_DEFAULT);
2325 #if defined(NETWORK_AVALIABLE)
2326 /* pause network game while waiting for request to answer */
2327 if (options.network &&
2328 game_status == GAME_MODE_PLAYING &&
2329 req_state & REQUEST_WAIT_FOR_INPUT)
2330 SendToServer_PausePlaying();
2333 old_door_state = GetDoorState();
2335 /* simulate releasing mouse button over last gadget, if still pressed */
2337 HandleGadgets(-1, -1, 0);
2341 if (old_door_state & DOOR_OPEN_1)
2343 CloseDoor(DOOR_CLOSE_1);
2345 /* save old door content */
2346 BlitBitmap(bitmap_db_door, bitmap_db_door,
2347 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2348 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2352 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2355 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2357 /* clear door drawing field */
2358 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2360 /* force DOOR font on preview level */
2361 game_status = GAME_MODE_PSEUDO_DOOR;
2363 /* write text for request */
2364 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2366 char text_line[max_request_line_len + 1];
2372 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2375 if (!tc || tc == ' ')
2386 strncpy(text_line, text, tl);
2389 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2390 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2391 text_line, font_nr);
2393 text += tl + (tc == ' ' ? 1 : 0);
2396 game_status = last_game_status; /* restore current game status */
2398 if (req_state & REQ_ASK)
2400 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2401 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2403 else if (req_state & REQ_CONFIRM)
2405 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2407 else if (req_state & REQ_PLAYER)
2409 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2410 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2411 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2412 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2415 /* copy request gadgets to door backbuffer */
2416 BlitBitmap(drawto, bitmap_db_door,
2417 DX, DY, DXSIZE, DYSIZE,
2418 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2420 OpenDoor(DOOR_OPEN_1);
2422 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2424 if (game_status == GAME_MODE_PLAYING)
2426 SetPanelBackground();
2427 SetDrawBackgroundMask(REDRAW_DOOR_1);
2431 SetDrawBackgroundMask(REDRAW_FIELD);
2437 if (game_status != GAME_MODE_MAIN)
2440 button_status = MB_RELEASED;
2442 request_gadget_id = -1;
2444 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2456 case EVENT_BUTTONPRESS:
2457 case EVENT_BUTTONRELEASE:
2458 case EVENT_MOTIONNOTIFY:
2460 if (event.type == EVENT_MOTIONNOTIFY)
2462 if (!PointerInWindow(window))
2463 continue; /* window and pointer are on different screens */
2468 motion_status = TRUE;
2469 mx = ((MotionEvent *) &event)->x;
2470 my = ((MotionEvent *) &event)->y;
2474 motion_status = FALSE;
2475 mx = ((ButtonEvent *) &event)->x;
2476 my = ((ButtonEvent *) &event)->y;
2477 if (event.type == EVENT_BUTTONPRESS)
2478 button_status = ((ButtonEvent *) &event)->button;
2480 button_status = MB_RELEASED;
2483 /* this sets 'request_gadget_id' */
2484 HandleGadgets(mx, my, button_status);
2486 switch(request_gadget_id)
2488 case TOOL_CTRL_ID_YES:
2491 case TOOL_CTRL_ID_NO:
2494 case TOOL_CTRL_ID_CONFIRM:
2495 result = TRUE | FALSE;
2498 case TOOL_CTRL_ID_PLAYER_1:
2501 case TOOL_CTRL_ID_PLAYER_2:
2504 case TOOL_CTRL_ID_PLAYER_3:
2507 case TOOL_CTRL_ID_PLAYER_4:
2518 case EVENT_KEYPRESS:
2519 switch(GetEventKey((KeyEvent *)&event, TRUE))
2532 if (req_state & REQ_PLAYER)
2536 case EVENT_KEYRELEASE:
2537 ClearPlayerAction();
2541 HandleOtherEvents(&event);
2545 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2547 int joy = AnyJoystick();
2549 if (joy & JOY_BUTTON_1)
2551 else if (joy & JOY_BUTTON_2)
2557 /* don't eat all CPU time */
2561 if (game_status != GAME_MODE_MAIN)
2566 if (!(req_state & REQ_STAY_OPEN))
2568 CloseDoor(DOOR_CLOSE_1);
2570 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2571 (req_state & REQ_REOPEN))
2572 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2577 if (game_status == GAME_MODE_PLAYING)
2579 SetPanelBackground();
2580 SetDrawBackgroundMask(REDRAW_DOOR_1);
2584 SetDrawBackgroundMask(REDRAW_FIELD);
2587 #if defined(NETWORK_AVALIABLE)
2588 /* continue network game after request */
2589 if (options.network &&
2590 game_status == GAME_MODE_PLAYING &&
2591 req_state & REQUEST_WAIT_FOR_INPUT)
2592 SendToServer_ContinuePlaying();
2595 /* restore deactivated drawing when quick-loading level tape recording */
2596 if (tape.playing && tape.deactivate_display)
2597 TapeDeactivateDisplayOn();
2602 unsigned int OpenDoor(unsigned int door_state)
2604 if (door_state & DOOR_COPY_BACK)
2606 if (door_state & DOOR_OPEN_1)
2607 BlitBitmap(bitmap_db_door, bitmap_db_door,
2608 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2609 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2611 if (door_state & DOOR_OPEN_2)
2612 BlitBitmap(bitmap_db_door, bitmap_db_door,
2613 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2614 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2616 door_state &= ~DOOR_COPY_BACK;
2619 return MoveDoor(door_state);
2622 unsigned int CloseDoor(unsigned int door_state)
2624 unsigned int old_door_state = GetDoorState();
2626 if (!(door_state & DOOR_NO_COPY_BACK))
2628 if (old_door_state & DOOR_OPEN_1)
2629 BlitBitmap(backbuffer, bitmap_db_door,
2630 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2632 if (old_door_state & DOOR_OPEN_2)
2633 BlitBitmap(backbuffer, bitmap_db_door,
2634 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2636 door_state &= ~DOOR_NO_COPY_BACK;
2639 return MoveDoor(door_state);
2642 unsigned int GetDoorState()
2644 return MoveDoor(DOOR_GET_STATE);
2647 unsigned int SetDoorState(unsigned int door_state)
2649 return MoveDoor(door_state | DOOR_SET_STATE);
2652 unsigned int MoveDoor(unsigned int door_state)
2654 static int door1 = DOOR_OPEN_1;
2655 static int door2 = DOOR_CLOSE_2;
2656 unsigned long door_delay = 0;
2657 unsigned long door_delay_value;
2660 if (door_1.width < 0 || door_1.width > DXSIZE)
2661 door_1.width = DXSIZE;
2662 if (door_1.height < 0 || door_1.height > DYSIZE)
2663 door_1.height = DYSIZE;
2664 if (door_2.width < 0 || door_2.width > VXSIZE)
2665 door_2.width = VXSIZE;
2666 if (door_2.height < 0 || door_2.height > VYSIZE)
2667 door_2.height = VYSIZE;
2669 if (door_state == DOOR_GET_STATE)
2670 return (door1 | door2);
2672 if (door_state & DOOR_SET_STATE)
2674 if (door_state & DOOR_ACTION_1)
2675 door1 = door_state & DOOR_ACTION_1;
2676 if (door_state & DOOR_ACTION_2)
2677 door2 = door_state & DOOR_ACTION_2;
2679 return (door1 | door2);
2682 if (!(door_state & DOOR_FORCE_REDRAW))
2684 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2685 door_state &= ~DOOR_OPEN_1;
2686 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2687 door_state &= ~DOOR_CLOSE_1;
2688 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2689 door_state &= ~DOOR_OPEN_2;
2690 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2691 door_state &= ~DOOR_CLOSE_2;
2694 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2697 if (setup.quick_doors)
2699 stepsize = 20; /* must be choosen to always draw last frame */
2700 door_delay_value = 0;
2703 if (global.autoplay_leveldir)
2705 door_state |= DOOR_NO_DELAY;
2706 door_state &= ~DOOR_CLOSE_ALL;
2709 if (door_state & DOOR_ACTION)
2711 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2712 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2713 boolean door_1_done = (!handle_door_1);
2714 boolean door_2_done = (!handle_door_2);
2715 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2716 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2717 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2718 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2719 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2720 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2721 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2722 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2723 int door_skip = max_door_size - door_size;
2725 int end = door_size;
2727 int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
2731 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2733 int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2737 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2739 /* opening door sound has priority over simultaneously closing door */
2740 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2741 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2742 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2743 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2746 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2749 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2750 GC gc = bitmap->stored_clip_gc;
2752 if (door_state & DOOR_ACTION_1)
2754 int a = MIN(x * door_1.step_offset, end);
2755 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2756 int i = p + door_skip;
2758 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2760 BlitBitmap(bitmap_db_door, drawto,
2761 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2762 DXSIZE, DYSIZE, DX, DY);
2766 BlitBitmap(bitmap_db_door, drawto,
2767 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2768 DXSIZE, DYSIZE - p / 2, DX, DY);
2770 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2773 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2775 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2776 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2777 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2778 int dst2_x = DX, dst2_y = DY;
2779 int width = i, height = DYSIZE;
2781 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2782 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2785 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2786 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2789 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2791 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2792 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2793 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2794 int dst2_x = DX, dst2_y = DY;
2795 int width = DXSIZE, height = i;
2797 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2798 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2801 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2802 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2805 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2807 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2809 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2810 BlitBitmapMasked(bitmap, drawto,
2811 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2812 DX + DXSIZE - i, DY + j);
2813 BlitBitmapMasked(bitmap, drawto,
2814 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2815 DX + DXSIZE - i, DY + 140 + j);
2816 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2817 DY - (DOOR_GFX_PAGEY1 + j));
2818 BlitBitmapMasked(bitmap, drawto,
2819 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2821 BlitBitmapMasked(bitmap, drawto,
2822 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2825 BlitBitmapMasked(bitmap, drawto,
2826 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2828 BlitBitmapMasked(bitmap, drawto,
2829 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2831 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2832 BlitBitmapMasked(bitmap, drawto,
2833 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2834 DX + DXSIZE - i, DY + 77 + j);
2835 BlitBitmapMasked(bitmap, drawto,
2836 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2837 DX + DXSIZE - i, DY + 203 + j);
2840 redraw_mask |= REDRAW_DOOR_1;
2841 door_1_done = (a == end);
2844 if (door_state & DOOR_ACTION_2)
2847 int a = MIN(x * door_2.step_offset, door_size);
2848 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2849 int i = p + door_skip;
2851 int a = MIN(x * door_2.step_offset, door_size_2);
2852 int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2853 int i = p + door_skip;
2856 if (door_2.anim_mode & ANIM_STATIC_PANEL)
2858 BlitBitmap(bitmap_db_door, drawto,
2859 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2860 VXSIZE, VYSIZE, VX, VY);
2862 else if (x <= VYSIZE)
2864 BlitBitmap(bitmap_db_door, drawto,
2865 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2866 VXSIZE, VYSIZE - p / 2, VX, VY);
2868 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2871 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2873 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2874 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2875 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2876 int dst2_x = VX, dst2_y = VY;
2877 int width = i, height = VYSIZE;
2879 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2880 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2883 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2884 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2887 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2889 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2890 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2891 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2892 int dst2_x = VX, dst2_y = VY;
2893 int width = VXSIZE, height = i;
2895 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2896 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2899 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2900 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2903 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2905 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2907 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2908 BlitBitmapMasked(bitmap, drawto,
2909 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2910 VX + VXSIZE - i, VY + j);
2911 SetClipOrigin(bitmap, gc,
2912 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2913 BlitBitmapMasked(bitmap, drawto,
2914 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2917 BlitBitmapMasked(bitmap, drawto,
2918 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2919 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2920 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2921 BlitBitmapMasked(bitmap, drawto,
2922 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2924 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2927 redraw_mask |= REDRAW_DOOR_2;
2928 door_2_done = (a == VXSIZE);
2931 if (!(door_state & DOOR_NO_DELAY))
2935 if (game_status == GAME_MODE_MAIN)
2938 WaitUntilDelayReached(&door_delay, door_delay_value);
2943 if (door_state & DOOR_ACTION_1)
2944 door1 = door_state & DOOR_ACTION_1;
2945 if (door_state & DOOR_ACTION_2)
2946 door2 = door_state & DOOR_ACTION_2;
2948 return (door1 | door2);
2951 void DrawSpecialEditorDoor()
2953 /* draw bigger toolbox window */
2954 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2955 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2957 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2958 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2961 redraw_mask |= REDRAW_ALL;
2964 void UndrawSpecialEditorDoor()
2966 /* draw normal tape recorder window */
2967 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2968 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2971 redraw_mask |= REDRAW_ALL;
2975 /* ---------- new tool button stuff ---------------------------------------- */
2977 /* graphic position values for tool buttons */
2978 #define TOOL_BUTTON_YES_XPOS 2
2979 #define TOOL_BUTTON_YES_YPOS 250
2980 #define TOOL_BUTTON_YES_GFX_YPOS 0
2981 #define TOOL_BUTTON_YES_XSIZE 46
2982 #define TOOL_BUTTON_YES_YSIZE 28
2983 #define TOOL_BUTTON_NO_XPOS 52
2984 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2985 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2986 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2987 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2988 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2989 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2990 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2991 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2992 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2993 #define TOOL_BUTTON_PLAYER_XSIZE 30
2994 #define TOOL_BUTTON_PLAYER_YSIZE 30
2995 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2996 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2997 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2998 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2999 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3000 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3001 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3002 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3003 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3004 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3005 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3006 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3007 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3008 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3009 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3010 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3011 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3012 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3013 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3014 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3023 } toolbutton_info[NUM_TOOL_BUTTONS] =
3026 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3027 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3028 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3033 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3034 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3035 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3040 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3041 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3042 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3043 TOOL_CTRL_ID_CONFIRM,
3047 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3048 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3049 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3050 TOOL_CTRL_ID_PLAYER_1,
3054 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3055 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3056 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3057 TOOL_CTRL_ID_PLAYER_2,
3061 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3062 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3063 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3064 TOOL_CTRL_ID_PLAYER_3,
3068 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3069 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3070 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3071 TOOL_CTRL_ID_PLAYER_4,
3076 void CreateToolButtons()
3080 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3082 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3083 Bitmap *deco_bitmap = None;
3084 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3085 struct GadgetInfo *gi;
3086 unsigned long event_mask;
3087 int gd_xoffset, gd_yoffset;
3088 int gd_x1, gd_x2, gd_y;
3091 event_mask = GD_EVENT_RELEASED;
3093 gd_xoffset = toolbutton_info[i].xpos;
3094 gd_yoffset = toolbutton_info[i].ypos;
3095 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3096 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3097 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3099 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3101 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3103 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3104 &deco_bitmap, &deco_x, &deco_y);
3105 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3106 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3109 gi = CreateGadget(GDI_CUSTOM_ID, id,
3110 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3111 GDI_X, DX + toolbutton_info[i].x,
3112 GDI_Y, DY + toolbutton_info[i].y,
3113 GDI_WIDTH, toolbutton_info[i].width,
3114 GDI_HEIGHT, toolbutton_info[i].height,
3115 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3116 GDI_STATE, GD_BUTTON_UNPRESSED,
3117 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3118 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3119 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3120 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3121 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3122 GDI_DECORATION_SHIFTING, 1, 1,
3123 GDI_EVENT_MASK, event_mask,
3124 GDI_CALLBACK_ACTION, HandleToolButtons,
3128 Error(ERR_EXIT, "cannot create gadget");
3130 tool_gadget[id] = gi;
3134 void FreeToolButtons()
3138 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3139 FreeGadget(tool_gadget[i]);
3142 static void UnmapToolButtons()
3146 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3147 UnmapGadget(tool_gadget[i]);
3150 static void HandleToolButtons(struct GadgetInfo *gi)
3152 request_gadget_id = gi->custom_id;
3155 static struct Mapping_EM_to_RND_object
3158 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3159 boolean is_backside; /* backside of moving element */
3165 em_object_mapping_list[] =
3168 Xblank, TRUE, FALSE,
3172 Yacid_splash_eB, FALSE, FALSE,
3173 EL_ACID_SPLASH_RIGHT, -1, -1
3176 Yacid_splash_wB, FALSE, FALSE,
3177 EL_ACID_SPLASH_LEFT, -1, -1
3180 #ifdef EM_ENGINE_BAD_ROLL
3182 Xstone_force_e, FALSE, FALSE,
3183 EL_ROCK, -1, MV_BIT_RIGHT
3186 Xstone_force_w, FALSE, FALSE,
3187 EL_ROCK, -1, MV_BIT_LEFT
3190 Xnut_force_e, FALSE, FALSE,
3191 EL_NUT, -1, MV_BIT_RIGHT
3194 Xnut_force_w, FALSE, FALSE,
3195 EL_NUT, -1, MV_BIT_LEFT
3198 Xspring_force_e, FALSE, FALSE,
3199 EL_SPRING, -1, MV_BIT_RIGHT
3202 Xspring_force_w, FALSE, FALSE,
3203 EL_SPRING, -1, MV_BIT_LEFT
3206 Xemerald_force_e, FALSE, FALSE,
3207 EL_EMERALD, -1, MV_BIT_RIGHT
3210 Xemerald_force_w, FALSE, FALSE,
3211 EL_EMERALD, -1, MV_BIT_LEFT
3214 Xdiamond_force_e, FALSE, FALSE,
3215 EL_DIAMOND, -1, MV_BIT_RIGHT
3218 Xdiamond_force_w, FALSE, FALSE,
3219 EL_DIAMOND, -1, MV_BIT_LEFT
3222 Xbomb_force_e, FALSE, FALSE,
3223 EL_BOMB, -1, MV_BIT_RIGHT
3226 Xbomb_force_w, FALSE, FALSE,
3227 EL_BOMB, -1, MV_BIT_LEFT
3229 #endif /* EM_ENGINE_BAD_ROLL */
3232 Xstone, TRUE, FALSE,
3236 Xstone_pause, FALSE, FALSE,
3240 Xstone_fall, FALSE, FALSE,
3244 Ystone_s, FALSE, FALSE,
3245 EL_ROCK, ACTION_FALLING, -1
3248 Ystone_sB, FALSE, TRUE,
3249 EL_ROCK, ACTION_FALLING, -1
3252 Ystone_e, FALSE, FALSE,
3253 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3256 Ystone_eB, FALSE, TRUE,
3257 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3260 Ystone_w, FALSE, FALSE,
3261 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3264 Ystone_wB, FALSE, TRUE,
3265 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3272 Xnut_pause, FALSE, FALSE,
3276 Xnut_fall, FALSE, FALSE,
3280 Ynut_s, FALSE, FALSE,
3281 EL_NUT, ACTION_FALLING, -1
3284 Ynut_sB, FALSE, TRUE,
3285 EL_NUT, ACTION_FALLING, -1
3288 Ynut_e, FALSE, FALSE,
3289 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3292 Ynut_eB, FALSE, TRUE,
3293 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3296 Ynut_w, FALSE, FALSE,
3297 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3300 Ynut_wB, FALSE, TRUE,
3301 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3304 Xbug_n, TRUE, FALSE,
3308 Xbug_e, TRUE, FALSE,
3309 EL_BUG_RIGHT, -1, -1
3312 Xbug_s, TRUE, FALSE,
3316 Xbug_w, TRUE, FALSE,
3320 Xbug_gon, FALSE, FALSE,
3324 Xbug_goe, FALSE, FALSE,
3325 EL_BUG_RIGHT, -1, -1
3328 Xbug_gos, FALSE, FALSE,
3332 Xbug_gow, FALSE, FALSE,
3336 Ybug_n, FALSE, FALSE,
3337 EL_BUG, ACTION_MOVING, MV_BIT_UP
3340 Ybug_nB, FALSE, TRUE,
3341 EL_BUG, ACTION_MOVING, MV_BIT_UP
3344 Ybug_e, FALSE, FALSE,
3345 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3348 Ybug_eB, FALSE, TRUE,
3349 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3352 Ybug_s, FALSE, FALSE,
3353 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3356 Ybug_sB, FALSE, TRUE,
3357 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3360 Ybug_w, FALSE, FALSE,
3361 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3364 Ybug_wB, FALSE, TRUE,
3365 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3368 Ybug_w_n, FALSE, FALSE,
3369 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3372 Ybug_n_e, FALSE, FALSE,
3373 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3376 Ybug_e_s, FALSE, FALSE,
3377 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3380 Ybug_s_w, FALSE, FALSE,
3381 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3384 Ybug_e_n, FALSE, FALSE,
3385 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3388 Ybug_s_e, FALSE, FALSE,
3389 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3392 Ybug_w_s, FALSE, FALSE,
3393 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3396 Ybug_n_w, FALSE, FALSE,
3397 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3400 Ybug_stone, FALSE, FALSE,
3401 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3404 Ybug_spring, FALSE, FALSE,
3405 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3408 Xtank_n, TRUE, FALSE,
3409 EL_SPACESHIP_UP, -1, -1
3412 Xtank_e, TRUE, FALSE,
3413 EL_SPACESHIP_RIGHT, -1, -1
3416 Xtank_s, TRUE, FALSE,
3417 EL_SPACESHIP_DOWN, -1, -1
3420 Xtank_w, TRUE, FALSE,
3421 EL_SPACESHIP_LEFT, -1, -1
3424 Xtank_gon, FALSE, FALSE,
3425 EL_SPACESHIP_UP, -1, -1
3428 Xtank_goe, FALSE, FALSE,
3429 EL_SPACESHIP_RIGHT, -1, -1
3432 Xtank_gos, FALSE, FALSE,
3433 EL_SPACESHIP_DOWN, -1, -1
3436 Xtank_gow, FALSE, FALSE,
3437 EL_SPACESHIP_LEFT, -1, -1
3440 Ytank_n, FALSE, FALSE,
3441 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3444 Ytank_nB, FALSE, TRUE,
3445 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3448 Ytank_e, FALSE, FALSE,
3449 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3452 Ytank_eB, FALSE, TRUE,
3453 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3456 Ytank_s, FALSE, FALSE,
3457 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3460 Ytank_sB, FALSE, TRUE,
3461 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3464 Ytank_w, FALSE, FALSE,
3465 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3468 Ytank_wB, FALSE, TRUE,
3469 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3472 Ytank_w_n, FALSE, FALSE,
3473 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3476 Ytank_n_e, FALSE, FALSE,
3477 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3480 Ytank_e_s, FALSE, FALSE,
3481 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3484 Ytank_s_w, FALSE, FALSE,
3485 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3488 Ytank_e_n, FALSE, FALSE,
3489 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3492 Ytank_s_e, FALSE, FALSE,
3493 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3496 Ytank_w_s, FALSE, FALSE,
3497 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3500 Ytank_n_w, FALSE, FALSE,
3501 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3504 Ytank_stone, FALSE, FALSE,
3505 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3508 Ytank_spring, FALSE, FALSE,
3509 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3512 Xandroid, TRUE, FALSE,
3513 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3516 Xandroid_1_n, FALSE, FALSE,
3517 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3520 Xandroid_2_n, FALSE, FALSE,
3521 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3524 Xandroid_1_e, FALSE, FALSE,
3525 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3528 Xandroid_2_e, FALSE, FALSE,
3529 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3532 Xandroid_1_w, FALSE, FALSE,
3533 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3536 Xandroid_2_w, FALSE, FALSE,
3537 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3540 Xandroid_1_s, FALSE, FALSE,
3541 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3544 Xandroid_2_s, FALSE, FALSE,
3545 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3548 Yandroid_n, FALSE, FALSE,
3549 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3552 Yandroid_nB, FALSE, TRUE,
3553 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3556 Yandroid_ne, FALSE, FALSE,
3557 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3560 Yandroid_neB, FALSE, TRUE,
3561 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3564 Yandroid_e, FALSE, FALSE,
3565 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3568 Yandroid_eB, FALSE, TRUE,
3569 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3572 Yandroid_se, FALSE, FALSE,
3573 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3576 Yandroid_seB, FALSE, TRUE,
3577 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3580 Yandroid_s, FALSE, FALSE,
3581 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3584 Yandroid_sB, FALSE, TRUE,
3585 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3588 Yandroid_sw, FALSE, FALSE,
3589 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3592 Yandroid_swB, FALSE, TRUE,
3593 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3596 Yandroid_w, FALSE, FALSE,
3597 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3600 Yandroid_wB, FALSE, TRUE,
3601 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3604 Yandroid_nw, FALSE, FALSE,
3605 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3608 Yandroid_nwB, FALSE, TRUE,
3609 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3612 Xspring, TRUE, FALSE,
3616 Xspring_pause, FALSE, FALSE,
3620 Xspring_e, FALSE, FALSE,
3624 Xspring_w, FALSE, FALSE,
3628 Xspring_fall, FALSE, FALSE,
3632 Yspring_s, FALSE, FALSE,
3633 EL_SPRING, ACTION_FALLING, -1
3636 Yspring_sB, FALSE, TRUE,
3637 EL_SPRING, ACTION_FALLING, -1
3640 Yspring_e, FALSE, FALSE,
3641 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3644 Yspring_eB, FALSE, TRUE,
3645 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3648 Yspring_w, FALSE, FALSE,
3649 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3652 Yspring_wB, FALSE, TRUE,
3653 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3656 Yspring_kill_e, FALSE, FALSE,
3657 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3660 Yspring_kill_eB, FALSE, TRUE,
3661 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3664 Yspring_kill_w, FALSE, FALSE,
3665 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3668 Yspring_kill_wB, FALSE, TRUE,
3669 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3672 Xeater_n, TRUE, FALSE,
3673 EL_YAMYAM_UP, -1, -1
3676 Xeater_e, TRUE, FALSE,
3677 EL_YAMYAM_RIGHT, -1, -1
3680 Xeater_w, TRUE, FALSE,
3681 EL_YAMYAM_LEFT, -1, -1
3684 Xeater_s, TRUE, FALSE,
3685 EL_YAMYAM_DOWN, -1, -1
3688 Yeater_n, FALSE, FALSE,
3689 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3692 Yeater_nB, FALSE, TRUE,
3693 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3696 Yeater_e, FALSE, FALSE,
3697 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3700 Yeater_eB, FALSE, TRUE,
3701 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3704 Yeater_s, FALSE, FALSE,
3705 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3708 Yeater_sB, FALSE, TRUE,
3709 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3712 Yeater_w, FALSE, FALSE,
3713 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3716 Yeater_wB, FALSE, TRUE,
3717 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3720 Yeater_stone, FALSE, FALSE,
3721 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3724 Yeater_spring, FALSE, FALSE,
3725 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3728 Xalien, TRUE, FALSE,
3732 Xalien_pause, FALSE, FALSE,
3736 Yalien_n, FALSE, FALSE,
3737 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3740 Yalien_nB, FALSE, TRUE,
3741 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3744 Yalien_e, FALSE, FALSE,
3745 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3748 Yalien_eB, FALSE, TRUE,
3749 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3752 Yalien_s, FALSE, FALSE,
3753 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3756 Yalien_sB, FALSE, TRUE,
3757 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3760 Yalien_w, FALSE, FALSE,
3761 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3764 Yalien_wB, FALSE, TRUE,
3765 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3768 Yalien_stone, FALSE, FALSE,
3769 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3772 Yalien_spring, FALSE, FALSE,
3773 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3776 Xemerald, TRUE, FALSE,
3780 Xemerald_pause, FALSE, FALSE,
3784 Xemerald_fall, FALSE, FALSE,
3788 Xemerald_shine, FALSE, FALSE,
3789 EL_EMERALD, ACTION_TWINKLING, -1
3792 Yemerald_s, FALSE, FALSE,
3793 EL_EMERALD, ACTION_FALLING, -1
3796 Yemerald_sB, FALSE, TRUE,
3797 EL_EMERALD, ACTION_FALLING, -1
3800 Yemerald_e, FALSE, FALSE,
3801 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3804 Yemerald_eB, FALSE, TRUE,
3805 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3808 Yemerald_w, FALSE, FALSE,
3809 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3812 Yemerald_wB, FALSE, TRUE,
3813 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3816 Yemerald_eat, FALSE, FALSE,
3817 EL_EMERALD, ACTION_COLLECTING, -1
3820 Yemerald_stone, FALSE, FALSE,
3821 EL_NUT, ACTION_BREAKING, -1
3824 Xdiamond, TRUE, FALSE,
3828 Xdiamond_pause, FALSE, FALSE,
3832 Xdiamond_fall, FALSE, FALSE,
3836 Xdiamond_shine, FALSE, FALSE,
3837 EL_DIAMOND, ACTION_TWINKLING, -1
3840 Ydiamond_s, FALSE, FALSE,
3841 EL_DIAMOND, ACTION_FALLING, -1
3844 Ydiamond_sB, FALSE, TRUE,
3845 EL_DIAMOND, ACTION_FALLING, -1
3848 Ydiamond_e, FALSE, FALSE,
3849 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3852 Ydiamond_eB, FALSE, TRUE,
3853 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3856 Ydiamond_w, FALSE, FALSE,
3857 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3860 Ydiamond_wB, FALSE, TRUE,
3861 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3864 Ydiamond_eat, FALSE, FALSE,
3865 EL_DIAMOND, ACTION_COLLECTING, -1
3868 Ydiamond_stone, FALSE, FALSE,
3869 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
3872 Xdrip_fall, TRUE, FALSE,
3873 EL_AMOEBA_DROP, -1, -1
3876 Xdrip_stretch, FALSE, FALSE,
3877 EL_AMOEBA_DROP, ACTION_FALLING, -1
3880 Xdrip_stretchB, FALSE, TRUE,
3881 EL_AMOEBA_DROP, ACTION_FALLING, -1
3884 Xdrip_eat, FALSE, FALSE,
3885 EL_AMOEBA_DROP, ACTION_GROWING, -1
3888 Ydrip_s1, FALSE, FALSE,
3889 EL_AMOEBA_DROP, ACTION_FALLING, -1
3892 Ydrip_s1B, FALSE, TRUE,
3893 EL_AMOEBA_DROP, ACTION_FALLING, -1
3896 Ydrip_s2, FALSE, FALSE,
3897 EL_AMOEBA_DROP, ACTION_FALLING, -1
3900 Ydrip_s2B, FALSE, TRUE,
3901 EL_AMOEBA_DROP, ACTION_FALLING, -1
3908 Xbomb_pause, FALSE, FALSE,
3912 Xbomb_fall, FALSE, FALSE,
3916 Ybomb_s, FALSE, FALSE,
3917 EL_BOMB, ACTION_FALLING, -1
3920 Ybomb_sB, FALSE, TRUE,
3921 EL_BOMB, ACTION_FALLING, -1
3924 Ybomb_e, FALSE, FALSE,
3925 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3928 Ybomb_eB, FALSE, TRUE,
3929 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3932 Ybomb_w, FALSE, FALSE,
3933 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3936 Ybomb_wB, FALSE, TRUE,
3937 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3940 Ybomb_eat, FALSE, FALSE,
3941 EL_BOMB, ACTION_ACTIVATING, -1
3944 Xballoon, TRUE, FALSE,
3948 Yballoon_n, FALSE, FALSE,
3949 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3952 Yballoon_nB, FALSE, TRUE,
3953 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3956 Yballoon_e, FALSE, FALSE,
3957 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3960 Yballoon_eB, FALSE, TRUE,
3961 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3964 Yballoon_s, FALSE, FALSE,
3965 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3968 Yballoon_sB, FALSE, TRUE,
3969 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3972 Yballoon_w, FALSE, FALSE,
3973 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3976 Yballoon_wB, FALSE, TRUE,
3977 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3980 Xgrass, TRUE, FALSE,
3981 EL_EMC_GRASS, -1, -1
3984 Ygrass_nB, FALSE, FALSE,
3985 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
3988 Ygrass_eB, FALSE, FALSE,
3989 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
3992 Ygrass_sB, FALSE, FALSE,
3993 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
3996 Ygrass_wB, FALSE, FALSE,
3997 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4004 Ydirt_nB, FALSE, FALSE,
4005 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4008 Ydirt_eB, FALSE, FALSE,
4009 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4012 Ydirt_sB, FALSE, FALSE,
4013 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4016 Ydirt_wB, FALSE, FALSE,
4017 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4020 Xacid_ne, TRUE, FALSE,
4021 EL_ACID_POOL_TOPRIGHT, -1, -1
4024 Xacid_se, TRUE, FALSE,
4025 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4028 Xacid_s, TRUE, FALSE,
4029 EL_ACID_POOL_BOTTOM, -1, -1
4032 Xacid_sw, TRUE, FALSE,
4033 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4036 Xacid_nw, TRUE, FALSE,
4037 EL_ACID_POOL_TOPLEFT, -1, -1
4040 Xacid_1, TRUE, FALSE,
4044 Xacid_2, FALSE, FALSE,
4048 Xacid_3, FALSE, FALSE,
4052 Xacid_4, FALSE, FALSE,
4056 Xacid_5, FALSE, FALSE,
4060 Xacid_6, FALSE, FALSE,
4064 Xacid_7, FALSE, FALSE,
4068 Xacid_8, FALSE, FALSE,
4072 Xball_1, TRUE, FALSE,
4073 EL_EMC_MAGIC_BALL, -1, -1
4076 Xball_1B, FALSE, FALSE,
4077 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4080 Xball_2, FALSE, FALSE,
4081 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4084 Xball_2B, FALSE, FALSE,
4085 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4088 Yball_eat, FALSE, FALSE,
4089 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4092 Ykey_1_eat, FALSE, FALSE,
4093 EL_EM_KEY_1, ACTION_COLLECTING, -1
4096 Ykey_2_eat, FALSE, FALSE,
4097 EL_EM_KEY_2, ACTION_COLLECTING, -1
4100 Ykey_3_eat, FALSE, FALSE,
4101 EL_EM_KEY_3, ACTION_COLLECTING, -1
4104 Ykey_4_eat, FALSE, FALSE,
4105 EL_EM_KEY_4, ACTION_COLLECTING, -1
4108 Ykey_5_eat, FALSE, FALSE,
4109 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4112 Ykey_6_eat, FALSE, FALSE,
4113 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4116 Ykey_7_eat, FALSE, FALSE,
4117 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4120 Ykey_8_eat, FALSE, FALSE,
4121 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4124 Ylenses_eat, FALSE, FALSE,
4125 EL_EMC_LENSES, ACTION_COLLECTING, -1
4128 Ymagnify_eat, FALSE, FALSE,
4129 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4132 Ygrass_eat, FALSE, FALSE,
4133 EL_EMC_GRASS, ACTION_SNAPPING, -1
4136 Ydirt_eat, FALSE, FALSE,
4137 EL_SAND, ACTION_SNAPPING, -1
4140 Xgrow_ns, TRUE, FALSE,
4141 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4144 Ygrow_ns_eat, FALSE, FALSE,
4145 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4148 Xgrow_ew, TRUE, FALSE,
4149 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4152 Ygrow_ew_eat, FALSE, FALSE,
4153 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4156 Xwonderwall, TRUE, FALSE,
4157 EL_MAGIC_WALL, -1, -1
4160 XwonderwallB, FALSE, FALSE,
4161 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4164 Xamoeba_1, TRUE, FALSE,
4165 EL_AMOEBA_DRY, ACTION_OTHER, -1
4168 Xamoeba_2, FALSE, FALSE,
4169 EL_AMOEBA_DRY, ACTION_OTHER, -1
4172 Xamoeba_3, FALSE, FALSE,
4173 EL_AMOEBA_DRY, ACTION_OTHER, -1
4176 Xamoeba_4, FALSE, FALSE,
4177 EL_AMOEBA_DRY, ACTION_OTHER, -1
4180 Xamoeba_5, TRUE, FALSE,
4181 EL_AMOEBA_WET, ACTION_OTHER, -1
4184 Xamoeba_6, FALSE, FALSE,
4185 EL_AMOEBA_WET, ACTION_OTHER, -1
4188 Xamoeba_7, FALSE, FALSE,
4189 EL_AMOEBA_WET, ACTION_OTHER, -1
4192 Xamoeba_8, FALSE, FALSE,
4193 EL_AMOEBA_WET, ACTION_OTHER, -1
4196 Xdoor_1, TRUE, FALSE,
4197 EL_EM_GATE_1, -1, -1
4200 Xdoor_2, TRUE, FALSE,
4201 EL_EM_GATE_2, -1, -1
4204 Xdoor_3, TRUE, FALSE,
4205 EL_EM_GATE_3, -1, -1
4208 Xdoor_4, TRUE, FALSE,
4209 EL_EM_GATE_4, -1, -1
4212 Xdoor_5, TRUE, FALSE,
4213 EL_EMC_GATE_5, -1, -1
4216 Xdoor_6, TRUE, FALSE,
4217 EL_EMC_GATE_6, -1, -1
4220 Xdoor_7, TRUE, FALSE,
4221 EL_EMC_GATE_7, -1, -1
4224 Xdoor_8, TRUE, FALSE,
4225 EL_EMC_GATE_8, -1, -1
4228 Xkey_1, TRUE, FALSE,
4232 Xkey_2, TRUE, FALSE,
4236 Xkey_3, TRUE, FALSE,
4240 Xkey_4, TRUE, FALSE,
4244 Xkey_5, TRUE, FALSE,
4245 EL_EMC_KEY_5, -1, -1
4248 Xkey_6, TRUE, FALSE,
4249 EL_EMC_KEY_6, -1, -1
4252 Xkey_7, TRUE, FALSE,
4253 EL_EMC_KEY_7, -1, -1
4256 Xkey_8, TRUE, FALSE,
4257 EL_EMC_KEY_8, -1, -1
4260 Xwind_n, TRUE, FALSE,
4261 EL_BALLOON_SWITCH_UP, -1, -1
4264 Xwind_e, TRUE, FALSE,
4265 EL_BALLOON_SWITCH_RIGHT, -1, -1
4268 Xwind_s, TRUE, FALSE,
4269 EL_BALLOON_SWITCH_DOWN, -1, -1
4272 Xwind_w, TRUE, FALSE,
4273 EL_BALLOON_SWITCH_LEFT, -1, -1
4276 Xwind_nesw, TRUE, FALSE,
4277 EL_BALLOON_SWITCH_ANY, -1, -1
4280 Xwind_stop, TRUE, FALSE,
4281 EL_BALLOON_SWITCH_NONE, -1, -1
4285 EL_EXIT_CLOSED, -1, -1
4288 Xexit_1, TRUE, FALSE,
4289 EL_EXIT_OPEN, -1, -1
4292 Xexit_2, FALSE, FALSE,
4293 EL_EXIT_OPEN, -1, -1
4296 Xexit_3, FALSE, FALSE,
4297 EL_EXIT_OPEN, -1, -1
4300 Xdynamite, TRUE, FALSE,
4301 EL_EM_DYNAMITE, -1, -1
4304 Ydynamite_eat, FALSE, FALSE,
4305 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4308 Xdynamite_1, TRUE, FALSE,
4309 EL_EM_DYNAMITE_ACTIVE, -1, -1
4312 Xdynamite_2, FALSE, FALSE,
4313 EL_EM_DYNAMITE_ACTIVE, -1, -1
4316 Xdynamite_3, FALSE, FALSE,
4317 EL_EM_DYNAMITE_ACTIVE, -1, -1
4320 Xdynamite_4, FALSE, FALSE,
4321 EL_EM_DYNAMITE_ACTIVE, -1, -1
4324 Xbumper, TRUE, FALSE,
4325 EL_EMC_SPRING_BUMPER, -1, -1
4328 XbumperB, FALSE, FALSE,
4329 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4332 Xwheel, TRUE, FALSE,
4333 EL_ROBOT_WHEEL, -1, -1
4336 XwheelB, FALSE, FALSE,
4337 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4340 Xswitch, TRUE, FALSE,
4341 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4344 XswitchB, FALSE, FALSE,
4345 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4349 EL_QUICKSAND_EMPTY, -1, -1
4352 Xsand_stone, TRUE, FALSE,
4353 EL_QUICKSAND_FULL, -1, -1
4356 Xsand_stonein_1, FALSE, TRUE,
4357 EL_ROCK, ACTION_FILLING, -1
4360 Xsand_stonein_2, FALSE, TRUE,
4361 EL_ROCK, ACTION_FILLING, -1
4364 Xsand_stonein_3, FALSE, TRUE,
4365 EL_ROCK, ACTION_FILLING, -1
4368 Xsand_stonein_4, FALSE, TRUE,
4369 EL_ROCK, ACTION_FILLING, -1
4372 Xsand_stonesand_1, FALSE, FALSE,
4373 EL_QUICKSAND_FULL, -1, -1
4376 Xsand_stonesand_2, FALSE, FALSE,
4377 EL_QUICKSAND_FULL, -1, -1
4380 Xsand_stonesand_3, FALSE, FALSE,
4381 EL_QUICKSAND_FULL, -1, -1
4384 Xsand_stonesand_4, FALSE, FALSE,
4385 EL_QUICKSAND_FULL, -1, -1
4388 Xsand_stoneout_1, FALSE, FALSE,
4389 EL_ROCK, ACTION_EMPTYING, -1
4392 Xsand_stoneout_2, FALSE, FALSE,
4393 EL_ROCK, ACTION_EMPTYING, -1
4396 Xsand_sandstone_1, FALSE, FALSE,
4397 EL_QUICKSAND_FULL, -1, -1
4400 Xsand_sandstone_2, FALSE, FALSE,
4401 EL_QUICKSAND_FULL, -1, -1
4404 Xsand_sandstone_3, FALSE, FALSE,
4405 EL_QUICKSAND_FULL, -1, -1
4408 Xsand_sandstone_4, FALSE, FALSE,
4409 EL_QUICKSAND_FULL, -1, -1
4412 Xplant, TRUE, FALSE,
4413 EL_EMC_PLANT, -1, -1
4416 Yplant, FALSE, FALSE,
4417 EL_EMC_PLANT, -1, -1
4420 Xlenses, TRUE, FALSE,
4421 EL_EMC_LENSES, -1, -1
4424 Xmagnify, TRUE, FALSE,
4425 EL_EMC_MAGNIFIER, -1, -1
4428 Xdripper, TRUE, FALSE,
4429 EL_EMC_DRIPPER, -1, -1
4432 XdripperB, FALSE, FALSE,
4433 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4436 Xfake_blank, TRUE, FALSE,
4437 EL_INVISIBLE_WALL, -1, -1
4440 Xfake_blankB, FALSE, FALSE,
4441 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4444 Xfake_grass, TRUE, FALSE,
4445 EL_EMC_FAKE_GRASS, -1, -1
4448 Xfake_grassB, FALSE, FALSE,
4449 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4452 Xfake_door_1, TRUE, FALSE,
4453 EL_EM_GATE_1_GRAY, -1, -1
4456 Xfake_door_2, TRUE, FALSE,
4457 EL_EM_GATE_2_GRAY, -1, -1
4460 Xfake_door_3, TRUE, FALSE,
4461 EL_EM_GATE_3_GRAY, -1, -1
4464 Xfake_door_4, TRUE, FALSE,
4465 EL_EM_GATE_4_GRAY, -1, -1
4468 Xfake_door_5, TRUE, FALSE,
4469 EL_EMC_GATE_5_GRAY, -1, -1
4472 Xfake_door_6, TRUE, FALSE,
4473 EL_EMC_GATE_6_GRAY, -1, -1
4476 Xfake_door_7, TRUE, FALSE,
4477 EL_EMC_GATE_7_GRAY, -1, -1
4480 Xfake_door_8, TRUE, FALSE,
4481 EL_EMC_GATE_8_GRAY, -1, -1
4484 Xfake_acid_1, TRUE, FALSE,
4485 EL_EMC_FAKE_ACID, -1, -1
4488 Xfake_acid_2, FALSE, FALSE,
4489 EL_EMC_FAKE_ACID, -1, -1
4492 Xfake_acid_3, FALSE, FALSE,
4493 EL_EMC_FAKE_ACID, -1, -1
4496 Xfake_acid_4, FALSE, FALSE,
4497 EL_EMC_FAKE_ACID, -1, -1
4500 Xfake_acid_5, FALSE, FALSE,
4501 EL_EMC_FAKE_ACID, -1, -1
4504 Xfake_acid_6, FALSE, FALSE,
4505 EL_EMC_FAKE_ACID, -1, -1
4508 Xfake_acid_7, FALSE, FALSE,
4509 EL_EMC_FAKE_ACID, -1, -1
4512 Xfake_acid_8, FALSE, FALSE,
4513 EL_EMC_FAKE_ACID, -1, -1
4516 Xsteel_1, TRUE, FALSE,
4517 EL_STEELWALL, -1, -1
4520 Xsteel_2, TRUE, FALSE,
4521 EL_EMC_STEELWALL_2, -1, -1
4524 Xsteel_3, TRUE, FALSE,
4525 EL_EMC_STEELWALL_3, -1, -1
4528 Xsteel_4, TRUE, FALSE,
4529 EL_EMC_STEELWALL_4, -1, -1
4532 Xwall_1, TRUE, FALSE,
4536 Xwall_2, TRUE, FALSE,
4537 EL_EMC_WALL_14, -1, -1
4540 Xwall_3, TRUE, FALSE,
4541 EL_EMC_WALL_15, -1, -1
4544 Xwall_4, TRUE, FALSE,
4545 EL_EMC_WALL_16, -1, -1
4548 Xround_wall_1, TRUE, FALSE,
4549 EL_WALL_SLIPPERY, -1, -1
4552 Xround_wall_2, TRUE, FALSE,
4553 EL_EMC_WALL_SLIPPERY_2, -1, -1
4556 Xround_wall_3, TRUE, FALSE,
4557 EL_EMC_WALL_SLIPPERY_3, -1, -1
4560 Xround_wall_4, TRUE, FALSE,
4561 EL_EMC_WALL_SLIPPERY_4, -1, -1
4564 Xdecor_1, TRUE, FALSE,
4565 EL_EMC_WALL_8, -1, -1
4568 Xdecor_2, TRUE, FALSE,
4569 EL_EMC_WALL_6, -1, -1
4572 Xdecor_3, TRUE, FALSE,
4573 EL_EMC_WALL_4, -1, -1
4576 Xdecor_4, TRUE, FALSE,
4577 EL_EMC_WALL_7, -1, -1
4580 Xdecor_5, TRUE, FALSE,
4581 EL_EMC_WALL_5, -1, -1
4584 Xdecor_6, TRUE, FALSE,
4585 EL_EMC_WALL_9, -1, -1
4588 Xdecor_7, TRUE, FALSE,
4589 EL_EMC_WALL_10, -1, -1
4592 Xdecor_8, TRUE, FALSE,
4593 EL_EMC_WALL_1, -1, -1
4596 Xdecor_9, TRUE, FALSE,
4597 EL_EMC_WALL_2, -1, -1
4600 Xdecor_10, TRUE, FALSE,
4601 EL_EMC_WALL_3, -1, -1
4604 Xdecor_11, TRUE, FALSE,
4605 EL_EMC_WALL_11, -1, -1
4608 Xdecor_12, TRUE, FALSE,
4609 EL_EMC_WALL_12, -1, -1
4612 Xalpha_0, TRUE, FALSE,
4613 EL_CHAR('0'), -1, -1
4616 Xalpha_1, TRUE, FALSE,
4617 EL_CHAR('1'), -1, -1
4620 Xalpha_2, TRUE, FALSE,
4621 EL_CHAR('2'), -1, -1
4624 Xalpha_3, TRUE, FALSE,
4625 EL_CHAR('3'), -1, -1
4628 Xalpha_4, TRUE, FALSE,
4629 EL_CHAR('4'), -1, -1
4632 Xalpha_5, TRUE, FALSE,
4633 EL_CHAR('5'), -1, -1
4636 Xalpha_6, TRUE, FALSE,
4637 EL_CHAR('6'), -1, -1
4640 Xalpha_7, TRUE, FALSE,
4641 EL_CHAR('7'), -1, -1
4644 Xalpha_8, TRUE, FALSE,
4645 EL_CHAR('8'), -1, -1
4648 Xalpha_9, TRUE, FALSE,
4649 EL_CHAR('9'), -1, -1
4652 Xalpha_excla, TRUE, FALSE,
4653 EL_CHAR('!'), -1, -1
4656 Xalpha_quote, TRUE, FALSE,
4657 EL_CHAR('"'), -1, -1
4660 Xalpha_comma, TRUE, FALSE,
4661 EL_CHAR(','), -1, -1
4664 Xalpha_minus, TRUE, FALSE,
4665 EL_CHAR('-'), -1, -1
4668 Xalpha_perio, TRUE, FALSE,
4669 EL_CHAR('.'), -1, -1
4672 Xalpha_colon, TRUE, FALSE,
4673 EL_CHAR(':'), -1, -1
4676 Xalpha_quest, TRUE, FALSE,
4677 EL_CHAR('?'), -1, -1
4680 Xalpha_a, TRUE, FALSE,
4681 EL_CHAR('A'), -1, -1
4684 Xalpha_b, TRUE, FALSE,
4685 EL_CHAR('B'), -1, -1
4688 Xalpha_c, TRUE, FALSE,
4689 EL_CHAR('C'), -1, -1
4692 Xalpha_d, TRUE, FALSE,
4693 EL_CHAR('D'), -1, -1
4696 Xalpha_e, TRUE, FALSE,
4697 EL_CHAR('E'), -1, -1
4700 Xalpha_f, TRUE, FALSE,
4701 EL_CHAR('F'), -1, -1
4704 Xalpha_g, TRUE, FALSE,
4705 EL_CHAR('G'), -1, -1
4708 Xalpha_h, TRUE, FALSE,
4709 EL_CHAR('H'), -1, -1
4712 Xalpha_i, TRUE, FALSE,
4713 EL_CHAR('I'), -1, -1
4716 Xalpha_j, TRUE, FALSE,
4717 EL_CHAR('J'), -1, -1
4720 Xalpha_k, TRUE, FALSE,
4721 EL_CHAR('K'), -1, -1
4724 Xalpha_l, TRUE, FALSE,
4725 EL_CHAR('L'), -1, -1
4728 Xalpha_m, TRUE, FALSE,
4729 EL_CHAR('M'), -1, -1
4732 Xalpha_n, TRUE, FALSE,
4733 EL_CHAR('N'), -1, -1
4736 Xalpha_o, TRUE, FALSE,
4737 EL_CHAR('O'), -1, -1
4740 Xalpha_p, TRUE, FALSE,
4741 EL_CHAR('P'), -1, -1
4744 Xalpha_q, TRUE, FALSE,
4745 EL_CHAR('Q'), -1, -1
4748 Xalpha_r, TRUE, FALSE,
4749 EL_CHAR('R'), -1, -1
4752 Xalpha_s, TRUE, FALSE,
4753 EL_CHAR('S'), -1, -1
4756 Xalpha_t, TRUE, FALSE,
4757 EL_CHAR('T'), -1, -1
4760 Xalpha_u, TRUE, FALSE,
4761 EL_CHAR('U'), -1, -1
4764 Xalpha_v, TRUE, FALSE,
4765 EL_CHAR('V'), -1, -1
4768 Xalpha_w, TRUE, FALSE,
4769 EL_CHAR('W'), -1, -1
4772 Xalpha_x, TRUE, FALSE,
4773 EL_CHAR('X'), -1, -1
4776 Xalpha_y, TRUE, FALSE,
4777 EL_CHAR('Y'), -1, -1
4780 Xalpha_z, TRUE, FALSE,
4781 EL_CHAR('Z'), -1, -1
4784 Xalpha_arrow_e, TRUE, FALSE,
4785 EL_CHAR('>'), -1, -1
4788 Xalpha_arrow_w, TRUE, FALSE,
4789 EL_CHAR('<'), -1, -1
4792 Xalpha_copyr, TRUE, FALSE,
4793 EL_CHAR('©'), -1, -1
4797 Xboom_bug, FALSE, FALSE,
4798 EL_BUG, ACTION_EXPLODING, -1
4801 Xboom_bomb, FALSE, FALSE,
4802 EL_BOMB, ACTION_EXPLODING, -1
4805 Xboom_android, FALSE, FALSE,
4806 EL_EMC_ANDROID, ACTION_OTHER, -1
4809 Xboom_1, FALSE, FALSE,
4810 EL_DEFAULT, ACTION_EXPLODING, -1
4813 Xboom_2, FALSE, FALSE,
4814 EL_DEFAULT, ACTION_EXPLODING, -1
4817 Znormal, FALSE, FALSE,
4821 Zdynamite, FALSE, FALSE,
4825 Zplayer, FALSE, FALSE,
4829 ZBORDER, FALSE, FALSE,
4839 static struct Mapping_EM_to_RND_player
4848 em_player_mapping_list[] =
4852 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
4856 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
4860 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
4864 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
4868 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
4872 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
4876 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
4880 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
4884 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
4888 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
4892 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
4896 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
4900 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
4904 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
4908 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
4912 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
4916 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
4920 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
4924 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
4928 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
4932 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
4936 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
4940 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
4944 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
4948 EL_PLAYER_1, ACTION_DEFAULT, -1,
4952 EL_PLAYER_2, ACTION_DEFAULT, -1,
4956 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
4960 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
4964 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
4968 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
4972 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
4976 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
4980 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
4984 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
4988 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
4992 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
4996 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5000 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5004 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5008 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5012 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5016 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5020 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5024 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5028 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5032 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5036 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5040 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5044 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5048 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5052 EL_PLAYER_3, ACTION_DEFAULT, -1,
5056 EL_PLAYER_4, ACTION_DEFAULT, -1,
5065 int map_element_RND_to_EM(int element_rnd)
5067 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5068 static boolean mapping_initialized = FALSE;
5070 if (!mapping_initialized)
5074 /* return "Xalpha_quest" for all undefined elements in mapping array */
5075 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5076 mapping_RND_to_EM[i] = Xalpha_quest;
5078 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5079 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5080 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5081 em_object_mapping_list[i].element_em;
5083 mapping_initialized = TRUE;
5086 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5087 return mapping_RND_to_EM[element_rnd];
5089 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5094 int map_element_EM_to_RND(int element_em)
5096 static unsigned short mapping_EM_to_RND[TILE_MAX];
5097 static boolean mapping_initialized = FALSE;
5099 if (!mapping_initialized)
5103 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5104 for (i = 0; i < TILE_MAX; i++)
5105 mapping_EM_to_RND[i] = EL_UNKNOWN;
5107 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5108 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5109 em_object_mapping_list[i].element_rnd;
5111 mapping_initialized = TRUE;
5114 if (element_em >= 0 && element_em < TILE_MAX)
5115 return mapping_EM_to_RND[element_em];
5117 Error(ERR_WARN, "invalid EM level element %d", element_em);
5122 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5124 struct LevelInfo_EM *level_em = level->native_em_level;
5125 struct LEVEL *lev = level_em->lev;
5128 for (i = 0; i < TILE_MAX; i++)
5129 lev->android_array[i] = Xblank;
5131 for (i = 0; i < level->num_android_clone_elements; i++)
5133 int element_rnd = level->android_clone_element[i];
5134 int element_em = map_element_RND_to_EM(element_rnd);
5136 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5137 if (em_object_mapping_list[j].element_rnd == element_rnd)
5138 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5142 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5144 struct LevelInfo_EM *level_em = level->native_em_level;
5145 struct LEVEL *lev = level_em->lev;
5148 level->num_android_clone_elements = 0;
5150 for (i = 0; i < TILE_MAX; i++)
5152 int element_em = lev->android_array[i];
5154 boolean element_found = FALSE;
5156 if (element_em == Xblank)
5159 element_rnd = map_element_EM_to_RND(element_em);
5161 for (j = 0; j < level->num_android_clone_elements; j++)
5162 if (level->android_clone_element[j] == element_rnd)
5163 element_found = TRUE;
5167 level->android_clone_element[level->num_android_clone_elements++] =
5170 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5175 if (level->num_android_clone_elements == 0)
5177 level->num_android_clone_elements = 1;
5178 level->android_clone_element[0] = EL_EMPTY;
5182 int map_direction_RND_to_EM(int direction)
5184 return (direction == MV_UP ? 0 :
5185 direction == MV_RIGHT ? 1 :
5186 direction == MV_DOWN ? 2 :
5187 direction == MV_LEFT ? 3 :
5191 int map_direction_EM_to_RND(int direction)
5193 return (direction == 0 ? MV_UP :
5194 direction == 1 ? MV_RIGHT :
5195 direction == 2 ? MV_DOWN :
5196 direction == 3 ? MV_LEFT :
5200 int get_next_element(int element)
5204 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5205 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5206 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5207 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5208 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5209 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5210 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5212 default: return element;
5217 int el_act_dir2img(int element, int action, int direction)
5219 element = GFX_ELEMENT(element);
5221 if (direction == MV_NONE)
5222 return element_info[element].graphic[action];
5224 direction = MV_DIR_TO_BIT(direction);
5226 return element_info[element].direction_graphic[action][direction];
5229 int el_act_dir2img(int element, int action, int direction)
5231 element = GFX_ELEMENT(element);
5232 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5234 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5235 return element_info[element].direction_graphic[action][direction];
5240 static int el_act_dir2crm(int element, int action, int direction)
5242 element = GFX_ELEMENT(element);
5244 if (direction == MV_NONE)
5245 return element_info[element].crumbled[action];
5247 direction = MV_DIR_TO_BIT(direction);
5249 return element_info[element].direction_crumbled[action][direction];
5252 static int el_act_dir2crm(int element, int action, int direction)
5254 element = GFX_ELEMENT(element);
5255 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5257 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5258 return element_info[element].direction_crumbled[action][direction];
5262 int el_act2img(int element, int action)
5264 element = GFX_ELEMENT(element);
5266 return element_info[element].graphic[action];
5269 int el_act2crm(int element, int action)
5271 element = GFX_ELEMENT(element);
5273 return element_info[element].crumbled[action];
5276 int el_dir2img(int element, int direction)
5278 element = GFX_ELEMENT(element);
5280 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5283 int el2baseimg(int element)
5285 return element_info[element].graphic[ACTION_DEFAULT];
5288 int el2img(int element)
5290 element = GFX_ELEMENT(element);
5292 return element_info[element].graphic[ACTION_DEFAULT];
5295 int el2edimg(int element)
5297 element = GFX_ELEMENT(element);
5299 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5302 int el2preimg(int element)
5304 element = GFX_ELEMENT(element);
5306 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5309 int font2baseimg(int font_nr)
5311 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5315 void setCenteredPlayerNr_EM(int centered_player_nr)
5317 game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5320 int getCenteredPlayerNr_EM()
5323 if (game.centered_player_nr_next >= 0 &&
5324 !native_em_level.ply[game.centered_player_nr_next]->alive)
5325 game.centered_player_nr_next = game.centered_player_nr;
5328 if (game.centered_player_nr != game.centered_player_nr_next)
5329 game.centered_player_nr = game.centered_player_nr_next;
5331 return game.centered_player_nr;
5334 void setSetCenteredPlayer_EM(boolean set_centered_player)
5336 game.set_centered_player = set_centered_player;
5339 boolean getSetCenteredPlayer_EM()
5341 return game.set_centered_player;
5345 int getNumActivePlayers_EM()
5347 int num_players = 0;
5353 for (i = 0; i < MAX_PLAYERS; i++)
5354 if (tape.player_participates[i])
5361 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5363 int game_frame_delay_value;
5365 game_frame_delay_value =
5366 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5367 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5370 if (tape.playing && tape.warp_forward && !tape.pausing)
5371 game_frame_delay_value = 0;
5373 return game_frame_delay_value;
5377 unsigned int InitRND(long seed)
5379 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5380 return InitEngineRND_EM(seed);
5382 return InitEngineRND(seed);
5385 void InitGraphicInfo_EM(void)
5387 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5388 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5392 int num_em_gfx_errors = 0;
5394 if (graphic_info_em_object[0][0].bitmap == NULL)
5396 /* EM graphics not yet initialized in em_open_all() */
5401 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5404 /* always start with reliable default values */
5405 for (i = 0; i < TILE_MAX; i++)
5407 object_mapping[i].element_rnd = EL_UNKNOWN;
5408 object_mapping[i].is_backside = FALSE;
5409 object_mapping[i].action = ACTION_DEFAULT;
5410 object_mapping[i].direction = MV_NONE;
5413 /* always start with reliable default values */
5414 for (p = 0; p < MAX_PLAYERS; p++)
5416 for (i = 0; i < SPR_MAX; i++)
5418 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5419 player_mapping[p][i].action = ACTION_DEFAULT;
5420 player_mapping[p][i].direction = MV_NONE;
5424 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5426 int e = em_object_mapping_list[i].element_em;
5428 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5429 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5431 if (em_object_mapping_list[i].action != -1)
5432 object_mapping[e].action = em_object_mapping_list[i].action;
5434 if (em_object_mapping_list[i].direction != -1)
5435 object_mapping[e].direction =
5436 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5439 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5441 int a = em_player_mapping_list[i].action_em;
5442 int p = em_player_mapping_list[i].player_nr;
5444 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5446 if (em_player_mapping_list[i].action != -1)
5447 player_mapping[p][a].action = em_player_mapping_list[i].action;
5449 if (em_player_mapping_list[i].direction != -1)
5450 player_mapping[p][a].direction =
5451 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5454 for (i = 0; i < TILE_MAX; i++)
5456 int element = object_mapping[i].element_rnd;
5457 int action = object_mapping[i].action;
5458 int direction = object_mapping[i].direction;
5459 boolean is_backside = object_mapping[i].is_backside;
5460 boolean action_removing = (action == ACTION_DIGGING ||
5461 action == ACTION_SNAPPING ||
5462 action == ACTION_COLLECTING);
5463 boolean action_exploding = ((action == ACTION_EXPLODING ||
5464 action == ACTION_SMASHED_BY_ROCK ||
5465 action == ACTION_SMASHED_BY_SPRING) &&
5466 element != EL_DIAMOND);
5467 boolean action_active = (action == ACTION_ACTIVE);
5468 boolean action_other = (action == ACTION_OTHER);
5470 for (j = 0; j < 8; j++)
5472 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5473 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5475 i == Xdrip_stretch ? element :
5476 i == Xdrip_stretchB ? element :
5477 i == Ydrip_s1 ? element :
5478 i == Ydrip_s1B ? element :
5479 i == Xball_1B ? element :
5480 i == Xball_2 ? element :
5481 i == Xball_2B ? element :
5482 i == Yball_eat ? element :
5483 i == Ykey_1_eat ? element :
5484 i == Ykey_2_eat ? element :
5485 i == Ykey_3_eat ? element :
5486 i == Ykey_4_eat ? element :
5487 i == Ykey_5_eat ? element :
5488 i == Ykey_6_eat ? element :
5489 i == Ykey_7_eat ? element :
5490 i == Ykey_8_eat ? element :
5491 i == Ylenses_eat ? element :
5492 i == Ymagnify_eat ? element :
5493 i == Ygrass_eat ? element :
5494 i == Ydirt_eat ? element :
5495 i == Yemerald_stone ? EL_EMERALD :
5496 i == Ydiamond_stone ? EL_ROCK :
5497 i == Xsand_stonein_1 ? element :
5498 i == Xsand_stonein_2 ? element :
5499 i == Xsand_stonein_3 ? element :
5500 i == Xsand_stonein_4 ? element :
5501 is_backside ? EL_EMPTY :
5502 action_removing ? EL_EMPTY :
5504 int effective_action = (j < 7 ? action :
5505 i == Xdrip_stretch ? action :
5506 i == Xdrip_stretchB ? action :
5507 i == Ydrip_s1 ? action :
5508 i == Ydrip_s1B ? action :
5509 i == Xball_1B ? action :
5510 i == Xball_2 ? action :
5511 i == Xball_2B ? action :
5512 i == Yball_eat ? action :
5513 i == Ykey_1_eat ? action :
5514 i == Ykey_2_eat ? action :
5515 i == Ykey_3_eat ? action :
5516 i == Ykey_4_eat ? action :
5517 i == Ykey_5_eat ? action :
5518 i == Ykey_6_eat ? action :
5519 i == Ykey_7_eat ? action :
5520 i == Ykey_8_eat ? action :
5521 i == Ylenses_eat ? action :
5522 i == Ymagnify_eat ? action :
5523 i == Ygrass_eat ? action :
5524 i == Ydirt_eat ? action :
5525 i == Xsand_stonein_1 ? action :
5526 i == Xsand_stonein_2 ? action :
5527 i == Xsand_stonein_3 ? action :
5528 i == Xsand_stonein_4 ? action :
5529 i == Xsand_stoneout_1 ? action :
5530 i == Xsand_stoneout_2 ? action :
5531 i == Xboom_android ? ACTION_EXPLODING :
5532 action_exploding ? ACTION_EXPLODING :
5533 action_active ? action :
5534 action_other ? action :
5536 int graphic = (el_act_dir2img(effective_element, effective_action,
5538 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5540 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5541 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5542 boolean has_action_graphics = (graphic != base_graphic);
5543 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5544 struct GraphicInfo *g = &graphic_info[graphic];
5545 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5548 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5549 boolean special_animation = (action != ACTION_DEFAULT &&
5550 g->anim_frames == 3 &&
5551 g->anim_delay == 2 &&
5552 g->anim_mode & ANIM_LINEAR);
5553 int sync_frame = (i == Xdrip_stretch ? 7 :
5554 i == Xdrip_stretchB ? 7 :
5555 i == Ydrip_s2 ? j + 8 :
5556 i == Ydrip_s2B ? j + 8 :
5565 i == Xfake_acid_1 ? 0 :
5566 i == Xfake_acid_2 ? 10 :
5567 i == Xfake_acid_3 ? 20 :
5568 i == Xfake_acid_4 ? 30 :
5569 i == Xfake_acid_5 ? 40 :
5570 i == Xfake_acid_6 ? 50 :
5571 i == Xfake_acid_7 ? 60 :
5572 i == Xfake_acid_8 ? 70 :
5574 i == Xball_2B ? j + 8 :
5575 i == Yball_eat ? j + 1 :
5576 i == Ykey_1_eat ? j + 1 :
5577 i == Ykey_2_eat ? j + 1 :
5578 i == Ykey_3_eat ? j + 1 :
5579 i == Ykey_4_eat ? j + 1 :
5580 i == Ykey_5_eat ? j + 1 :
5581 i == Ykey_6_eat ? j + 1 :
5582 i == Ykey_7_eat ? j + 1 :
5583 i == Ykey_8_eat ? j + 1 :
5584 i == Ylenses_eat ? j + 1 :
5585 i == Ymagnify_eat ? j + 1 :
5586 i == Ygrass_eat ? j + 1 :
5587 i == Ydirt_eat ? j + 1 :
5588 i == Xamoeba_1 ? 0 :
5589 i == Xamoeba_2 ? 1 :
5590 i == Xamoeba_3 ? 2 :
5591 i == Xamoeba_4 ? 3 :
5592 i == Xamoeba_5 ? 0 :
5593 i == Xamoeba_6 ? 1 :
5594 i == Xamoeba_7 ? 2 :
5595 i == Xamoeba_8 ? 3 :
5596 i == Xexit_2 ? j + 8 :
5597 i == Xexit_3 ? j + 16 :
5598 i == Xdynamite_1 ? 0 :
5599 i == Xdynamite_2 ? 8 :
5600 i == Xdynamite_3 ? 16 :
5601 i == Xdynamite_4 ? 24 :
5602 i == Xsand_stonein_1 ? j + 1 :
5603 i == Xsand_stonein_2 ? j + 9 :
5604 i == Xsand_stonein_3 ? j + 17 :
5605 i == Xsand_stonein_4 ? j + 25 :
5606 i == Xsand_stoneout_1 && j == 0 ? 0 :
5607 i == Xsand_stoneout_1 && j == 1 ? 0 :
5608 i == Xsand_stoneout_1 && j == 2 ? 1 :
5609 i == Xsand_stoneout_1 && j == 3 ? 2 :
5610 i == Xsand_stoneout_1 && j == 4 ? 2 :
5611 i == Xsand_stoneout_1 && j == 5 ? 3 :
5612 i == Xsand_stoneout_1 && j == 6 ? 4 :
5613 i == Xsand_stoneout_1 && j == 7 ? 4 :
5614 i == Xsand_stoneout_2 && j == 0 ? 5 :
5615 i == Xsand_stoneout_2 && j == 1 ? 6 :
5616 i == Xsand_stoneout_2 && j == 2 ? 7 :
5617 i == Xsand_stoneout_2 && j == 3 ? 8 :
5618 i == Xsand_stoneout_2 && j == 4 ? 9 :
5619 i == Xsand_stoneout_2 && j == 5 ? 11 :
5620 i == Xsand_stoneout_2 && j == 6 ? 13 :
5621 i == Xsand_stoneout_2 && j == 7 ? 15 :
5622 i == Xboom_bug && j == 1 ? 2 :
5623 i == Xboom_bug && j == 2 ? 2 :
5624 i == Xboom_bug && j == 3 ? 4 :
5625 i == Xboom_bug && j == 4 ? 4 :
5626 i == Xboom_bug && j == 5 ? 2 :
5627 i == Xboom_bug && j == 6 ? 2 :
5628 i == Xboom_bug && j == 7 ? 0 :
5629 i == Xboom_bomb && j == 1 ? 2 :
5630 i == Xboom_bomb && j == 2 ? 2 :
5631 i == Xboom_bomb && j == 3 ? 4 :
5632 i == Xboom_bomb && j == 4 ? 4 :
5633 i == Xboom_bomb && j == 5 ? 2 :
5634 i == Xboom_bomb && j == 6 ? 2 :
5635 i == Xboom_bomb && j == 7 ? 0 :
5636 i == Xboom_android && j == 7 ? 6 :
5637 i == Xboom_1 && j == 1 ? 2 :
5638 i == Xboom_1 && j == 2 ? 2 :
5639 i == Xboom_1 && j == 3 ? 4 :
5640 i == Xboom_1 && j == 4 ? 4 :
5641 i == Xboom_1 && j == 5 ? 6 :
5642 i == Xboom_1 && j == 6 ? 6 :
5643 i == Xboom_1 && j == 7 ? 8 :
5644 i == Xboom_2 && j == 0 ? 8 :
5645 i == Xboom_2 && j == 1 ? 8 :
5646 i == Xboom_2 && j == 2 ? 10 :
5647 i == Xboom_2 && j == 3 ? 10 :
5648 i == Xboom_2 && j == 4 ? 10 :
5649 i == Xboom_2 && j == 5 ? 12 :
5650 i == Xboom_2 && j == 6 ? 12 :
5651 i == Xboom_2 && j == 7 ? 12 :
5652 special_animation && j == 4 ? 3 :
5653 effective_action != action ? 0 :
5657 Bitmap *debug_bitmap = g_em->bitmap;
5658 int debug_src_x = g_em->src_x;
5659 int debug_src_y = g_em->src_y;
5662 int frame = getAnimationFrame(g->anim_frames,
5665 g->anim_start_frame,
5668 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5669 g->double_movement && is_backside);
5671 g_em->bitmap = src_bitmap;
5672 g_em->src_x = src_x;
5673 g_em->src_y = src_y;
5674 g_em->src_offset_x = 0;
5675 g_em->src_offset_y = 0;
5676 g_em->dst_offset_x = 0;
5677 g_em->dst_offset_y = 0;
5678 g_em->width = TILEX;
5679 g_em->height = TILEY;
5681 g_em->crumbled_bitmap = NULL;
5682 g_em->crumbled_src_x = 0;
5683 g_em->crumbled_src_y = 0;
5684 g_em->crumbled_border_size = 0;
5686 g_em->has_crumbled_graphics = FALSE;
5687 g_em->preserve_background = FALSE;
5690 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5691 printf("::: empty crumbled: %d [%s], %d, %d\n",
5692 effective_element, element_info[effective_element].token_name,
5693 effective_action, direction);
5696 /* if element can be crumbled, but certain action graphics are just empty
5697 space (like snapping sand with the original R'n'D graphics), do not
5698 treat these empty space graphics as crumbled graphics in EMC engine */
5699 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5701 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5703 g_em->has_crumbled_graphics = TRUE;
5704 g_em->crumbled_bitmap = src_bitmap;
5705 g_em->crumbled_src_x = src_x;
5706 g_em->crumbled_src_y = src_y;
5707 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5711 if (element == EL_ROCK &&
5712 effective_action == ACTION_FILLING)
5713 printf("::: has_action_graphics == %d\n", has_action_graphics);
5716 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5717 effective_action == ACTION_MOVING ||
5718 effective_action == ACTION_PUSHING ||
5719 effective_action == ACTION_EATING)) ||
5720 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5721 effective_action == ACTION_EMPTYING)))
5724 (effective_action == ACTION_FALLING ||
5725 effective_action == ACTION_FILLING ||
5726 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5727 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5728 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5729 int num_steps = (i == Ydrip_s1 ? 16 :
5730 i == Ydrip_s1B ? 16 :
5731 i == Ydrip_s2 ? 16 :
5732 i == Ydrip_s2B ? 16 :
5733 i == Xsand_stonein_1 ? 32 :
5734 i == Xsand_stonein_2 ? 32 :
5735 i == Xsand_stonein_3 ? 32 :
5736 i == Xsand_stonein_4 ? 32 :
5737 i == Xsand_stoneout_1 ? 16 :
5738 i == Xsand_stoneout_2 ? 16 : 8);
5739 int cx = ABS(dx) * (TILEX / num_steps);
5740 int cy = ABS(dy) * (TILEY / num_steps);
5741 int step_frame = (i == Ydrip_s2 ? j + 8 :
5742 i == Ydrip_s2B ? j + 8 :
5743 i == Xsand_stonein_2 ? j + 8 :
5744 i == Xsand_stonein_3 ? j + 16 :
5745 i == Xsand_stonein_4 ? j + 24 :
5746 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5747 int step = (is_backside ? step_frame : num_steps - step_frame);
5749 if (is_backside) /* tile where movement starts */
5751 if (dx < 0 || dy < 0)
5753 g_em->src_offset_x = cx * step;
5754 g_em->src_offset_y = cy * step;
5758 g_em->dst_offset_x = cx * step;
5759 g_em->dst_offset_y = cy * step;
5762 else /* tile where movement ends */
5764 if (dx < 0 || dy < 0)
5766 g_em->dst_offset_x = cx * step;
5767 g_em->dst_offset_y = cy * step;
5771 g_em->src_offset_x = cx * step;
5772 g_em->src_offset_y = cy * step;
5776 g_em->width = TILEX - cx * step;
5777 g_em->height = TILEY - cy * step;
5781 /* create unique graphic identifier to decide if tile must be redrawn */
5782 /* bit 31 - 16 (16 bit): EM style graphic
5783 bit 15 - 12 ( 4 bit): EM style frame
5784 bit 11 - 6 ( 6 bit): graphic width
5785 bit 5 - 0 ( 6 bit): graphic height */
5786 g_em->unique_identifier =
5787 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5789 /* create unique graphic identifier to decide if tile must be redrawn */
5790 /* bit 31 - 16 (16 bit): EM style element
5791 bit 15 - 12 ( 4 bit): EM style frame
5792 bit 11 - 6 ( 6 bit): graphic width
5793 bit 5 - 0 ( 6 bit): graphic height */
5794 g_em->unique_identifier =
5795 (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5799 if (effective_element == EL_ROCK)
5800 printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5801 effective_action, j, graphic, frame, g_em->unique_identifier);
5807 /* skip check for EMC elements not contained in original EMC artwork */
5808 if (element == EL_EMC_FAKE_ACID)
5812 if (g_em->bitmap != debug_bitmap ||
5813 g_em->src_x != debug_src_x ||
5814 g_em->src_y != debug_src_y ||
5815 g_em->src_offset_x != 0 ||
5816 g_em->src_offset_y != 0 ||
5817 g_em->dst_offset_x != 0 ||
5818 g_em->dst_offset_y != 0 ||
5819 g_em->width != TILEX ||
5820 g_em->height != TILEY)
5822 static int last_i = -1;
5830 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5831 i, element, element_info[element].token_name,
5832 element_action_info[effective_action].suffix, direction);
5834 if (element != effective_element)
5835 printf(" [%d ('%s')]",
5837 element_info[effective_element].token_name);
5841 if (g_em->bitmap != debug_bitmap)
5842 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5843 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5845 if (g_em->src_x != debug_src_x ||
5846 g_em->src_y != debug_src_y)
5847 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5848 j, (is_backside ? 'B' : 'F'),
5849 g_em->src_x, g_em->src_y,
5850 g_em->src_x / 32, g_em->src_y / 32,
5851 debug_src_x, debug_src_y,
5852 debug_src_x / 32, debug_src_y / 32);
5854 if (g_em->src_offset_x != 0 ||
5855 g_em->src_offset_y != 0 ||
5856 g_em->dst_offset_x != 0 ||
5857 g_em->dst_offset_y != 0)
5858 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5860 g_em->src_offset_x, g_em->src_offset_y,
5861 g_em->dst_offset_x, g_em->dst_offset_y);
5863 if (g_em->width != TILEX ||
5864 g_em->height != TILEY)
5865 printf(" %d (%d): size %d,%d should be %d,%d\n",
5867 g_em->width, g_em->height, TILEX, TILEY);
5869 num_em_gfx_errors++;
5876 for (i = 0; i < TILE_MAX; i++)
5878 for (j = 0; j < 8; j++)
5880 int element = object_mapping[i].element_rnd;
5881 int action = object_mapping[i].action;
5882 int direction = object_mapping[i].direction;
5883 boolean is_backside = object_mapping[i].is_backside;
5885 int graphic_action = el_act_dir2img(element, action, direction);
5886 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5888 int graphic_action = element_info[element].graphic[action];
5889 int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5892 if ((action == ACTION_SMASHED_BY_ROCK ||
5893 action == ACTION_SMASHED_BY_SPRING ||
5894 action == ACTION_EATING) &&
5895 graphic_action == graphic_default)
5897 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5898 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5899 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
5900 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5903 /* no separate animation for "smashed by rock" -- use rock instead */
5904 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5905 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5907 g_em->bitmap = g_xx->bitmap;
5908 g_em->src_x = g_xx->src_x;
5909 g_em->src_y = g_xx->src_y;
5910 g_em->src_offset_x = g_xx->src_offset_x;
5911 g_em->src_offset_y = g_xx->src_offset_y;
5912 g_em->dst_offset_x = g_xx->dst_offset_x;
5913 g_em->dst_offset_y = g_xx->dst_offset_y;
5914 g_em->width = g_xx->width;
5915 g_em->height = g_xx->height;
5917 g_em->unique_identifier = g_xx->unique_identifier;
5921 g_em->preserve_background = TRUE;
5926 for (p = 0; p < MAX_PLAYERS; p++)
5928 for (i = 0; i < SPR_MAX; i++)
5930 int element = player_mapping[p][i].element_rnd;
5931 int action = player_mapping[p][i].action;
5932 int direction = player_mapping[p][i].direction;
5934 for (j = 0; j < 8; j++)
5936 int effective_element = element;
5937 int effective_action = action;
5938 int graphic = (direction == MV_NONE ?
5939 el_act2img(effective_element, effective_action) :
5940 el_act_dir2img(effective_element, effective_action,
5942 struct GraphicInfo *g = &graphic_info[graphic];
5943 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5949 Bitmap *debug_bitmap = g_em->bitmap;
5950 int debug_src_x = g_em->src_x;
5951 int debug_src_y = g_em->src_y;
5954 int frame = getAnimationFrame(g->anim_frames,
5957 g->anim_start_frame,
5960 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5962 g_em->bitmap = src_bitmap;
5963 g_em->src_x = src_x;
5964 g_em->src_y = src_y;
5965 g_em->src_offset_x = 0;
5966 g_em->src_offset_y = 0;
5967 g_em->dst_offset_x = 0;
5968 g_em->dst_offset_y = 0;
5969 g_em->width = TILEX;
5970 g_em->height = TILEY;
5975 /* skip check for EMC elements not contained in original EMC artwork */
5976 if (element == EL_PLAYER_3 ||
5977 element == EL_PLAYER_4)
5981 if (g_em->bitmap != debug_bitmap ||
5982 g_em->src_x != debug_src_x ||
5983 g_em->src_y != debug_src_y)
5985 static int last_i = -1;
5993 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5994 p, i, element, element_info[element].token_name,
5995 element_action_info[effective_action].suffix, direction);
5997 if (element != effective_element)
5998 printf(" [%d ('%s')]",
6000 element_info[effective_element].token_name);
6004 if (g_em->bitmap != debug_bitmap)
6005 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6006 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6008 if (g_em->src_x != debug_src_x ||
6009 g_em->src_y != debug_src_y)
6010 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6012 g_em->src_x, g_em->src_y,
6013 g_em->src_x / 32, g_em->src_y / 32,
6014 debug_src_x, debug_src_y,
6015 debug_src_x / 32, debug_src_y / 32);
6017 num_em_gfx_errors++;
6027 printf("::: [%d errors found]\n", num_em_gfx_errors);
6033 void PlayMenuSound()
6035 int sound = menu.sound[game_status];
6037 if (sound == SND_UNDEFINED)
6040 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6041 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6044 if (IS_LOOP_SOUND(sound))
6045 PlaySoundLoop(sound);
6050 void PlayMenuSoundStereo(int sound, int stereo_position)
6052 if (sound == SND_UNDEFINED)
6055 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6056 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6059 if (IS_LOOP_SOUND(sound))
6060 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6062 PlaySoundStereo(sound, stereo_position);
6065 void PlayMenuSoundIfLoop()
6067 int sound = menu.sound[game_status];
6069 if (sound == SND_UNDEFINED)
6072 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6073 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6076 if (IS_LOOP_SOUND(sound))
6077 PlaySoundLoop(sound);
6080 void PlayMenuMusic()
6082 int music = menu.music[game_status];
6084 if (music == MUS_UNDEFINED)
6090 void ToggleFullscreenIfNeeded()
6092 if (setup.fullscreen != video.fullscreen_enabled ||
6093 setup.fullscreen_mode != video.fullscreen_mode_current)
6095 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6097 /* save backbuffer content which gets lost when toggling fullscreen mode */
6098 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6100 if (setup.fullscreen && video.fullscreen_enabled)
6102 /* keep fullscreen mode, but change screen mode */
6103 video.fullscreen_mode_current = setup.fullscreen_mode;
6104 video.fullscreen_enabled = FALSE;
6107 /* toggle fullscreen */
6108 ChangeVideoModeIfNeeded(setup.fullscreen);
6109 setup.fullscreen = video.fullscreen_enabled;
6111 /* restore backbuffer content from temporary backbuffer backup bitmap */
6112 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6114 FreeBitmap(tmp_backbuffer);
6116 redraw_mask = REDRAW_ALL;