1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX 0
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES 0
30 #define TOOL_CTRL_ID_NO 1
31 #define TOOL_CTRL_ID_CONFIRM 2
32 #define TOOL_CTRL_ID_PLAYER_1 3
33 #define TOOL_CTRL_ID_PLAYER_2 4
34 #define TOOL_CTRL_ID_PLAYER_3 5
35 #define TOOL_CTRL_ID_PLAYER_4 6
37 #define NUM_TOOL_BUTTONS 7
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
48 static char *print_if_not_empty(int element)
50 static char *s = NULL;
51 char *token_name = element_info[element].token_name;
56 s = checked_malloc(strlen(token_name) + 10 + 1);
58 if (element != EL_EMPTY)
59 sprintf(s, "%d\t['%s']", element, token_name);
61 sprintf(s, "%d", element);
66 void DumpTile(int x, int y)
71 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
78 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
81 if (!IN_LEV_FIELD(x, y))
83 printf("(not in level field)\n");
89 printf(" Feld: %d\t['%s']\n", Feld[x][y],
90 element_info[Feld[x][y]].token_name);
91 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
92 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
93 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
94 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95 printf(" MovPos: %d\n", MovPos[x][y]);
96 printf(" MovDir: %d\n", MovDir[x][y]);
97 printf(" MovDelay: %d\n", MovDelay[x][y]);
98 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
99 printf(" CustomValue: %d\n", CustomValue[x][y]);
100 printf(" GfxElement: %d\n", GfxElement[x][y]);
101 printf(" GfxAction: %d\n", GfxAction[x][y]);
102 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
106 void SetDrawtoField(int mode)
108 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
119 drawto_field = fieldbuffer;
121 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
138 if (game_status == GAME_MODE_PLAYING &&
139 level.game_engine_type == GAME_ENGINE_TYPE_EM)
141 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
153 width = gfx.sxsize + 2 * TILEX;
154 height = gfx.sysize + 2 * TILEY;
157 if (force_redraw || setup.direct_draw)
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 if (setup.direct_draw)
164 SetDrawtoField(DRAW_BACKBUFFER);
166 for (xx = BX1; xx <= BX2; xx++)
167 for (yy = BY1; yy <= BY2; yy++)
168 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
169 DrawScreenField(xx, yy);
172 if (setup.direct_draw)
173 SetDrawtoField(DRAW_DIRECT);
176 if (setup.soft_scrolling)
178 int fx = FX, fy = FY;
180 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
181 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
183 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
195 BlitBitmap(drawto, window, x, y, width, height, x, y);
198 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
200 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
202 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
203 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
206 void DrawMaskedBorder_FIELD()
208 if (game_status >= GAME_MODE_TITLE &&
209 game_status <= GAME_MODE_PLAYING &&
210 border.draw_masked[game_status])
211 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
214 void DrawMaskedBorder_DOOR_1()
216 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
217 (game_status != GAME_MODE_EDITOR ||
218 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
219 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
222 void DrawMaskedBorder_DOOR_2()
224 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
225 game_status != GAME_MODE_EDITOR)
226 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
229 void DrawMaskedBorder_DOOR_3()
231 /* currently not available */
234 void DrawMaskedBorder_ALL()
236 DrawMaskedBorder_FIELD();
237 DrawMaskedBorder_DOOR_1();
238 DrawMaskedBorder_DOOR_2();
239 DrawMaskedBorder_DOOR_3();
242 void DrawMaskedBorder(int redraw_mask)
244 /* do not draw masked screen borders when displaying title screens */
245 if (effectiveGameStatus() == GAME_MODE_TITLE ||
246 effectiveGameStatus() == GAME_MODE_MESSAGE)
249 if (redraw_mask & REDRAW_ALL)
250 DrawMaskedBorder_ALL();
253 if (redraw_mask & REDRAW_FIELD)
254 DrawMaskedBorder_FIELD();
255 if (redraw_mask & REDRAW_DOOR_1)
256 DrawMaskedBorder_DOOR_1();
257 if (redraw_mask & REDRAW_DOOR_2)
258 DrawMaskedBorder_DOOR_2();
259 if (redraw_mask & REDRAW_DOOR_3)
260 DrawMaskedBorder_DOOR_3();
267 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
269 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
270 redraw_mask &= ~REDRAW_MAIN;
272 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
273 redraw_mask |= REDRAW_FIELD;
275 if (redraw_mask & REDRAW_FIELD)
276 redraw_mask &= ~REDRAW_TILES;
278 if (redraw_mask == REDRAW_NONE)
281 if (redraw_mask & REDRAW_TILES &&
282 game_status == GAME_MODE_PLAYING &&
283 border.draw_masked[GAME_MODE_PLAYING])
284 redraw_mask |= REDRAW_FIELD;
286 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
288 static boolean last_frame_skipped = FALSE;
289 boolean skip_even_when_not_scrolling = TRUE;
290 boolean just_scrolling = (ScreenMovDir != 0);
291 boolean verbose = FALSE;
293 if (global.fps_slowdown_factor > 1 &&
294 (FrameCounter % global.fps_slowdown_factor) &&
295 (just_scrolling || skip_even_when_not_scrolling))
297 redraw_mask &= ~REDRAW_MAIN;
299 last_frame_skipped = TRUE;
302 printf("FRAME SKIPPED\n");
306 if (last_frame_skipped)
307 redraw_mask |= REDRAW_FIELD;
309 last_frame_skipped = FALSE;
312 printf("frame not skipped\n");
316 /* synchronize X11 graphics at this point; if we would synchronize the
317 display immediately after the buffer switching (after the XFlush),
318 this could mean that we have to wait for the graphics to complete,
319 although we could go on doing calculations for the next frame */
323 /* prevent drawing masked border to backbuffer when using playfield buffer */
324 if (game_status != GAME_MODE_PLAYING ||
325 redraw_mask & REDRAW_FROM_BACKBUFFER ||
326 buffer == backbuffer)
327 DrawMaskedBorder(redraw_mask);
329 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
331 if (redraw_mask & REDRAW_ALL)
333 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
335 redraw_mask = REDRAW_NONE;
338 if (redraw_mask & REDRAW_FIELD)
340 if (game_status != GAME_MODE_PLAYING ||
341 redraw_mask & REDRAW_FROM_BACKBUFFER)
343 BlitBitmap(backbuffer, window,
344 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
348 int fx = FX, fy = FY;
350 if (setup.soft_scrolling)
352 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
353 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
356 if (setup.soft_scrolling ||
357 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
358 ABS(ScreenMovPos) == ScrollStepSize ||
359 redraw_tiles > REDRAWTILES_THRESHOLD)
361 if (border.draw_masked[GAME_MODE_PLAYING])
363 if (buffer != backbuffer)
365 /* copy playfield buffer to backbuffer to add masked border */
366 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
367 DrawMaskedBorder(REDRAW_FIELD);
370 BlitBitmap(backbuffer, window,
371 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
376 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
381 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
383 (setup.soft_scrolling ?
384 "setup.soft_scrolling" :
385 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
386 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
387 ABS(ScreenGfxPos) == ScrollStepSize ?
388 "ABS(ScreenGfxPos) == ScrollStepSize" :
389 "redraw_tiles > REDRAWTILES_THRESHOLD"));
395 redraw_mask &= ~REDRAW_MAIN;
398 if (redraw_mask & REDRAW_DOORS)
400 if (redraw_mask & REDRAW_DOOR_1)
401 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
403 if (redraw_mask & REDRAW_DOOR_2)
404 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
406 if (redraw_mask & REDRAW_DOOR_3)
407 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
409 redraw_mask &= ~REDRAW_DOORS;
412 if (redraw_mask & REDRAW_MICROLEVEL)
414 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
415 SX, SY + 10 * TILEY);
417 redraw_mask &= ~REDRAW_MICROLEVEL;
420 if (redraw_mask & REDRAW_TILES)
422 for (x = 0; x < SCR_FIELDX; x++)
423 for (y = 0 ; y < SCR_FIELDY; y++)
424 if (redraw[redraw_x1 + x][redraw_y1 + y])
425 BlitBitmap(buffer, window,
426 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
427 SX + x * TILEX, SY + y * TILEY);
430 if (redraw_mask & REDRAW_FPS) /* display frames per second */
435 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
436 if (!global.fps_slowdown)
439 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
440 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
445 for (x = 0; x < MAX_BUF_XSIZE; x++)
446 for (y = 0; y < MAX_BUF_YSIZE; y++)
449 redraw_mask = REDRAW_NONE;
455 long fading_delay = 300;
457 if (setup.fading && (redraw_mask & REDRAW_FIELD))
464 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
467 for (i = 0; i < 2 * FULL_SYSIZE; i++)
469 for (y = 0; y < FULL_SYSIZE; y++)
471 BlitBitmap(backbuffer, window,
472 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
480 for (i = 1; i < FULL_SYSIZE; i+=2)
481 BlitBitmap(backbuffer, window,
482 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
488 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
489 BlitBitmapMasked(backbuffer, window,
490 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
495 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
496 BlitBitmapMasked(backbuffer, window,
497 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
502 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
503 BlitBitmapMasked(backbuffer, window,
504 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
509 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
510 BlitBitmapMasked(backbuffer, window,
511 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
516 redraw_mask &= ~REDRAW_MAIN;
523 void FadeExt(int fade_mask, int fade_mode)
525 void (*draw_border_function)(void) = NULL;
526 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
527 int x, y, width, height;
528 int fade_delay, post_delay;
530 if (fade_mask & REDRAW_FIELD)
535 height = FULL_SYSIZE;
537 fade_delay = menu.fade_delay;
538 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
540 draw_border_function = DrawMaskedBorder_FIELD;
542 else /* REDRAW_ALL */
549 fade_delay = title.fade_delay_final;
550 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? title.post_delay_final : 0);
553 redraw_mask |= fade_mask;
555 if (!setup.fade_screens || fade_delay == 0)
557 if (fade_mode == FADE_MODE_FADE_OUT)
558 ClearRectangle(backbuffer, x, y, width, height);
565 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
566 draw_border_function);
568 redraw_mask &= ~fade_mask;
571 void FadeIn(int fade_mask)
573 FadeExt(fade_mask, FADE_MODE_FADE_IN);
576 void FadeOut(int fade_mask)
578 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
581 void FadeCross(int fade_mask)
583 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
586 void FadeCrossSaveBackbuffer()
588 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
591 void SetWindowBackgroundImageIfDefined(int graphic)
593 if (graphic_info[graphic].bitmap)
594 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
597 void SetMainBackgroundImageIfDefined(int graphic)
599 if (graphic_info[graphic].bitmap)
600 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
603 void SetMainBackgroundImage(int graphic)
605 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
606 graphic_info[graphic].bitmap ?
607 graphic_info[graphic].bitmap :
608 graphic_info[IMG_BACKGROUND].bitmap);
611 void SetDoorBackgroundImage(int graphic)
613 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
614 graphic_info[graphic].bitmap ?
615 graphic_info[graphic].bitmap :
616 graphic_info[IMG_BACKGROUND].bitmap);
619 void SetPanelBackground()
621 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
622 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
624 SetDoorBackgroundBitmap(bitmap_db_panel);
627 void DrawBackground(int x, int y, int width, int height)
629 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
630 /* (when entering hall of fame after playing) */
632 ClearRectangleOnBackground(drawto, x, y, width, height);
634 ClearRectangleOnBackground(backbuffer, x, y, width, height);
637 redraw_mask |= REDRAW_FIELD;
640 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
642 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
644 if (font->bitmap == NULL)
647 DrawBackground(x, y, width, height);
650 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
652 struct GraphicInfo *g = &graphic_info[graphic];
654 if (g->bitmap == NULL)
657 DrawBackground(x, y, width, height);
662 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
663 /* (when entering hall of fame after playing) */
664 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
666 /* !!! maybe this should be done before clearing the background !!! */
667 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
669 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
670 SetDrawtoField(DRAW_BUFFERED);
673 SetDrawtoField(DRAW_BACKBUFFER);
675 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
677 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
678 SetDrawtoField(DRAW_DIRECT);
682 void MarkTileDirty(int x, int y)
684 int xx = redraw_x1 + x;
685 int yy = redraw_y1 + y;
690 redraw[xx][yy] = TRUE;
691 redraw_mask |= REDRAW_TILES;
694 void SetBorderElement()
698 BorderElement = EL_EMPTY;
700 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
702 for (x = 0; x < lev_fieldx; x++)
704 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
705 BorderElement = EL_STEELWALL;
707 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
713 void SetRandomAnimationValue(int x, int y)
715 gfx.anim_random_frame = GfxRandom[x][y];
718 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
720 /* animation synchronized with global frame counter, not move position */
721 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
722 sync_frame = FrameCounter;
724 return getAnimationFrame(graphic_info[graphic].anim_frames,
725 graphic_info[graphic].anim_delay,
726 graphic_info[graphic].anim_mode,
727 graphic_info[graphic].anim_start_frame,
731 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
732 int *x, int *y, boolean get_backside)
734 struct GraphicInfo *g = &graphic_info[graphic];
735 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
736 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
740 if (g->offset_y == 0) /* frames are ordered horizontally */
742 int max_width = g->anim_frames_per_line * g->width;
743 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
745 *x = pos % max_width;
746 *y = src_y % g->height + pos / max_width * g->height;
748 else if (g->offset_x == 0) /* frames are ordered vertically */
750 int max_height = g->anim_frames_per_line * g->height;
751 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
753 *x = src_x % g->width + pos / max_height * g->width;
754 *y = pos % max_height;
756 else /* frames are ordered diagonally */
758 *x = src_x + frame * g->offset_x;
759 *y = src_y + frame * g->offset_y;
763 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
765 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
768 void DrawGraphic(int x, int y, int graphic, int frame)
771 if (!IN_SCR_FIELD(x, y))
773 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
774 printf("DrawGraphic(): This should never happen!\n");
779 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
783 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
789 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
790 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
793 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
796 if (!IN_SCR_FIELD(x, y))
798 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
799 printf("DrawGraphicThruMask(): This should never happen!\n");
804 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
809 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
815 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
817 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
818 dst_x - src_x, dst_y - src_y);
819 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
822 void DrawMiniGraphic(int x, int y, int graphic)
824 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
825 MarkTileDirty(x / 2, y / 2);
828 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
830 struct GraphicInfo *g = &graphic_info[graphic];
832 int mini_starty = g->bitmap->height * 2 / 3;
835 *x = mini_startx + g->src_x / 2;
836 *y = mini_starty + g->src_y / 2;
839 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
844 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
845 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
848 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
849 int graphic, int frame,
850 int cut_mode, int mask_mode)
855 int width = TILEX, height = TILEY;
858 if (dx || dy) /* shifted graphic */
860 if (x < BX1) /* object enters playfield from the left */
867 else if (x > BX2) /* object enters playfield from the right */
873 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
879 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
881 else if (dx) /* general horizontal movement */
882 MarkTileDirty(x + SIGN(dx), y);
884 if (y < BY1) /* object enters playfield from the top */
886 if (cut_mode==CUT_BELOW) /* object completely above top border */
894 else if (y > BY2) /* object enters playfield from the bottom */
900 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
906 else if (dy > 0 && cut_mode == CUT_ABOVE)
908 if (y == BY2) /* object completely above bottom border */
914 MarkTileDirty(x, y + 1);
915 } /* object leaves playfield to the bottom */
916 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
918 else if (dy) /* general vertical movement */
919 MarkTileDirty(x, y + SIGN(dy));
923 if (!IN_SCR_FIELD(x, y))
925 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
926 printf("DrawGraphicShifted(): This should never happen!\n");
931 if (width > 0 && height > 0)
933 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
938 dst_x = FX + x * TILEX + dx;
939 dst_y = FY + y * TILEY + dy;
941 if (mask_mode == USE_MASKING)
943 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
944 dst_x - src_x, dst_y - src_y);
945 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
949 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
956 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
957 int graphic, int frame,
958 int cut_mode, int mask_mode)
963 int width = TILEX, height = TILEY;
966 int x2 = x + SIGN(dx);
967 int y2 = y + SIGN(dy);
968 int anim_frames = graphic_info[graphic].anim_frames;
969 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
970 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
971 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
973 /* re-calculate animation frame for two-tile movement animation */
974 frame = getGraphicAnimationFrame(graphic, sync_frame);
976 /* check if movement start graphic inside screen area and should be drawn */
977 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
979 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
981 dst_x = FX + x1 * TILEX;
982 dst_y = FY + y1 * TILEY;
984 if (mask_mode == USE_MASKING)
986 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
987 dst_x - src_x, dst_y - src_y);
988 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
992 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
995 MarkTileDirty(x1, y1);
998 /* check if movement end graphic inside screen area and should be drawn */
999 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1001 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1003 dst_x = FX + x2 * TILEX;
1004 dst_y = FY + y2 * TILEY;
1006 if (mask_mode == USE_MASKING)
1008 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1009 dst_x - src_x, dst_y - src_y);
1010 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1014 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1017 MarkTileDirty(x2, y2);
1021 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1022 int graphic, int frame,
1023 int cut_mode, int mask_mode)
1027 DrawGraphic(x, y, graphic, frame);
1032 if (graphic_info[graphic].double_movement) /* EM style movement images */
1033 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1035 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1038 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1039 int frame, int cut_mode)
1041 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1044 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1045 int cut_mode, int mask_mode)
1047 int lx = LEVELX(x), ly = LEVELY(y);
1051 if (IN_LEV_FIELD(lx, ly))
1053 SetRandomAnimationValue(lx, ly);
1055 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1056 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1058 /* do not use double (EM style) movement graphic when not moving */
1059 if (graphic_info[graphic].double_movement && !dx && !dy)
1061 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1062 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1065 else /* border element */
1067 graphic = el2img(element);
1068 frame = getGraphicAnimationFrame(graphic, -1);
1071 if (element == EL_EXPANDABLE_WALL)
1073 boolean left_stopped = FALSE, right_stopped = FALSE;
1075 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1076 left_stopped = TRUE;
1077 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1078 right_stopped = TRUE;
1080 if (left_stopped && right_stopped)
1082 else if (left_stopped)
1084 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1085 frame = graphic_info[graphic].anim_frames - 1;
1087 else if (right_stopped)
1089 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1090 frame = graphic_info[graphic].anim_frames - 1;
1095 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1096 else if (mask_mode == USE_MASKING)
1097 DrawGraphicThruMask(x, y, graphic, frame);
1099 DrawGraphic(x, y, graphic, frame);
1102 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1103 int cut_mode, int mask_mode)
1105 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1106 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1107 cut_mode, mask_mode);
1110 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1113 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1116 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1119 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1122 void DrawLevelElementThruMask(int x, int y, int element)
1124 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1127 void DrawLevelFieldThruMask(int x, int y)
1129 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1132 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1136 int sx = SCREENX(x), sy = SCREENY(y);
1138 int width, height, cx, cy, i;
1139 int crumbled_border_size = graphic_info[graphic].border_size;
1140 static int xy[4][2] =
1148 if (!IN_LEV_FIELD(x, y))
1151 element = TILE_GFX_ELEMENT(x, y);
1153 /* crumble field itself */
1154 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1156 if (!IN_SCR_FIELD(sx, sy))
1159 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1161 for (i = 0; i < 4; i++)
1163 int xx = x + xy[i][0];
1164 int yy = y + xy[i][1];
1166 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1169 /* check if neighbour field is of same type */
1170 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1173 if (i == 1 || i == 2)
1175 width = crumbled_border_size;
1177 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1183 height = crumbled_border_size;
1185 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1188 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1189 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1192 MarkTileDirty(sx, sy);
1194 else /* crumble neighbour fields */
1196 for (i = 0; i < 4; i++)
1198 int xx = x + xy[i][0];
1199 int yy = y + xy[i][1];
1200 int sxx = sx + xy[i][0];
1201 int syy = sy + xy[i][1];
1203 if (!IN_LEV_FIELD(xx, yy) ||
1204 !IN_SCR_FIELD(sxx, syy) ||
1208 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1211 element = TILE_GFX_ELEMENT(xx, yy);
1213 if (!GFX_CRUMBLED(element))
1216 graphic = el_act2crm(element, ACTION_DEFAULT);
1217 crumbled_border_size = graphic_info[graphic].border_size;
1219 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1221 if (i == 1 || i == 2)
1223 width = crumbled_border_size;
1225 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1231 height = crumbled_border_size;
1233 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1236 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1237 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1239 MarkTileDirty(sxx, syy);
1244 void DrawLevelFieldCrumbledSand(int x, int y)
1248 if (!IN_LEV_FIELD(x, y))
1252 /* !!! CHECK THIS !!! */
1255 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1256 GFX_CRUMBLED(GfxElement[x][y]))
1259 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1260 GfxElement[x][y] != EL_UNDEFINED &&
1261 GFX_CRUMBLED(GfxElement[x][y]))
1263 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1270 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1272 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1275 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1278 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1281 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1282 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1283 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1284 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1285 int sx = SCREENX(x), sy = SCREENY(y);
1287 DrawGraphic(sx, sy, graphic1, frame1);
1288 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1291 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1293 int sx = SCREENX(x), sy = SCREENY(y);
1294 static int xy[4][2] =
1303 for (i = 0; i < 4; i++)
1305 int xx = x + xy[i][0];
1306 int yy = y + xy[i][1];
1307 int sxx = sx + xy[i][0];
1308 int syy = sy + xy[i][1];
1310 if (!IN_LEV_FIELD(xx, yy) ||
1311 !IN_SCR_FIELD(sxx, syy) ||
1312 !GFX_CRUMBLED(Feld[xx][yy]) ||
1316 DrawLevelField(xx, yy);
1320 static int getBorderElement(int x, int y)
1324 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1325 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1326 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1327 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1328 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1329 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1330 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1332 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1333 int steel_position = (x == -1 && y == -1 ? 0 :
1334 x == lev_fieldx && y == -1 ? 1 :
1335 x == -1 && y == lev_fieldy ? 2 :
1336 x == lev_fieldx && y == lev_fieldy ? 3 :
1337 x == -1 || x == lev_fieldx ? 4 :
1338 y == -1 || y == lev_fieldy ? 5 : 6);
1340 return border[steel_position][steel_type];
1343 void DrawScreenElement(int x, int y, int element)
1345 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1346 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1349 void DrawLevelElement(int x, int y, int element)
1351 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1352 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1355 void DrawScreenField(int x, int y)
1357 int lx = LEVELX(x), ly = LEVELY(y);
1358 int element, content;
1360 if (!IN_LEV_FIELD(lx, ly))
1362 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1365 element = getBorderElement(lx, ly);
1367 DrawScreenElement(x, y, element);
1371 element = Feld[lx][ly];
1372 content = Store[lx][ly];
1374 if (IS_MOVING(lx, ly))
1376 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1377 boolean cut_mode = NO_CUTTING;
1379 if (element == EL_QUICKSAND_EMPTYING ||
1380 element == EL_MAGIC_WALL_EMPTYING ||
1381 element == EL_BD_MAGIC_WALL_EMPTYING ||
1382 element == EL_AMOEBA_DROPPING)
1383 cut_mode = CUT_ABOVE;
1384 else if (element == EL_QUICKSAND_FILLING ||
1385 element == EL_MAGIC_WALL_FILLING ||
1386 element == EL_BD_MAGIC_WALL_FILLING)
1387 cut_mode = CUT_BELOW;
1389 if (cut_mode == CUT_ABOVE)
1390 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1392 DrawScreenElement(x, y, EL_EMPTY);
1395 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1396 else if (cut_mode == NO_CUTTING)
1397 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1399 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1401 if (content == EL_ACID)
1403 int dir = MovDir[lx][ly];
1404 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1405 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1407 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1410 else if (IS_BLOCKED(lx, ly))
1415 boolean cut_mode = NO_CUTTING;
1416 int element_old, content_old;
1418 Blocked2Moving(lx, ly, &oldx, &oldy);
1421 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1422 MovDir[oldx][oldy] == MV_RIGHT);
1424 element_old = Feld[oldx][oldy];
1425 content_old = Store[oldx][oldy];
1427 if (element_old == EL_QUICKSAND_EMPTYING ||
1428 element_old == EL_MAGIC_WALL_EMPTYING ||
1429 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1430 element_old == EL_AMOEBA_DROPPING)
1431 cut_mode = CUT_ABOVE;
1433 DrawScreenElement(x, y, EL_EMPTY);
1436 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1438 else if (cut_mode == NO_CUTTING)
1439 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1442 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1445 else if (IS_DRAWABLE(element))
1446 DrawScreenElement(x, y, element);
1448 DrawScreenElement(x, y, EL_EMPTY);
1451 void DrawLevelField(int x, int y)
1453 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1454 DrawScreenField(SCREENX(x), SCREENY(y));
1455 else if (IS_MOVING(x, y))
1459 Moving2Blocked(x, y, &newx, &newy);
1460 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1461 DrawScreenField(SCREENX(newx), SCREENY(newy));
1463 else if (IS_BLOCKED(x, y))
1467 Blocked2Moving(x, y, &oldx, &oldy);
1468 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1469 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1473 void DrawMiniElement(int x, int y, int element)
1477 graphic = el2edimg(element);
1478 DrawMiniGraphic(x, y, graphic);
1481 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1483 int x = sx + scroll_x, y = sy + scroll_y;
1485 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1486 DrawMiniElement(sx, sy, EL_EMPTY);
1487 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1488 DrawMiniElement(sx, sy, Feld[x][y]);
1490 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1493 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1494 int x, int y, int xsize, int ysize, int font_nr)
1496 int font_width = getFontWidth(font_nr);
1497 int font_height = getFontHeight(font_nr);
1498 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1501 int dst_x = SX + startx + x * font_width;
1502 int dst_y = SY + starty + y * font_height;
1503 int width = graphic_info[graphic].width;
1504 int height = graphic_info[graphic].height;
1505 int inner_width = MAX(width - 2 * font_width, font_width);
1506 int inner_height = MAX(height - 2 * font_height, font_height);
1507 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1508 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1509 boolean draw_masked = graphic_info[graphic].draw_masked;
1511 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1513 if (src_bitmap == NULL || width < font_width || height < font_height)
1515 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1519 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1520 inner_sx + (x - 1) * font_width % inner_width);
1521 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1522 inner_sy + (y - 1) * font_height % inner_height);
1526 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1527 dst_x - src_x, dst_y - src_y);
1528 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1532 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1536 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1538 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1539 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1540 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1541 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1542 boolean no_delay = (tape.warp_forward);
1543 unsigned long anim_delay = 0;
1544 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1545 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1546 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1547 int font_width = getFontWidth(font_nr);
1548 int font_height = getFontHeight(font_nr);
1549 int max_xsize = level.envelope[envelope_nr].xsize;
1550 int max_ysize = level.envelope[envelope_nr].ysize;
1551 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1552 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1553 int xend = max_xsize;
1554 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1555 int xstep = (xstart < xend ? 1 : 0);
1556 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1559 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1561 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1562 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1563 int sx = (SXSIZE - xsize * font_width) / 2;
1564 int sy = (SYSIZE - ysize * font_height) / 2;
1567 SetDrawtoField(DRAW_BUFFERED);
1569 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1571 SetDrawtoField(DRAW_BACKBUFFER);
1573 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1574 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1576 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1577 level.envelope[envelope_nr].text, font_nr, max_xsize,
1578 xsize - 2, ysize - 2, mask_mode);
1580 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1583 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1587 void ShowEnvelope(int envelope_nr)
1589 int element = EL_ENVELOPE_1 + envelope_nr;
1590 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1591 int sound_opening = element_info[element].sound[ACTION_OPENING];
1592 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1593 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1594 boolean no_delay = (tape.warp_forward);
1595 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1596 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1597 int anim_mode = graphic_info[graphic].anim_mode;
1598 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1599 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1601 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1603 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1605 if (anim_mode == ANIM_DEFAULT)
1606 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1608 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1611 Delay(wait_delay_value);
1613 WaitForEventToContinue();
1615 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1617 if (anim_mode != ANIM_NONE)
1618 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1620 if (anim_mode == ANIM_DEFAULT)
1621 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1623 game.envelope_active = FALSE;
1625 SetDrawtoField(DRAW_BUFFERED);
1627 redraw_mask |= REDRAW_FIELD;
1631 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1636 int width_mult, width_div;
1637 int height_mult, height_div;
1645 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1646 5 - log_2(tilesize));
1647 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1648 int width_mult = offset_calc[offset_calc_pos].width_mult;
1649 int width_div = offset_calc[offset_calc_pos].width_div;
1650 int height_mult = offset_calc[offset_calc_pos].height_mult;
1651 int height_div = offset_calc[offset_calc_pos].height_div;
1652 int mini_startx = src_bitmap->width * width_mult / width_div;
1653 int mini_starty = src_bitmap->height * height_mult / height_div;
1654 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1655 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1657 *bitmap = src_bitmap;
1662 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1666 int graphic = el2preimg(element);
1668 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1669 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1676 SetDrawBackgroundMask(REDRAW_NONE);
1679 for (x = BX1; x <= BX2; x++)
1680 for (y = BY1; y <= BY2; y++)
1681 DrawScreenField(x, y);
1683 redraw_mask |= REDRAW_FIELD;
1686 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1690 for (x = 0; x < size_x; x++)
1691 for (y = 0; y < size_y; y++)
1692 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1694 redraw_mask |= REDRAW_FIELD;
1697 static void DrawPreviewLevelExt(int from_x, int from_y)
1699 boolean show_level_border = (BorderElement != EL_EMPTY);
1700 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1701 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1702 int tile_size = preview.tile_size;
1703 int preview_width = preview.xsize * tile_size;
1704 int preview_height = preview.ysize * tile_size;
1705 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1706 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1707 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1708 int dst_y = SY + preview.y;
1711 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1713 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1714 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1716 for (x = 0; x < real_preview_xsize; x++)
1718 for (y = 0; y < real_preview_ysize; y++)
1720 int lx = from_x + x + (show_level_border ? -1 : 0);
1721 int ly = from_y + y + (show_level_border ? -1 : 0);
1722 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1723 getBorderElement(lx, ly));
1725 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1726 element, tile_size);
1730 redraw_mask |= REDRAW_MICROLEVEL;
1733 #define MICROLABEL_EMPTY 0
1734 #define MICROLABEL_LEVEL_NAME 1
1735 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1736 #define MICROLABEL_LEVEL_AUTHOR 3
1737 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1738 #define MICROLABEL_IMPORTED_FROM 5
1739 #define MICROLABEL_IMPORTED_BY_HEAD 6
1740 #define MICROLABEL_IMPORTED_BY 7
1742 static int getMaxTextLength(struct MenuPosInfo *pos, int font_nr)
1744 int max_text_width = SXSIZE;
1745 int font_width = getFontWidth(font_nr);
1747 if (pos->align == ALIGN_CENTER)
1748 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1749 else if (pos->align == ALIGN_RIGHT)
1750 max_text_width = pos->x;
1752 max_text_width = SXSIZE - pos->x;
1754 return max_text_width / font_width;
1757 static void DrawPreviewLevelLabelExt(int mode)
1759 struct MenuPosInfo *pos = &menu.main.text.level_info_2;
1760 char label_text[MAX_OUTPUT_LINESIZE + 1];
1761 int max_len_label_text;
1762 int font_nr = FONT_TEXT_2;
1765 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1766 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1767 mode == MICROLABEL_IMPORTED_BY_HEAD)
1768 font_nr = FONT_TEXT_3;
1771 max_len_label_text = getMaxTextLength(pos, font_nr);
1773 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1776 for (i = 0; i < max_len_label_text; i++)
1777 label_text[i] = ' ';
1778 label_text[max_len_label_text] = '\0';
1780 if (strlen(label_text) > 0)
1783 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1785 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1786 int lypos = MICROLABEL2_YPOS;
1788 DrawText(lxpos, lypos, label_text, font_nr);
1793 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1794 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1795 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1796 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1797 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1798 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1799 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1800 max_len_label_text);
1801 label_text[max_len_label_text] = '\0';
1803 if (strlen(label_text) > 0)
1806 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1808 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1809 int lypos = MICROLABEL2_YPOS;
1811 DrawText(lxpos, lypos, label_text, font_nr);
1815 redraw_mask |= REDRAW_MICROLEVEL;
1818 void DrawPreviewLevel(boolean restart)
1820 static unsigned long scroll_delay = 0;
1821 static unsigned long label_delay = 0;
1822 static int from_x, from_y, scroll_direction;
1823 static int label_state, label_counter;
1824 unsigned long scroll_delay_value = preview.step_delay;
1825 boolean show_level_border = (BorderElement != EL_EMPTY);
1826 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1827 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1828 int last_game_status = game_status; /* save current game status */
1830 /* force PREVIEW font on preview level */
1831 game_status = GAME_MODE_PSEUDO_PREVIEW;
1838 if (preview.anim_mode == ANIM_CENTERED)
1840 if (level_xsize > preview.xsize)
1841 from_x = (level_xsize - preview.xsize) / 2;
1842 if (level_ysize > preview.ysize)
1843 from_y = (level_ysize - preview.ysize) / 2;
1846 from_x += preview.xoffset;
1847 from_y += preview.yoffset;
1849 scroll_direction = MV_RIGHT;
1853 DrawPreviewLevelExt(from_x, from_y);
1854 DrawPreviewLevelLabelExt(label_state);
1856 /* initialize delay counters */
1857 DelayReached(&scroll_delay, 0);
1858 DelayReached(&label_delay, 0);
1860 if (leveldir_current->name)
1862 struct MenuPosInfo *pos = &menu.main.text.level_info_1;
1863 char label_text[MAX_OUTPUT_LINESIZE + 1];
1864 int font_nr = FONT_TEXT_1;
1866 int max_len_label_text = getMaxTextLength(pos, font_nr);
1868 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1875 strncpy(label_text, leveldir_current->name, max_len_label_text);
1876 label_text[max_len_label_text] = '\0';
1879 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1881 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1882 lypos = SY + MICROLABEL1_YPOS;
1884 DrawText(lxpos, lypos, label_text, font_nr);
1888 game_status = last_game_status; /* restore current game status */
1893 /* scroll preview level, if needed */
1894 if (preview.anim_mode != ANIM_NONE &&
1895 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1896 DelayReached(&scroll_delay, scroll_delay_value))
1898 switch (scroll_direction)
1903 from_x -= preview.step_offset;
1904 from_x = (from_x < 0 ? 0 : from_x);
1907 scroll_direction = MV_UP;
1911 if (from_x < level_xsize - preview.xsize)
1913 from_x += preview.step_offset;
1914 from_x = (from_x > level_xsize - preview.xsize ?
1915 level_xsize - preview.xsize : from_x);
1918 scroll_direction = MV_DOWN;
1924 from_y -= preview.step_offset;
1925 from_y = (from_y < 0 ? 0 : from_y);
1928 scroll_direction = MV_RIGHT;
1932 if (from_y < level_ysize - preview.ysize)
1934 from_y += preview.step_offset;
1935 from_y = (from_y > level_ysize - preview.ysize ?
1936 level_ysize - preview.ysize : from_y);
1939 scroll_direction = MV_LEFT;
1946 DrawPreviewLevelExt(from_x, from_y);
1949 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1950 /* redraw micro level label, if needed */
1951 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1952 !strEqual(level.author, ANONYMOUS_NAME) &&
1953 !strEqual(level.author, leveldir_current->name) &&
1954 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1956 int max_label_counter = 23;
1958 if (leveldir_current->imported_from != NULL &&
1959 strlen(leveldir_current->imported_from) > 0)
1960 max_label_counter += 14;
1961 if (leveldir_current->imported_by != NULL &&
1962 strlen(leveldir_current->imported_by) > 0)
1963 max_label_counter += 14;
1965 label_counter = (label_counter + 1) % max_label_counter;
1966 label_state = (label_counter >= 0 && label_counter <= 7 ?
1967 MICROLABEL_LEVEL_NAME :
1968 label_counter >= 9 && label_counter <= 12 ?
1969 MICROLABEL_LEVEL_AUTHOR_HEAD :
1970 label_counter >= 14 && label_counter <= 21 ?
1971 MICROLABEL_LEVEL_AUTHOR :
1972 label_counter >= 23 && label_counter <= 26 ?
1973 MICROLABEL_IMPORTED_FROM_HEAD :
1974 label_counter >= 28 && label_counter <= 35 ?
1975 MICROLABEL_IMPORTED_FROM :
1976 label_counter >= 37 && label_counter <= 40 ?
1977 MICROLABEL_IMPORTED_BY_HEAD :
1978 label_counter >= 42 && label_counter <= 49 ?
1979 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1981 if (leveldir_current->imported_from == NULL &&
1982 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1983 label_state == MICROLABEL_IMPORTED_FROM))
1984 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1985 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1987 DrawPreviewLevelLabelExt(label_state);
1990 game_status = last_game_status; /* restore current game status */
1993 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1994 int graphic, int sync_frame, int mask_mode)
1996 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1998 if (mask_mode == USE_MASKING)
1999 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2001 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2004 inline void DrawGraphicAnimation(int x, int y, int graphic)
2006 int lx = LEVELX(x), ly = LEVELY(y);
2008 if (!IN_SCR_FIELD(x, y))
2011 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2012 graphic, GfxFrame[lx][ly], NO_MASKING);
2013 MarkTileDirty(x, y);
2016 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2018 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2021 void DrawLevelElementAnimation(int x, int y, int element)
2023 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2025 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2028 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2030 int sx = SCREENX(x), sy = SCREENY(y);
2032 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2035 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2038 DrawGraphicAnimation(sx, sy, graphic);
2041 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2042 DrawLevelFieldCrumbledSand(x, y);
2044 if (GFX_CRUMBLED(Feld[x][y]))
2045 DrawLevelFieldCrumbledSand(x, y);
2049 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2051 int sx = SCREENX(x), sy = SCREENY(y);
2054 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2057 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2059 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2062 DrawGraphicAnimation(sx, sy, graphic);
2064 if (GFX_CRUMBLED(element))
2065 DrawLevelFieldCrumbledSand(x, y);
2068 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2070 if (player->use_murphy)
2072 /* this works only because currently only one player can be "murphy" ... */
2073 static int last_horizontal_dir = MV_LEFT;
2074 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2076 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2077 last_horizontal_dir = move_dir;
2079 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2081 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2083 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2089 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2092 static boolean equalGraphics(int graphic1, int graphic2)
2094 struct GraphicInfo *g1 = &graphic_info[graphic1];
2095 struct GraphicInfo *g2 = &graphic_info[graphic2];
2097 return (g1->bitmap == g2->bitmap &&
2098 g1->src_x == g2->src_x &&
2099 g1->src_y == g2->src_y &&
2100 g1->anim_frames == g2->anim_frames &&
2101 g1->anim_delay == g2->anim_delay &&
2102 g1->anim_mode == g2->anim_mode);
2105 void DrawAllPlayers()
2109 for (i = 0; i < MAX_PLAYERS; i++)
2110 if (stored_player[i].active)
2111 DrawPlayer(&stored_player[i]);
2114 void DrawPlayerField(int x, int y)
2116 if (!IS_PLAYER(x, y))
2119 DrawPlayer(PLAYERINFO(x, y));
2122 void DrawPlayer(struct PlayerInfo *player)
2124 int jx = player->jx;
2125 int jy = player->jy;
2126 int move_dir = player->MovDir;
2127 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2128 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2129 int last_jx = (player->is_moving ? jx - dx : jx);
2130 int last_jy = (player->is_moving ? jy - dy : jy);
2131 int next_jx = jx + dx;
2132 int next_jy = jy + dy;
2133 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2134 boolean player_is_opaque = FALSE;
2135 int sx = SCREENX(jx), sy = SCREENY(jy);
2136 int sxx = 0, syy = 0;
2137 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2139 int action = ACTION_DEFAULT;
2140 int last_player_graphic = getPlayerGraphic(player, move_dir);
2141 int last_player_frame = player->Frame;
2144 /* GfxElement[][] is set to the element the player is digging or collecting;
2145 remove also for off-screen player if the player is not moving anymore */
2146 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2147 GfxElement[jx][jy] = EL_UNDEFINED;
2149 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2153 if (!IN_LEV_FIELD(jx, jy))
2155 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2156 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2157 printf("DrawPlayerField(): This should never happen!\n");
2162 if (element == EL_EXPLOSION)
2165 action = (player->is_pushing ? ACTION_PUSHING :
2166 player->is_digging ? ACTION_DIGGING :
2167 player->is_collecting ? ACTION_COLLECTING :
2168 player->is_moving ? ACTION_MOVING :
2169 player->is_snapping ? ACTION_SNAPPING :
2170 player->is_dropping ? ACTION_DROPPING :
2171 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2173 if (player->is_waiting)
2174 move_dir = player->dir_waiting;
2176 InitPlayerGfxAnimation(player, action, move_dir);
2178 /* ----------------------------------------------------------------------- */
2179 /* draw things in the field the player is leaving, if needed */
2180 /* ----------------------------------------------------------------------- */
2182 if (player->is_moving)
2184 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2186 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2188 if (last_element == EL_DYNAMITE_ACTIVE ||
2189 last_element == EL_EM_DYNAMITE_ACTIVE ||
2190 last_element == EL_SP_DISK_RED_ACTIVE)
2191 DrawDynamite(last_jx, last_jy);
2193 DrawLevelFieldThruMask(last_jx, last_jy);
2195 else if (last_element == EL_DYNAMITE_ACTIVE ||
2196 last_element == EL_EM_DYNAMITE_ACTIVE ||
2197 last_element == EL_SP_DISK_RED_ACTIVE)
2198 DrawDynamite(last_jx, last_jy);
2200 /* !!! this is not enough to prevent flickering of players which are
2201 moving next to each others without a free tile between them -- this
2202 can only be solved by drawing all players layer by layer (first the
2203 background, then the foreground etc.) !!! => TODO */
2204 else if (!IS_PLAYER(last_jx, last_jy))
2205 DrawLevelField(last_jx, last_jy);
2208 DrawLevelField(last_jx, last_jy);
2211 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2212 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2215 if (!IN_SCR_FIELD(sx, sy))
2218 if (setup.direct_draw)
2219 SetDrawtoField(DRAW_BUFFERED);
2221 /* ----------------------------------------------------------------------- */
2222 /* draw things behind the player, if needed */
2223 /* ----------------------------------------------------------------------- */
2226 DrawLevelElement(jx, jy, Back[jx][jy]);
2227 else if (IS_ACTIVE_BOMB(element))
2228 DrawLevelElement(jx, jy, EL_EMPTY);
2231 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2233 int old_element = GfxElement[jx][jy];
2234 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2235 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2237 if (GFX_CRUMBLED(old_element))
2238 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2240 DrawGraphic(sx, sy, old_graphic, frame);
2242 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2243 player_is_opaque = TRUE;
2247 GfxElement[jx][jy] = EL_UNDEFINED;
2249 /* make sure that pushed elements are drawn with correct frame rate */
2251 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2253 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2254 GfxFrame[jx][jy] = player->StepFrame;
2256 if (player->is_pushing && player->is_moving)
2257 GfxFrame[jx][jy] = player->StepFrame;
2260 DrawLevelField(jx, jy);
2264 /* ----------------------------------------------------------------------- */
2265 /* draw player himself */
2266 /* ----------------------------------------------------------------------- */
2268 graphic = getPlayerGraphic(player, move_dir);
2270 /* in the case of changed player action or direction, prevent the current
2271 animation frame from being restarted for identical animations */
2272 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2273 player->Frame = last_player_frame;
2275 frame = getGraphicAnimationFrame(graphic, player->Frame);
2279 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2280 sxx = player->GfxPos;
2282 syy = player->GfxPos;
2285 if (!setup.soft_scrolling && ScreenMovPos)
2288 if (player_is_opaque)
2289 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2291 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2293 if (SHIELD_ON(player))
2295 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2296 IMG_SHIELD_NORMAL_ACTIVE);
2297 int frame = getGraphicAnimationFrame(graphic, -1);
2299 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2302 /* ----------------------------------------------------------------------- */
2303 /* draw things the player is pushing, if needed */
2304 /* ----------------------------------------------------------------------- */
2307 printf("::: %d, %d [%d, %d] [%d]\n",
2308 player->is_pushing, player_is_moving, player->GfxAction,
2309 player->is_moving, player_is_moving);
2313 if (player->is_pushing && player->is_moving)
2315 int px = SCREENX(jx), py = SCREENY(jy);
2316 int pxx = (TILEX - ABS(sxx)) * dx;
2317 int pyy = (TILEY - ABS(syy)) * dy;
2318 int gfx_frame = GfxFrame[jx][jy];
2324 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2326 element = Feld[next_jx][next_jy];
2327 gfx_frame = GfxFrame[next_jx][next_jy];
2330 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2333 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2334 frame = getGraphicAnimationFrame(graphic, sync_frame);
2336 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2339 /* draw background element under pushed element (like the Sokoban field) */
2340 if (Back[next_jx][next_jy])
2341 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2343 /* masked drawing is needed for EMC style (double) movement graphics */
2344 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2348 /* ----------------------------------------------------------------------- */
2349 /* draw things in front of player (active dynamite or dynabombs) */
2350 /* ----------------------------------------------------------------------- */
2352 if (IS_ACTIVE_BOMB(element))
2354 graphic = el2img(element);
2355 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2357 if (game.emulation == EMU_SUPAPLEX)
2358 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2360 DrawGraphicThruMask(sx, sy, graphic, frame);
2363 if (player_is_moving && last_element == EL_EXPLOSION)
2365 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2366 GfxElement[last_jx][last_jy] : EL_EMPTY);
2367 int graphic = el_act2img(element, ACTION_EXPLODING);
2368 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2369 int phase = ExplodePhase[last_jx][last_jy] - 1;
2370 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2373 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2376 /* ----------------------------------------------------------------------- */
2377 /* draw elements the player is just walking/passing through/under */
2378 /* ----------------------------------------------------------------------- */
2380 if (player_is_moving)
2382 /* handle the field the player is leaving ... */
2383 if (IS_ACCESSIBLE_INSIDE(last_element))
2384 DrawLevelField(last_jx, last_jy);
2385 else if (IS_ACCESSIBLE_UNDER(last_element))
2386 DrawLevelFieldThruMask(last_jx, last_jy);
2389 /* do not redraw accessible elements if the player is just pushing them */
2390 if (!player_is_moving || !player->is_pushing)
2392 /* ... and the field the player is entering */
2393 if (IS_ACCESSIBLE_INSIDE(element))
2394 DrawLevelField(jx, jy);
2395 else if (IS_ACCESSIBLE_UNDER(element))
2396 DrawLevelFieldThruMask(jx, jy);
2399 if (setup.direct_draw)
2401 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2402 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2403 int x_size = TILEX * (1 + ABS(jx - last_jx));
2404 int y_size = TILEY * (1 + ABS(jy - last_jy));
2406 BlitBitmap(drawto_field, window,
2407 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2408 SetDrawtoField(DRAW_DIRECT);
2411 MarkTileDirty(sx, sy);
2414 /* ------------------------------------------------------------------------- */
2416 void WaitForEventToContinue()
2418 boolean still_wait = TRUE;
2420 /* simulate releasing mouse button over last gadget, if still pressed */
2422 HandleGadgets(-1, -1, 0);
2424 button_status = MB_RELEASED;
2440 case EVENT_BUTTONPRESS:
2441 case EVENT_KEYPRESS:
2445 case EVENT_KEYRELEASE:
2446 ClearPlayerAction();
2450 HandleOtherEvents(&event);
2454 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2461 /* don't eat all CPU time */
2466 #define MAX_REQUEST_LINES 13
2467 #define MAX_REQUEST_LINE_FONT1_LEN 7
2468 #define MAX_REQUEST_LINE_FONT2_LEN 10
2470 boolean Request(char *text, unsigned int req_state)
2472 int mx, my, ty, result = -1;
2473 unsigned int old_door_state;
2474 int last_game_status = game_status; /* save current game status */
2475 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2476 int font_nr = FONT_TEXT_2;
2477 int max_word_len = 0;
2480 for (text_ptr = text; *text_ptr; text_ptr++)
2482 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2484 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2486 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2487 font_nr = FONT_LEVEL_NUMBER;
2493 if (game_status == GAME_MODE_PLAYING &&
2494 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2495 BlitScreenToBitmap_EM(backbuffer);
2497 /* disable deactivated drawing when quick-loading level tape recording */
2498 if (tape.playing && tape.deactivate_display)
2499 TapeDeactivateDisplayOff(TRUE);
2501 SetMouseCursor(CURSOR_DEFAULT);
2503 #if defined(NETWORK_AVALIABLE)
2504 /* pause network game while waiting for request to answer */
2505 if (options.network &&
2506 game_status == GAME_MODE_PLAYING &&
2507 req_state & REQUEST_WAIT_FOR_INPUT)
2508 SendToServer_PausePlaying();
2511 old_door_state = GetDoorState();
2513 /* simulate releasing mouse button over last gadget, if still pressed */
2515 HandleGadgets(-1, -1, 0);
2519 if (old_door_state & DOOR_OPEN_1)
2521 CloseDoor(DOOR_CLOSE_1);
2523 /* save old door content */
2524 BlitBitmap(bitmap_db_door, bitmap_db_door,
2525 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2526 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2530 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2533 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2535 /* clear door drawing field */
2536 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2538 /* force DOOR font on preview level */
2539 game_status = GAME_MODE_PSEUDO_DOOR;
2541 /* write text for request */
2542 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2544 char text_line[max_request_line_len + 1];
2550 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2553 if (!tc || tc == ' ')
2564 strncpy(text_line, text, tl);
2567 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2568 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2569 text_line, font_nr);
2571 text += tl + (tc == ' ' ? 1 : 0);
2574 game_status = last_game_status; /* restore current game status */
2576 if (req_state & REQ_ASK)
2578 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2579 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2581 else if (req_state & REQ_CONFIRM)
2583 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2585 else if (req_state & REQ_PLAYER)
2587 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2588 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2589 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2590 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2593 /* copy request gadgets to door backbuffer */
2594 BlitBitmap(drawto, bitmap_db_door,
2595 DX, DY, DXSIZE, DYSIZE,
2596 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2598 OpenDoor(DOOR_OPEN_1);
2600 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2602 if (game_status == GAME_MODE_PLAYING)
2604 SetPanelBackground();
2605 SetDrawBackgroundMask(REDRAW_DOOR_1);
2609 SetDrawBackgroundMask(REDRAW_FIELD);
2615 if (game_status != GAME_MODE_MAIN)
2618 button_status = MB_RELEASED;
2620 request_gadget_id = -1;
2622 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2634 case EVENT_BUTTONPRESS:
2635 case EVENT_BUTTONRELEASE:
2636 case EVENT_MOTIONNOTIFY:
2638 if (event.type == EVENT_MOTIONNOTIFY)
2640 if (!PointerInWindow(window))
2641 continue; /* window and pointer are on different screens */
2646 motion_status = TRUE;
2647 mx = ((MotionEvent *) &event)->x;
2648 my = ((MotionEvent *) &event)->y;
2652 motion_status = FALSE;
2653 mx = ((ButtonEvent *) &event)->x;
2654 my = ((ButtonEvent *) &event)->y;
2655 if (event.type == EVENT_BUTTONPRESS)
2656 button_status = ((ButtonEvent *) &event)->button;
2658 button_status = MB_RELEASED;
2661 /* this sets 'request_gadget_id' */
2662 HandleGadgets(mx, my, button_status);
2664 switch (request_gadget_id)
2666 case TOOL_CTRL_ID_YES:
2669 case TOOL_CTRL_ID_NO:
2672 case TOOL_CTRL_ID_CONFIRM:
2673 result = TRUE | FALSE;
2676 case TOOL_CTRL_ID_PLAYER_1:
2679 case TOOL_CTRL_ID_PLAYER_2:
2682 case TOOL_CTRL_ID_PLAYER_3:
2685 case TOOL_CTRL_ID_PLAYER_4:
2696 case EVENT_KEYPRESS:
2697 switch (GetEventKey((KeyEvent *)&event, TRUE))
2710 if (req_state & REQ_PLAYER)
2714 case EVENT_KEYRELEASE:
2715 ClearPlayerAction();
2719 HandleOtherEvents(&event);
2723 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2725 int joy = AnyJoystick();
2727 if (joy & JOY_BUTTON_1)
2729 else if (joy & JOY_BUTTON_2)
2736 if (!PendingEvent()) /* delay only if no pending events */
2739 /* don't eat all CPU time */
2744 if (game_status != GAME_MODE_MAIN)
2749 if (!(req_state & REQ_STAY_OPEN))
2751 CloseDoor(DOOR_CLOSE_1);
2753 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2754 (req_state & REQ_REOPEN))
2755 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2760 if (game_status == GAME_MODE_PLAYING)
2762 SetPanelBackground();
2763 SetDrawBackgroundMask(REDRAW_DOOR_1);
2767 SetDrawBackgroundMask(REDRAW_FIELD);
2770 #if defined(NETWORK_AVALIABLE)
2771 /* continue network game after request */
2772 if (options.network &&
2773 game_status == GAME_MODE_PLAYING &&
2774 req_state & REQUEST_WAIT_FOR_INPUT)
2775 SendToServer_ContinuePlaying();
2778 /* restore deactivated drawing when quick-loading level tape recording */
2779 if (tape.playing && tape.deactivate_display)
2780 TapeDeactivateDisplayOn();
2785 unsigned int OpenDoor(unsigned int door_state)
2787 if (door_state & DOOR_COPY_BACK)
2789 if (door_state & DOOR_OPEN_1)
2790 BlitBitmap(bitmap_db_door, bitmap_db_door,
2791 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2792 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2794 if (door_state & DOOR_OPEN_2)
2795 BlitBitmap(bitmap_db_door, bitmap_db_door,
2796 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2797 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2799 door_state &= ~DOOR_COPY_BACK;
2802 return MoveDoor(door_state);
2805 unsigned int CloseDoor(unsigned int door_state)
2807 unsigned int old_door_state = GetDoorState();
2809 if (!(door_state & DOOR_NO_COPY_BACK))
2811 if (old_door_state & DOOR_OPEN_1)
2812 BlitBitmap(backbuffer, bitmap_db_door,
2813 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2815 if (old_door_state & DOOR_OPEN_2)
2816 BlitBitmap(backbuffer, bitmap_db_door,
2817 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2819 door_state &= ~DOOR_NO_COPY_BACK;
2822 return MoveDoor(door_state);
2825 unsigned int GetDoorState()
2827 return MoveDoor(DOOR_GET_STATE);
2830 unsigned int SetDoorState(unsigned int door_state)
2832 return MoveDoor(door_state | DOOR_SET_STATE);
2835 unsigned int MoveDoor(unsigned int door_state)
2837 static int door1 = DOOR_OPEN_1;
2838 static int door2 = DOOR_CLOSE_2;
2839 unsigned long door_delay = 0;
2840 unsigned long door_delay_value;
2843 if (door_1.width < 0 || door_1.width > DXSIZE)
2844 door_1.width = DXSIZE;
2845 if (door_1.height < 0 || door_1.height > DYSIZE)
2846 door_1.height = DYSIZE;
2847 if (door_2.width < 0 || door_2.width > VXSIZE)
2848 door_2.width = VXSIZE;
2849 if (door_2.height < 0 || door_2.height > VYSIZE)
2850 door_2.height = VYSIZE;
2852 if (door_state == DOOR_GET_STATE)
2853 return (door1 | door2);
2855 if (door_state & DOOR_SET_STATE)
2857 if (door_state & DOOR_ACTION_1)
2858 door1 = door_state & DOOR_ACTION_1;
2859 if (door_state & DOOR_ACTION_2)
2860 door2 = door_state & DOOR_ACTION_2;
2862 return (door1 | door2);
2865 if (!(door_state & DOOR_FORCE_REDRAW))
2867 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2868 door_state &= ~DOOR_OPEN_1;
2869 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2870 door_state &= ~DOOR_CLOSE_1;
2871 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2872 door_state &= ~DOOR_OPEN_2;
2873 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2874 door_state &= ~DOOR_CLOSE_2;
2877 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2880 if (setup.quick_doors)
2882 stepsize = 20; /* must be choosen to always draw last frame */
2883 door_delay_value = 0;
2886 if (global.autoplay_leveldir)
2888 door_state |= DOOR_NO_DELAY;
2889 door_state &= ~DOOR_CLOSE_ALL;
2892 if (door_state & DOOR_ACTION)
2894 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2895 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2896 boolean door_1_done = (!handle_door_1);
2897 boolean door_2_done = (!handle_door_2);
2898 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2899 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2900 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2901 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2902 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2903 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2904 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2905 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2906 int door_skip = max_door_size - door_size;
2907 int end = door_size;
2908 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2911 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2913 /* opening door sound has priority over simultaneously closing door */
2914 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2915 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2916 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2917 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2920 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2923 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2924 GC gc = bitmap->stored_clip_gc;
2926 if (door_state & DOOR_ACTION_1)
2928 int a = MIN(x * door_1.step_offset, end);
2929 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2930 int i = p + door_skip;
2932 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2934 BlitBitmap(bitmap_db_door, drawto,
2935 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2936 DXSIZE, DYSIZE, DX, DY);
2940 BlitBitmap(bitmap_db_door, drawto,
2941 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2942 DXSIZE, DYSIZE - p / 2, DX, DY);
2944 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2947 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2949 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2950 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2951 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2952 int dst2_x = DX, dst2_y = DY;
2953 int width = i, height = DYSIZE;
2955 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2956 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2959 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2960 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2963 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2965 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2966 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2967 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2968 int dst2_x = DX, dst2_y = DY;
2969 int width = DXSIZE, height = i;
2971 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2972 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2975 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2976 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2979 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2981 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2983 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2984 BlitBitmapMasked(bitmap, drawto,
2985 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2986 DX + DXSIZE - i, DY + j);
2987 BlitBitmapMasked(bitmap, drawto,
2988 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2989 DX + DXSIZE - i, DY + 140 + j);
2990 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2991 DY - (DOOR_GFX_PAGEY1 + j));
2992 BlitBitmapMasked(bitmap, drawto,
2993 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2995 BlitBitmapMasked(bitmap, drawto,
2996 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2999 BlitBitmapMasked(bitmap, drawto,
3000 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3002 BlitBitmapMasked(bitmap, drawto,
3003 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3005 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3006 BlitBitmapMasked(bitmap, drawto,
3007 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3008 DX + DXSIZE - i, DY + 77 + j);
3009 BlitBitmapMasked(bitmap, drawto,
3010 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3011 DX + DXSIZE - i, DY + 203 + j);
3014 redraw_mask |= REDRAW_DOOR_1;
3015 door_1_done = (a == end);
3018 if (door_state & DOOR_ACTION_2)
3020 int a = MIN(x * door_2.step_offset, door_size);
3021 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3022 int i = p + door_skip;
3024 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3026 BlitBitmap(bitmap_db_door, drawto,
3027 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3028 VXSIZE, VYSIZE, VX, VY);
3030 else if (x <= VYSIZE)
3032 BlitBitmap(bitmap_db_door, drawto,
3033 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3034 VXSIZE, VYSIZE - p / 2, VX, VY);
3036 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3039 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3041 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3042 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3043 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3044 int dst2_x = VX, dst2_y = VY;
3045 int width = i, height = VYSIZE;
3047 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3048 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3051 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3052 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3055 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3057 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3058 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3059 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3060 int dst2_x = VX, dst2_y = VY;
3061 int width = VXSIZE, height = i;
3063 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3064 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3067 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3068 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3071 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3073 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3075 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3076 BlitBitmapMasked(bitmap, drawto,
3077 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3078 VX + VXSIZE - i, VY + j);
3079 SetClipOrigin(bitmap, gc,
3080 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3081 BlitBitmapMasked(bitmap, drawto,
3082 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3085 BlitBitmapMasked(bitmap, drawto,
3086 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3087 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3088 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3089 BlitBitmapMasked(bitmap, drawto,
3090 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3092 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3095 redraw_mask |= REDRAW_DOOR_2;
3096 door_2_done = (a == VXSIZE);
3099 if (!(door_state & DOOR_NO_DELAY))
3103 if (game_status == GAME_MODE_MAIN)
3106 WaitUntilDelayReached(&door_delay, door_delay_value);
3111 if (door_state & DOOR_ACTION_1)
3112 door1 = door_state & DOOR_ACTION_1;
3113 if (door_state & DOOR_ACTION_2)
3114 door2 = door_state & DOOR_ACTION_2;
3116 return (door1 | door2);
3119 void DrawSpecialEditorDoor()
3121 /* draw bigger toolbox window */
3122 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3123 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3125 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3126 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3129 redraw_mask |= REDRAW_ALL;
3132 void UndrawSpecialEditorDoor()
3134 /* draw normal tape recorder window */
3135 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3136 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3139 redraw_mask |= REDRAW_ALL;
3143 /* ---------- new tool button stuff ---------------------------------------- */
3145 /* graphic position values for tool buttons */
3146 #define TOOL_BUTTON_YES_XPOS 2
3147 #define TOOL_BUTTON_YES_YPOS 250
3148 #define TOOL_BUTTON_YES_GFX_YPOS 0
3149 #define TOOL_BUTTON_YES_XSIZE 46
3150 #define TOOL_BUTTON_YES_YSIZE 28
3151 #define TOOL_BUTTON_NO_XPOS 52
3152 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3153 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3154 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3155 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3156 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3157 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3158 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3159 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3160 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3161 #define TOOL_BUTTON_PLAYER_XSIZE 30
3162 #define TOOL_BUTTON_PLAYER_YSIZE 30
3163 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3164 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3165 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3166 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3167 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3168 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3169 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3170 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3171 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3172 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3173 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3174 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3175 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3176 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3177 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3178 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3179 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3180 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3181 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3182 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3191 } toolbutton_info[NUM_TOOL_BUTTONS] =
3194 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3195 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3196 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3201 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3202 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3203 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3208 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3209 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3210 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3211 TOOL_CTRL_ID_CONFIRM,
3215 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3216 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3217 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3218 TOOL_CTRL_ID_PLAYER_1,
3222 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3223 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3224 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3225 TOOL_CTRL_ID_PLAYER_2,
3229 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3230 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3231 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3232 TOOL_CTRL_ID_PLAYER_3,
3236 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3237 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3238 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3239 TOOL_CTRL_ID_PLAYER_4,
3244 void CreateToolButtons()
3248 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3250 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3251 Bitmap *deco_bitmap = None;
3252 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3253 struct GadgetInfo *gi;
3254 unsigned long event_mask;
3255 int gd_xoffset, gd_yoffset;
3256 int gd_x1, gd_x2, gd_y;
3259 event_mask = GD_EVENT_RELEASED;
3261 gd_xoffset = toolbutton_info[i].xpos;
3262 gd_yoffset = toolbutton_info[i].ypos;
3263 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3264 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3265 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3267 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3269 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3271 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3272 &deco_bitmap, &deco_x, &deco_y);
3273 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3274 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3277 gi = CreateGadget(GDI_CUSTOM_ID, id,
3278 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3279 GDI_X, DX + toolbutton_info[i].x,
3280 GDI_Y, DY + toolbutton_info[i].y,
3281 GDI_WIDTH, toolbutton_info[i].width,
3282 GDI_HEIGHT, toolbutton_info[i].height,
3283 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3284 GDI_STATE, GD_BUTTON_UNPRESSED,
3285 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3286 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3287 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3288 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3289 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3290 GDI_DECORATION_SHIFTING, 1, 1,
3291 GDI_DIRECT_DRAW, FALSE,
3292 GDI_EVENT_MASK, event_mask,
3293 GDI_CALLBACK_ACTION, HandleToolButtons,
3297 Error(ERR_EXIT, "cannot create gadget");
3299 tool_gadget[id] = gi;
3303 void FreeToolButtons()
3307 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3308 FreeGadget(tool_gadget[i]);
3311 static void UnmapToolButtons()
3315 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3316 UnmapGadget(tool_gadget[i]);
3319 static void HandleToolButtons(struct GadgetInfo *gi)
3321 request_gadget_id = gi->custom_id;
3324 static struct Mapping_EM_to_RND_object
3327 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3328 boolean is_backside; /* backside of moving element */
3334 em_object_mapping_list[] =
3337 Xblank, TRUE, FALSE,
3341 Yacid_splash_eB, FALSE, FALSE,
3342 EL_ACID_SPLASH_RIGHT, -1, -1
3345 Yacid_splash_wB, FALSE, FALSE,
3346 EL_ACID_SPLASH_LEFT, -1, -1
3349 #ifdef EM_ENGINE_BAD_ROLL
3351 Xstone_force_e, FALSE, FALSE,
3352 EL_ROCK, -1, MV_BIT_RIGHT
3355 Xstone_force_w, FALSE, FALSE,
3356 EL_ROCK, -1, MV_BIT_LEFT
3359 Xnut_force_e, FALSE, FALSE,
3360 EL_NUT, -1, MV_BIT_RIGHT
3363 Xnut_force_w, FALSE, FALSE,
3364 EL_NUT, -1, MV_BIT_LEFT
3367 Xspring_force_e, FALSE, FALSE,
3368 EL_SPRING, -1, MV_BIT_RIGHT
3371 Xspring_force_w, FALSE, FALSE,
3372 EL_SPRING, -1, MV_BIT_LEFT
3375 Xemerald_force_e, FALSE, FALSE,
3376 EL_EMERALD, -1, MV_BIT_RIGHT
3379 Xemerald_force_w, FALSE, FALSE,
3380 EL_EMERALD, -1, MV_BIT_LEFT
3383 Xdiamond_force_e, FALSE, FALSE,
3384 EL_DIAMOND, -1, MV_BIT_RIGHT
3387 Xdiamond_force_w, FALSE, FALSE,
3388 EL_DIAMOND, -1, MV_BIT_LEFT
3391 Xbomb_force_e, FALSE, FALSE,
3392 EL_BOMB, -1, MV_BIT_RIGHT
3395 Xbomb_force_w, FALSE, FALSE,
3396 EL_BOMB, -1, MV_BIT_LEFT
3398 #endif /* EM_ENGINE_BAD_ROLL */
3401 Xstone, TRUE, FALSE,
3405 Xstone_pause, FALSE, FALSE,
3409 Xstone_fall, FALSE, FALSE,
3413 Ystone_s, FALSE, FALSE,
3414 EL_ROCK, ACTION_FALLING, -1
3417 Ystone_sB, FALSE, TRUE,
3418 EL_ROCK, ACTION_FALLING, -1
3421 Ystone_e, FALSE, FALSE,
3422 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3425 Ystone_eB, FALSE, TRUE,
3426 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3429 Ystone_w, FALSE, FALSE,
3430 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3433 Ystone_wB, FALSE, TRUE,
3434 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3441 Xnut_pause, FALSE, FALSE,
3445 Xnut_fall, FALSE, FALSE,
3449 Ynut_s, FALSE, FALSE,
3450 EL_NUT, ACTION_FALLING, -1
3453 Ynut_sB, FALSE, TRUE,
3454 EL_NUT, ACTION_FALLING, -1
3457 Ynut_e, FALSE, FALSE,
3458 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3461 Ynut_eB, FALSE, TRUE,
3462 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3465 Ynut_w, FALSE, FALSE,
3466 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3469 Ynut_wB, FALSE, TRUE,
3470 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3473 Xbug_n, TRUE, FALSE,
3477 Xbug_e, TRUE, FALSE,
3478 EL_BUG_RIGHT, -1, -1
3481 Xbug_s, TRUE, FALSE,
3485 Xbug_w, TRUE, FALSE,
3489 Xbug_gon, FALSE, FALSE,
3493 Xbug_goe, FALSE, FALSE,
3494 EL_BUG_RIGHT, -1, -1
3497 Xbug_gos, FALSE, FALSE,
3501 Xbug_gow, FALSE, FALSE,
3505 Ybug_n, FALSE, FALSE,
3506 EL_BUG, ACTION_MOVING, MV_BIT_UP
3509 Ybug_nB, FALSE, TRUE,
3510 EL_BUG, ACTION_MOVING, MV_BIT_UP
3513 Ybug_e, FALSE, FALSE,
3514 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3517 Ybug_eB, FALSE, TRUE,
3518 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3521 Ybug_s, FALSE, FALSE,
3522 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3525 Ybug_sB, FALSE, TRUE,
3526 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3529 Ybug_w, FALSE, FALSE,
3530 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3533 Ybug_wB, FALSE, TRUE,
3534 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3537 Ybug_w_n, FALSE, FALSE,
3538 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3541 Ybug_n_e, FALSE, FALSE,
3542 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3545 Ybug_e_s, FALSE, FALSE,
3546 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3549 Ybug_s_w, FALSE, FALSE,
3550 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3553 Ybug_e_n, FALSE, FALSE,
3554 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3557 Ybug_s_e, FALSE, FALSE,
3558 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3561 Ybug_w_s, FALSE, FALSE,
3562 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3565 Ybug_n_w, FALSE, FALSE,
3566 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3569 Ybug_stone, FALSE, FALSE,
3570 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3573 Ybug_spring, FALSE, FALSE,
3574 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3577 Xtank_n, TRUE, FALSE,
3578 EL_SPACESHIP_UP, -1, -1
3581 Xtank_e, TRUE, FALSE,
3582 EL_SPACESHIP_RIGHT, -1, -1
3585 Xtank_s, TRUE, FALSE,
3586 EL_SPACESHIP_DOWN, -1, -1
3589 Xtank_w, TRUE, FALSE,
3590 EL_SPACESHIP_LEFT, -1, -1
3593 Xtank_gon, FALSE, FALSE,
3594 EL_SPACESHIP_UP, -1, -1
3597 Xtank_goe, FALSE, FALSE,
3598 EL_SPACESHIP_RIGHT, -1, -1
3601 Xtank_gos, FALSE, FALSE,
3602 EL_SPACESHIP_DOWN, -1, -1
3605 Xtank_gow, FALSE, FALSE,
3606 EL_SPACESHIP_LEFT, -1, -1
3609 Ytank_n, FALSE, FALSE,
3610 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3613 Ytank_nB, FALSE, TRUE,
3614 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3617 Ytank_e, FALSE, FALSE,
3618 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3621 Ytank_eB, FALSE, TRUE,
3622 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3625 Ytank_s, FALSE, FALSE,
3626 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3629 Ytank_sB, FALSE, TRUE,
3630 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3633 Ytank_w, FALSE, FALSE,
3634 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3637 Ytank_wB, FALSE, TRUE,
3638 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3641 Ytank_w_n, FALSE, FALSE,
3642 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3645 Ytank_n_e, FALSE, FALSE,
3646 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3649 Ytank_e_s, FALSE, FALSE,
3650 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3653 Ytank_s_w, FALSE, FALSE,
3654 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3657 Ytank_e_n, FALSE, FALSE,
3658 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3661 Ytank_s_e, FALSE, FALSE,
3662 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3665 Ytank_w_s, FALSE, FALSE,
3666 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3669 Ytank_n_w, FALSE, FALSE,
3670 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3673 Ytank_stone, FALSE, FALSE,
3674 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3677 Ytank_spring, FALSE, FALSE,
3678 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3681 Xandroid, TRUE, FALSE,
3682 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3685 Xandroid_1_n, FALSE, FALSE,
3686 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3689 Xandroid_2_n, FALSE, FALSE,
3690 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3693 Xandroid_1_e, FALSE, FALSE,
3694 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3697 Xandroid_2_e, FALSE, FALSE,
3698 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3701 Xandroid_1_w, FALSE, FALSE,
3702 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3705 Xandroid_2_w, FALSE, FALSE,
3706 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3709 Xandroid_1_s, FALSE, FALSE,
3710 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3713 Xandroid_2_s, FALSE, FALSE,
3714 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3717 Yandroid_n, FALSE, FALSE,
3718 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3721 Yandroid_nB, FALSE, TRUE,
3722 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3725 Yandroid_ne, FALSE, FALSE,
3726 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3729 Yandroid_neB, FALSE, TRUE,
3730 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3733 Yandroid_e, FALSE, FALSE,
3734 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3737 Yandroid_eB, FALSE, TRUE,
3738 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3741 Yandroid_se, FALSE, FALSE,
3742 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3745 Yandroid_seB, FALSE, TRUE,
3746 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3749 Yandroid_s, FALSE, FALSE,
3750 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3753 Yandroid_sB, FALSE, TRUE,
3754 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3757 Yandroid_sw, FALSE, FALSE,
3758 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3761 Yandroid_swB, FALSE, TRUE,
3762 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3765 Yandroid_w, FALSE, FALSE,
3766 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3769 Yandroid_wB, FALSE, TRUE,
3770 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3773 Yandroid_nw, FALSE, FALSE,
3774 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3777 Yandroid_nwB, FALSE, TRUE,
3778 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3781 Xspring, TRUE, FALSE,
3785 Xspring_pause, FALSE, FALSE,
3789 Xspring_e, FALSE, FALSE,
3793 Xspring_w, FALSE, FALSE,
3797 Xspring_fall, FALSE, FALSE,
3801 Yspring_s, FALSE, FALSE,
3802 EL_SPRING, ACTION_FALLING, -1
3805 Yspring_sB, FALSE, TRUE,
3806 EL_SPRING, ACTION_FALLING, -1
3809 Yspring_e, FALSE, FALSE,
3810 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3813 Yspring_eB, FALSE, TRUE,
3814 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3817 Yspring_w, FALSE, FALSE,
3818 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3821 Yspring_wB, FALSE, TRUE,
3822 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3825 Yspring_kill_e, FALSE, FALSE,
3826 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3829 Yspring_kill_eB, FALSE, TRUE,
3830 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3833 Yspring_kill_w, FALSE, FALSE,
3834 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3837 Yspring_kill_wB, FALSE, TRUE,
3838 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3841 Xeater_n, TRUE, FALSE,
3842 EL_YAMYAM_UP, -1, -1
3845 Xeater_e, TRUE, FALSE,
3846 EL_YAMYAM_RIGHT, -1, -1
3849 Xeater_w, TRUE, FALSE,
3850 EL_YAMYAM_LEFT, -1, -1
3853 Xeater_s, TRUE, FALSE,
3854 EL_YAMYAM_DOWN, -1, -1
3857 Yeater_n, FALSE, FALSE,
3858 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3861 Yeater_nB, FALSE, TRUE,
3862 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3865 Yeater_e, FALSE, FALSE,
3866 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3869 Yeater_eB, FALSE, TRUE,
3870 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3873 Yeater_s, FALSE, FALSE,
3874 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3877 Yeater_sB, FALSE, TRUE,
3878 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3881 Yeater_w, FALSE, FALSE,
3882 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3885 Yeater_wB, FALSE, TRUE,
3886 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3889 Yeater_stone, FALSE, FALSE,
3890 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3893 Yeater_spring, FALSE, FALSE,
3894 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3897 Xalien, TRUE, FALSE,
3901 Xalien_pause, FALSE, FALSE,
3905 Yalien_n, FALSE, FALSE,
3906 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3909 Yalien_nB, FALSE, TRUE,
3910 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3913 Yalien_e, FALSE, FALSE,
3914 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3917 Yalien_eB, FALSE, TRUE,
3918 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3921 Yalien_s, FALSE, FALSE,
3922 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3925 Yalien_sB, FALSE, TRUE,
3926 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3929 Yalien_w, FALSE, FALSE,
3930 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3933 Yalien_wB, FALSE, TRUE,
3934 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3937 Yalien_stone, FALSE, FALSE,
3938 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3941 Yalien_spring, FALSE, FALSE,
3942 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3945 Xemerald, TRUE, FALSE,
3949 Xemerald_pause, FALSE, FALSE,
3953 Xemerald_fall, FALSE, FALSE,
3957 Xemerald_shine, FALSE, FALSE,
3958 EL_EMERALD, ACTION_TWINKLING, -1
3961 Yemerald_s, FALSE, FALSE,
3962 EL_EMERALD, ACTION_FALLING, -1
3965 Yemerald_sB, FALSE, TRUE,
3966 EL_EMERALD, ACTION_FALLING, -1
3969 Yemerald_e, FALSE, FALSE,
3970 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3973 Yemerald_eB, FALSE, TRUE,
3974 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3977 Yemerald_w, FALSE, FALSE,
3978 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3981 Yemerald_wB, FALSE, TRUE,
3982 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3985 Yemerald_eat, FALSE, FALSE,
3986 EL_EMERALD, ACTION_COLLECTING, -1
3989 Yemerald_stone, FALSE, FALSE,
3990 EL_NUT, ACTION_BREAKING, -1
3993 Xdiamond, TRUE, FALSE,
3997 Xdiamond_pause, FALSE, FALSE,
4001 Xdiamond_fall, FALSE, FALSE,
4005 Xdiamond_shine, FALSE, FALSE,
4006 EL_DIAMOND, ACTION_TWINKLING, -1
4009 Ydiamond_s, FALSE, FALSE,
4010 EL_DIAMOND, ACTION_FALLING, -1
4013 Ydiamond_sB, FALSE, TRUE,
4014 EL_DIAMOND, ACTION_FALLING, -1
4017 Ydiamond_e, FALSE, FALSE,
4018 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4021 Ydiamond_eB, FALSE, TRUE,
4022 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4025 Ydiamond_w, FALSE, FALSE,
4026 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4029 Ydiamond_wB, FALSE, TRUE,
4030 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4033 Ydiamond_eat, FALSE, FALSE,
4034 EL_DIAMOND, ACTION_COLLECTING, -1
4037 Ydiamond_stone, FALSE, FALSE,
4038 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4041 Xdrip_fall, TRUE, FALSE,
4042 EL_AMOEBA_DROP, -1, -1
4045 Xdrip_stretch, FALSE, FALSE,
4046 EL_AMOEBA_DROP, ACTION_FALLING, -1
4049 Xdrip_stretchB, FALSE, TRUE,
4050 EL_AMOEBA_DROP, ACTION_FALLING, -1
4053 Xdrip_eat, FALSE, FALSE,
4054 EL_AMOEBA_DROP, ACTION_GROWING, -1
4057 Ydrip_s1, FALSE, FALSE,
4058 EL_AMOEBA_DROP, ACTION_FALLING, -1
4061 Ydrip_s1B, FALSE, TRUE,
4062 EL_AMOEBA_DROP, ACTION_FALLING, -1
4065 Ydrip_s2, FALSE, FALSE,
4066 EL_AMOEBA_DROP, ACTION_FALLING, -1
4069 Ydrip_s2B, FALSE, TRUE,
4070 EL_AMOEBA_DROP, ACTION_FALLING, -1
4077 Xbomb_pause, FALSE, FALSE,
4081 Xbomb_fall, FALSE, FALSE,
4085 Ybomb_s, FALSE, FALSE,
4086 EL_BOMB, ACTION_FALLING, -1
4089 Ybomb_sB, FALSE, TRUE,
4090 EL_BOMB, ACTION_FALLING, -1
4093 Ybomb_e, FALSE, FALSE,
4094 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4097 Ybomb_eB, FALSE, TRUE,
4098 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4101 Ybomb_w, FALSE, FALSE,
4102 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4105 Ybomb_wB, FALSE, TRUE,
4106 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4109 Ybomb_eat, FALSE, FALSE,
4110 EL_BOMB, ACTION_ACTIVATING, -1
4113 Xballoon, TRUE, FALSE,
4117 Yballoon_n, FALSE, FALSE,
4118 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4121 Yballoon_nB, FALSE, TRUE,
4122 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4125 Yballoon_e, FALSE, FALSE,
4126 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4129 Yballoon_eB, FALSE, TRUE,
4130 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4133 Yballoon_s, FALSE, FALSE,
4134 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4137 Yballoon_sB, FALSE, TRUE,
4138 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4141 Yballoon_w, FALSE, FALSE,
4142 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4145 Yballoon_wB, FALSE, TRUE,
4146 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4149 Xgrass, TRUE, FALSE,
4150 EL_EMC_GRASS, -1, -1
4153 Ygrass_nB, FALSE, FALSE,
4154 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4157 Ygrass_eB, FALSE, FALSE,
4158 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4161 Ygrass_sB, FALSE, FALSE,
4162 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4165 Ygrass_wB, FALSE, FALSE,
4166 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4173 Ydirt_nB, FALSE, FALSE,
4174 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4177 Ydirt_eB, FALSE, FALSE,
4178 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4181 Ydirt_sB, FALSE, FALSE,
4182 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4185 Ydirt_wB, FALSE, FALSE,
4186 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4189 Xacid_ne, TRUE, FALSE,
4190 EL_ACID_POOL_TOPRIGHT, -1, -1
4193 Xacid_se, TRUE, FALSE,
4194 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4197 Xacid_s, TRUE, FALSE,
4198 EL_ACID_POOL_BOTTOM, -1, -1
4201 Xacid_sw, TRUE, FALSE,
4202 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4205 Xacid_nw, TRUE, FALSE,
4206 EL_ACID_POOL_TOPLEFT, -1, -1
4209 Xacid_1, TRUE, FALSE,
4213 Xacid_2, FALSE, FALSE,
4217 Xacid_3, FALSE, FALSE,
4221 Xacid_4, FALSE, FALSE,
4225 Xacid_5, FALSE, FALSE,
4229 Xacid_6, FALSE, FALSE,
4233 Xacid_7, FALSE, FALSE,
4237 Xacid_8, FALSE, FALSE,
4241 Xball_1, TRUE, FALSE,
4242 EL_EMC_MAGIC_BALL, -1, -1
4245 Xball_1B, FALSE, FALSE,
4246 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4249 Xball_2, FALSE, FALSE,
4250 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4253 Xball_2B, FALSE, FALSE,
4254 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4257 Yball_eat, FALSE, FALSE,
4258 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4261 Ykey_1_eat, FALSE, FALSE,
4262 EL_EM_KEY_1, ACTION_COLLECTING, -1
4265 Ykey_2_eat, FALSE, FALSE,
4266 EL_EM_KEY_2, ACTION_COLLECTING, -1
4269 Ykey_3_eat, FALSE, FALSE,
4270 EL_EM_KEY_3, ACTION_COLLECTING, -1
4273 Ykey_4_eat, FALSE, FALSE,
4274 EL_EM_KEY_4, ACTION_COLLECTING, -1
4277 Ykey_5_eat, FALSE, FALSE,
4278 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4281 Ykey_6_eat, FALSE, FALSE,
4282 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4285 Ykey_7_eat, FALSE, FALSE,
4286 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4289 Ykey_8_eat, FALSE, FALSE,
4290 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4293 Ylenses_eat, FALSE, FALSE,
4294 EL_EMC_LENSES, ACTION_COLLECTING, -1
4297 Ymagnify_eat, FALSE, FALSE,
4298 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4301 Ygrass_eat, FALSE, FALSE,
4302 EL_EMC_GRASS, ACTION_SNAPPING, -1
4305 Ydirt_eat, FALSE, FALSE,
4306 EL_SAND, ACTION_SNAPPING, -1
4309 Xgrow_ns, TRUE, FALSE,
4310 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4313 Ygrow_ns_eat, FALSE, FALSE,
4314 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4317 Xgrow_ew, TRUE, FALSE,
4318 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4321 Ygrow_ew_eat, FALSE, FALSE,
4322 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4325 Xwonderwall, TRUE, FALSE,
4326 EL_MAGIC_WALL, -1, -1
4329 XwonderwallB, FALSE, FALSE,
4330 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4333 Xamoeba_1, TRUE, FALSE,
4334 EL_AMOEBA_DRY, ACTION_OTHER, -1
4337 Xamoeba_2, FALSE, FALSE,
4338 EL_AMOEBA_DRY, ACTION_OTHER, -1
4341 Xamoeba_3, FALSE, FALSE,
4342 EL_AMOEBA_DRY, ACTION_OTHER, -1
4345 Xamoeba_4, FALSE, FALSE,
4346 EL_AMOEBA_DRY, ACTION_OTHER, -1
4349 Xamoeba_5, TRUE, FALSE,
4350 EL_AMOEBA_WET, ACTION_OTHER, -1
4353 Xamoeba_6, FALSE, FALSE,
4354 EL_AMOEBA_WET, ACTION_OTHER, -1
4357 Xamoeba_7, FALSE, FALSE,
4358 EL_AMOEBA_WET, ACTION_OTHER, -1
4361 Xamoeba_8, FALSE, FALSE,
4362 EL_AMOEBA_WET, ACTION_OTHER, -1
4365 Xdoor_1, TRUE, FALSE,
4366 EL_EM_GATE_1, -1, -1
4369 Xdoor_2, TRUE, FALSE,
4370 EL_EM_GATE_2, -1, -1
4373 Xdoor_3, TRUE, FALSE,
4374 EL_EM_GATE_3, -1, -1
4377 Xdoor_4, TRUE, FALSE,
4378 EL_EM_GATE_4, -1, -1
4381 Xdoor_5, TRUE, FALSE,
4382 EL_EMC_GATE_5, -1, -1
4385 Xdoor_6, TRUE, FALSE,
4386 EL_EMC_GATE_6, -1, -1
4389 Xdoor_7, TRUE, FALSE,
4390 EL_EMC_GATE_7, -1, -1
4393 Xdoor_8, TRUE, FALSE,
4394 EL_EMC_GATE_8, -1, -1
4397 Xkey_1, TRUE, FALSE,
4401 Xkey_2, TRUE, FALSE,
4405 Xkey_3, TRUE, FALSE,
4409 Xkey_4, TRUE, FALSE,
4413 Xkey_5, TRUE, FALSE,
4414 EL_EMC_KEY_5, -1, -1
4417 Xkey_6, TRUE, FALSE,
4418 EL_EMC_KEY_6, -1, -1
4421 Xkey_7, TRUE, FALSE,
4422 EL_EMC_KEY_7, -1, -1
4425 Xkey_8, TRUE, FALSE,
4426 EL_EMC_KEY_8, -1, -1
4429 Xwind_n, TRUE, FALSE,
4430 EL_BALLOON_SWITCH_UP, -1, -1
4433 Xwind_e, TRUE, FALSE,
4434 EL_BALLOON_SWITCH_RIGHT, -1, -1
4437 Xwind_s, TRUE, FALSE,
4438 EL_BALLOON_SWITCH_DOWN, -1, -1
4441 Xwind_w, TRUE, FALSE,
4442 EL_BALLOON_SWITCH_LEFT, -1, -1
4445 Xwind_nesw, TRUE, FALSE,
4446 EL_BALLOON_SWITCH_ANY, -1, -1
4449 Xwind_stop, TRUE, FALSE,
4450 EL_BALLOON_SWITCH_NONE, -1, -1
4454 EL_EXIT_CLOSED, -1, -1
4457 Xexit_1, TRUE, FALSE,
4458 EL_EXIT_OPEN, -1, -1
4461 Xexit_2, FALSE, FALSE,
4462 EL_EXIT_OPEN, -1, -1
4465 Xexit_3, FALSE, FALSE,
4466 EL_EXIT_OPEN, -1, -1
4469 Xdynamite, TRUE, FALSE,
4470 EL_EM_DYNAMITE, -1, -1
4473 Ydynamite_eat, FALSE, FALSE,
4474 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4477 Xdynamite_1, TRUE, FALSE,
4478 EL_EM_DYNAMITE_ACTIVE, -1, -1
4481 Xdynamite_2, FALSE, FALSE,
4482 EL_EM_DYNAMITE_ACTIVE, -1, -1
4485 Xdynamite_3, FALSE, FALSE,
4486 EL_EM_DYNAMITE_ACTIVE, -1, -1
4489 Xdynamite_4, FALSE, FALSE,
4490 EL_EM_DYNAMITE_ACTIVE, -1, -1
4493 Xbumper, TRUE, FALSE,
4494 EL_EMC_SPRING_BUMPER, -1, -1
4497 XbumperB, FALSE, FALSE,
4498 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4501 Xwheel, TRUE, FALSE,
4502 EL_ROBOT_WHEEL, -1, -1
4505 XwheelB, FALSE, FALSE,
4506 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4509 Xswitch, TRUE, FALSE,
4510 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4513 XswitchB, FALSE, FALSE,
4514 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4518 EL_QUICKSAND_EMPTY, -1, -1
4521 Xsand_stone, TRUE, FALSE,
4522 EL_QUICKSAND_FULL, -1, -1
4525 Xsand_stonein_1, FALSE, TRUE,
4526 EL_ROCK, ACTION_FILLING, -1
4529 Xsand_stonein_2, FALSE, TRUE,
4530 EL_ROCK, ACTION_FILLING, -1
4533 Xsand_stonein_3, FALSE, TRUE,
4534 EL_ROCK, ACTION_FILLING, -1
4537 Xsand_stonein_4, FALSE, TRUE,
4538 EL_ROCK, ACTION_FILLING, -1
4541 Xsand_stonesand_1, FALSE, FALSE,
4542 EL_QUICKSAND_FULL, -1, -1
4545 Xsand_stonesand_2, FALSE, FALSE,
4546 EL_QUICKSAND_FULL, -1, -1
4549 Xsand_stonesand_3, FALSE, FALSE,
4550 EL_QUICKSAND_FULL, -1, -1
4553 Xsand_stonesand_4, FALSE, FALSE,
4554 EL_QUICKSAND_FULL, -1, -1
4557 Xsand_stoneout_1, FALSE, FALSE,
4558 EL_ROCK, ACTION_EMPTYING, -1
4561 Xsand_stoneout_2, FALSE, FALSE,
4562 EL_ROCK, ACTION_EMPTYING, -1
4565 Xsand_sandstone_1, FALSE, FALSE,
4566 EL_QUICKSAND_FULL, -1, -1
4569 Xsand_sandstone_2, FALSE, FALSE,
4570 EL_QUICKSAND_FULL, -1, -1
4573 Xsand_sandstone_3, FALSE, FALSE,
4574 EL_QUICKSAND_FULL, -1, -1
4577 Xsand_sandstone_4, FALSE, FALSE,
4578 EL_QUICKSAND_FULL, -1, -1
4581 Xplant, TRUE, FALSE,
4582 EL_EMC_PLANT, -1, -1
4585 Yplant, FALSE, FALSE,
4586 EL_EMC_PLANT, -1, -1
4589 Xlenses, TRUE, FALSE,
4590 EL_EMC_LENSES, -1, -1
4593 Xmagnify, TRUE, FALSE,
4594 EL_EMC_MAGNIFIER, -1, -1
4597 Xdripper, TRUE, FALSE,
4598 EL_EMC_DRIPPER, -1, -1
4601 XdripperB, FALSE, FALSE,
4602 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4605 Xfake_blank, TRUE, FALSE,
4606 EL_INVISIBLE_WALL, -1, -1
4609 Xfake_blankB, FALSE, FALSE,
4610 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4613 Xfake_grass, TRUE, FALSE,
4614 EL_EMC_FAKE_GRASS, -1, -1
4617 Xfake_grassB, FALSE, FALSE,
4618 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4621 Xfake_door_1, TRUE, FALSE,
4622 EL_EM_GATE_1_GRAY, -1, -1
4625 Xfake_door_2, TRUE, FALSE,
4626 EL_EM_GATE_2_GRAY, -1, -1
4629 Xfake_door_3, TRUE, FALSE,
4630 EL_EM_GATE_3_GRAY, -1, -1
4633 Xfake_door_4, TRUE, FALSE,
4634 EL_EM_GATE_4_GRAY, -1, -1
4637 Xfake_door_5, TRUE, FALSE,
4638 EL_EMC_GATE_5_GRAY, -1, -1
4641 Xfake_door_6, TRUE, FALSE,
4642 EL_EMC_GATE_6_GRAY, -1, -1
4645 Xfake_door_7, TRUE, FALSE,
4646 EL_EMC_GATE_7_GRAY, -1, -1
4649 Xfake_door_8, TRUE, FALSE,
4650 EL_EMC_GATE_8_GRAY, -1, -1
4653 Xfake_acid_1, TRUE, FALSE,
4654 EL_EMC_FAKE_ACID, -1, -1
4657 Xfake_acid_2, FALSE, FALSE,
4658 EL_EMC_FAKE_ACID, -1, -1
4661 Xfake_acid_3, FALSE, FALSE,
4662 EL_EMC_FAKE_ACID, -1, -1
4665 Xfake_acid_4, FALSE, FALSE,
4666 EL_EMC_FAKE_ACID, -1, -1
4669 Xfake_acid_5, FALSE, FALSE,
4670 EL_EMC_FAKE_ACID, -1, -1
4673 Xfake_acid_6, FALSE, FALSE,
4674 EL_EMC_FAKE_ACID, -1, -1
4677 Xfake_acid_7, FALSE, FALSE,
4678 EL_EMC_FAKE_ACID, -1, -1
4681 Xfake_acid_8, FALSE, FALSE,
4682 EL_EMC_FAKE_ACID, -1, -1
4685 Xsteel_1, TRUE, FALSE,
4686 EL_STEELWALL, -1, -1
4689 Xsteel_2, TRUE, FALSE,
4690 EL_EMC_STEELWALL_2, -1, -1
4693 Xsteel_3, TRUE, FALSE,
4694 EL_EMC_STEELWALL_3, -1, -1
4697 Xsteel_4, TRUE, FALSE,
4698 EL_EMC_STEELWALL_4, -1, -1
4701 Xwall_1, TRUE, FALSE,
4705 Xwall_2, TRUE, FALSE,
4706 EL_EMC_WALL_14, -1, -1
4709 Xwall_3, TRUE, FALSE,
4710 EL_EMC_WALL_15, -1, -1
4713 Xwall_4, TRUE, FALSE,
4714 EL_EMC_WALL_16, -1, -1
4717 Xround_wall_1, TRUE, FALSE,
4718 EL_WALL_SLIPPERY, -1, -1
4721 Xround_wall_2, TRUE, FALSE,
4722 EL_EMC_WALL_SLIPPERY_2, -1, -1
4725 Xround_wall_3, TRUE, FALSE,
4726 EL_EMC_WALL_SLIPPERY_3, -1, -1
4729 Xround_wall_4, TRUE, FALSE,
4730 EL_EMC_WALL_SLIPPERY_4, -1, -1
4733 Xdecor_1, TRUE, FALSE,
4734 EL_EMC_WALL_8, -1, -1
4737 Xdecor_2, TRUE, FALSE,
4738 EL_EMC_WALL_6, -1, -1
4741 Xdecor_3, TRUE, FALSE,
4742 EL_EMC_WALL_4, -1, -1
4745 Xdecor_4, TRUE, FALSE,
4746 EL_EMC_WALL_7, -1, -1
4749 Xdecor_5, TRUE, FALSE,
4750 EL_EMC_WALL_5, -1, -1
4753 Xdecor_6, TRUE, FALSE,
4754 EL_EMC_WALL_9, -1, -1
4757 Xdecor_7, TRUE, FALSE,
4758 EL_EMC_WALL_10, -1, -1
4761 Xdecor_8, TRUE, FALSE,
4762 EL_EMC_WALL_1, -1, -1
4765 Xdecor_9, TRUE, FALSE,
4766 EL_EMC_WALL_2, -1, -1
4769 Xdecor_10, TRUE, FALSE,
4770 EL_EMC_WALL_3, -1, -1
4773 Xdecor_11, TRUE, FALSE,
4774 EL_EMC_WALL_11, -1, -1
4777 Xdecor_12, TRUE, FALSE,
4778 EL_EMC_WALL_12, -1, -1
4781 Xalpha_0, TRUE, FALSE,
4782 EL_CHAR('0'), -1, -1
4785 Xalpha_1, TRUE, FALSE,
4786 EL_CHAR('1'), -1, -1
4789 Xalpha_2, TRUE, FALSE,
4790 EL_CHAR('2'), -1, -1
4793 Xalpha_3, TRUE, FALSE,
4794 EL_CHAR('3'), -1, -1
4797 Xalpha_4, TRUE, FALSE,
4798 EL_CHAR('4'), -1, -1
4801 Xalpha_5, TRUE, FALSE,
4802 EL_CHAR('5'), -1, -1
4805 Xalpha_6, TRUE, FALSE,
4806 EL_CHAR('6'), -1, -1
4809 Xalpha_7, TRUE, FALSE,
4810 EL_CHAR('7'), -1, -1
4813 Xalpha_8, TRUE, FALSE,
4814 EL_CHAR('8'), -1, -1
4817 Xalpha_9, TRUE, FALSE,
4818 EL_CHAR('9'), -1, -1
4821 Xalpha_excla, TRUE, FALSE,
4822 EL_CHAR('!'), -1, -1
4825 Xalpha_quote, TRUE, FALSE,
4826 EL_CHAR('"'), -1, -1
4829 Xalpha_comma, TRUE, FALSE,
4830 EL_CHAR(','), -1, -1
4833 Xalpha_minus, TRUE, FALSE,
4834 EL_CHAR('-'), -1, -1
4837 Xalpha_perio, TRUE, FALSE,
4838 EL_CHAR('.'), -1, -1
4841 Xalpha_colon, TRUE, FALSE,
4842 EL_CHAR(':'), -1, -1
4845 Xalpha_quest, TRUE, FALSE,
4846 EL_CHAR('?'), -1, -1
4849 Xalpha_a, TRUE, FALSE,
4850 EL_CHAR('A'), -1, -1
4853 Xalpha_b, TRUE, FALSE,
4854 EL_CHAR('B'), -1, -1
4857 Xalpha_c, TRUE, FALSE,
4858 EL_CHAR('C'), -1, -1
4861 Xalpha_d, TRUE, FALSE,
4862 EL_CHAR('D'), -1, -1
4865 Xalpha_e, TRUE, FALSE,
4866 EL_CHAR('E'), -1, -1
4869 Xalpha_f, TRUE, FALSE,
4870 EL_CHAR('F'), -1, -1
4873 Xalpha_g, TRUE, FALSE,
4874 EL_CHAR('G'), -1, -1
4877 Xalpha_h, TRUE, FALSE,
4878 EL_CHAR('H'), -1, -1
4881 Xalpha_i, TRUE, FALSE,
4882 EL_CHAR('I'), -1, -1
4885 Xalpha_j, TRUE, FALSE,
4886 EL_CHAR('J'), -1, -1
4889 Xalpha_k, TRUE, FALSE,
4890 EL_CHAR('K'), -1, -1
4893 Xalpha_l, TRUE, FALSE,
4894 EL_CHAR('L'), -1, -1
4897 Xalpha_m, TRUE, FALSE,
4898 EL_CHAR('M'), -1, -1
4901 Xalpha_n, TRUE, FALSE,
4902 EL_CHAR('N'), -1, -1
4905 Xalpha_o, TRUE, FALSE,
4906 EL_CHAR('O'), -1, -1
4909 Xalpha_p, TRUE, FALSE,
4910 EL_CHAR('P'), -1, -1
4913 Xalpha_q, TRUE, FALSE,
4914 EL_CHAR('Q'), -1, -1
4917 Xalpha_r, TRUE, FALSE,
4918 EL_CHAR('R'), -1, -1
4921 Xalpha_s, TRUE, FALSE,
4922 EL_CHAR('S'), -1, -1
4925 Xalpha_t, TRUE, FALSE,
4926 EL_CHAR('T'), -1, -1
4929 Xalpha_u, TRUE, FALSE,
4930 EL_CHAR('U'), -1, -1
4933 Xalpha_v, TRUE, FALSE,
4934 EL_CHAR('V'), -1, -1
4937 Xalpha_w, TRUE, FALSE,
4938 EL_CHAR('W'), -1, -1
4941 Xalpha_x, TRUE, FALSE,
4942 EL_CHAR('X'), -1, -1
4945 Xalpha_y, TRUE, FALSE,
4946 EL_CHAR('Y'), -1, -1
4949 Xalpha_z, TRUE, FALSE,
4950 EL_CHAR('Z'), -1, -1
4953 Xalpha_arrow_e, TRUE, FALSE,
4954 EL_CHAR('>'), -1, -1
4957 Xalpha_arrow_w, TRUE, FALSE,
4958 EL_CHAR('<'), -1, -1
4961 Xalpha_copyr, TRUE, FALSE,
4962 EL_CHAR('©'), -1, -1
4966 Xboom_bug, FALSE, FALSE,
4967 EL_BUG, ACTION_EXPLODING, -1
4970 Xboom_bomb, FALSE, FALSE,
4971 EL_BOMB, ACTION_EXPLODING, -1
4974 Xboom_android, FALSE, FALSE,
4975 EL_EMC_ANDROID, ACTION_OTHER, -1
4978 Xboom_1, FALSE, FALSE,
4979 EL_DEFAULT, ACTION_EXPLODING, -1
4982 Xboom_2, FALSE, FALSE,
4983 EL_DEFAULT, ACTION_EXPLODING, -1
4986 Znormal, FALSE, FALSE,
4990 Zdynamite, FALSE, FALSE,
4994 Zplayer, FALSE, FALSE,
4998 ZBORDER, FALSE, FALSE,
5008 static struct Mapping_EM_to_RND_player
5017 em_player_mapping_list[] =
5021 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5025 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5029 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5033 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5037 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5041 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5045 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5049 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5053 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5057 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5061 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5065 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5069 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5073 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5077 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5081 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5085 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5089 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5093 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5097 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5101 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5105 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5109 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5113 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5117 EL_PLAYER_1, ACTION_DEFAULT, -1,
5121 EL_PLAYER_2, ACTION_DEFAULT, -1,
5125 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5129 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5133 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5137 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5141 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5145 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5149 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5153 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5157 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5161 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5165 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5169 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5173 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5177 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5181 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5185 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5189 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5193 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5197 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5201 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5205 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5209 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5213 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5217 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5221 EL_PLAYER_3, ACTION_DEFAULT, -1,
5225 EL_PLAYER_4, ACTION_DEFAULT, -1,
5234 int map_element_RND_to_EM(int element_rnd)
5236 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5237 static boolean mapping_initialized = FALSE;
5239 if (!mapping_initialized)
5243 /* return "Xalpha_quest" for all undefined elements in mapping array */
5244 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5245 mapping_RND_to_EM[i] = Xalpha_quest;
5247 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5248 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5249 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5250 em_object_mapping_list[i].element_em;
5252 mapping_initialized = TRUE;
5255 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5256 return mapping_RND_to_EM[element_rnd];
5258 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5263 int map_element_EM_to_RND(int element_em)
5265 static unsigned short mapping_EM_to_RND[TILE_MAX];
5266 static boolean mapping_initialized = FALSE;
5268 if (!mapping_initialized)
5272 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5273 for (i = 0; i < TILE_MAX; i++)
5274 mapping_EM_to_RND[i] = EL_UNKNOWN;
5276 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5277 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5278 em_object_mapping_list[i].element_rnd;
5280 mapping_initialized = TRUE;
5283 if (element_em >= 0 && element_em < TILE_MAX)
5284 return mapping_EM_to_RND[element_em];
5286 Error(ERR_WARN, "invalid EM level element %d", element_em);
5291 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5293 struct LevelInfo_EM *level_em = level->native_em_level;
5294 struct LEVEL *lev = level_em->lev;
5297 for (i = 0; i < TILE_MAX; i++)
5298 lev->android_array[i] = Xblank;
5300 for (i = 0; i < level->num_android_clone_elements; i++)
5302 int element_rnd = level->android_clone_element[i];
5303 int element_em = map_element_RND_to_EM(element_rnd);
5305 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5306 if (em_object_mapping_list[j].element_rnd == element_rnd)
5307 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5311 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5313 struct LevelInfo_EM *level_em = level->native_em_level;
5314 struct LEVEL *lev = level_em->lev;
5317 level->num_android_clone_elements = 0;
5319 for (i = 0; i < TILE_MAX; i++)
5321 int element_em = lev->android_array[i];
5323 boolean element_found = FALSE;
5325 if (element_em == Xblank)
5328 element_rnd = map_element_EM_to_RND(element_em);
5330 for (j = 0; j < level->num_android_clone_elements; j++)
5331 if (level->android_clone_element[j] == element_rnd)
5332 element_found = TRUE;
5336 level->android_clone_element[level->num_android_clone_elements++] =
5339 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5344 if (level->num_android_clone_elements == 0)
5346 level->num_android_clone_elements = 1;
5347 level->android_clone_element[0] = EL_EMPTY;
5351 int map_direction_RND_to_EM(int direction)
5353 return (direction == MV_UP ? 0 :
5354 direction == MV_RIGHT ? 1 :
5355 direction == MV_DOWN ? 2 :
5356 direction == MV_LEFT ? 3 :
5360 int map_direction_EM_to_RND(int direction)
5362 return (direction == 0 ? MV_UP :
5363 direction == 1 ? MV_RIGHT :
5364 direction == 2 ? MV_DOWN :
5365 direction == 3 ? MV_LEFT :
5369 int get_next_element(int element)
5373 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5374 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5375 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5376 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5377 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5378 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5379 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5381 default: return element;
5386 int el_act_dir2img(int element, int action, int direction)
5388 element = GFX_ELEMENT(element);
5390 if (direction == MV_NONE)
5391 return element_info[element].graphic[action];
5393 direction = MV_DIR_TO_BIT(direction);
5395 return element_info[element].direction_graphic[action][direction];
5398 int el_act_dir2img(int element, int action, int direction)
5400 element = GFX_ELEMENT(element);
5401 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5403 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5404 return element_info[element].direction_graphic[action][direction];
5409 static int el_act_dir2crm(int element, int action, int direction)
5411 element = GFX_ELEMENT(element);
5413 if (direction == MV_NONE)
5414 return element_info[element].crumbled[action];
5416 direction = MV_DIR_TO_BIT(direction);
5418 return element_info[element].direction_crumbled[action][direction];
5421 static int el_act_dir2crm(int element, int action, int direction)
5423 element = GFX_ELEMENT(element);
5424 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5426 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5427 return element_info[element].direction_crumbled[action][direction];
5431 int el_act2img(int element, int action)
5433 element = GFX_ELEMENT(element);
5435 return element_info[element].graphic[action];
5438 int el_act2crm(int element, int action)
5440 element = GFX_ELEMENT(element);
5442 return element_info[element].crumbled[action];
5445 int el_dir2img(int element, int direction)
5447 element = GFX_ELEMENT(element);
5449 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5452 int el2baseimg(int element)
5454 return element_info[element].graphic[ACTION_DEFAULT];
5457 int el2img(int element)
5459 element = GFX_ELEMENT(element);
5461 return element_info[element].graphic[ACTION_DEFAULT];
5464 int el2edimg(int element)
5466 element = GFX_ELEMENT(element);
5468 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5471 int el2preimg(int element)
5473 element = GFX_ELEMENT(element);
5475 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5478 int font2baseimg(int font_nr)
5480 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5483 int getNumActivePlayers_EM()
5485 int num_players = 0;
5491 for (i = 0; i < MAX_PLAYERS; i++)
5492 if (tape.player_participates[i])
5498 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5500 int game_frame_delay_value;
5502 game_frame_delay_value =
5503 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5504 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5507 if (tape.playing && tape.warp_forward && !tape.pausing)
5508 game_frame_delay_value = 0;
5510 return game_frame_delay_value;
5513 unsigned int InitRND(long seed)
5515 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5516 return InitEngineRandom_EM(seed);
5518 return InitEngineRandom_RND(seed);
5521 void InitGraphicInfo_EM(void)
5523 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5524 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5528 int num_em_gfx_errors = 0;
5530 if (graphic_info_em_object[0][0].bitmap == NULL)
5532 /* EM graphics not yet initialized in em_open_all() */
5537 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5540 /* always start with reliable default values */
5541 for (i = 0; i < TILE_MAX; i++)
5543 object_mapping[i].element_rnd = EL_UNKNOWN;
5544 object_mapping[i].is_backside = FALSE;
5545 object_mapping[i].action = ACTION_DEFAULT;
5546 object_mapping[i].direction = MV_NONE;
5549 /* always start with reliable default values */
5550 for (p = 0; p < MAX_PLAYERS; p++)
5552 for (i = 0; i < SPR_MAX; i++)
5554 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5555 player_mapping[p][i].action = ACTION_DEFAULT;
5556 player_mapping[p][i].direction = MV_NONE;
5560 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5562 int e = em_object_mapping_list[i].element_em;
5564 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5565 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5567 if (em_object_mapping_list[i].action != -1)
5568 object_mapping[e].action = em_object_mapping_list[i].action;
5570 if (em_object_mapping_list[i].direction != -1)
5571 object_mapping[e].direction =
5572 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5575 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5577 int a = em_player_mapping_list[i].action_em;
5578 int p = em_player_mapping_list[i].player_nr;
5580 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5582 if (em_player_mapping_list[i].action != -1)
5583 player_mapping[p][a].action = em_player_mapping_list[i].action;
5585 if (em_player_mapping_list[i].direction != -1)
5586 player_mapping[p][a].direction =
5587 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5590 for (i = 0; i < TILE_MAX; i++)
5592 int element = object_mapping[i].element_rnd;
5593 int action = object_mapping[i].action;
5594 int direction = object_mapping[i].direction;
5595 boolean is_backside = object_mapping[i].is_backside;
5596 boolean action_removing = (action == ACTION_DIGGING ||
5597 action == ACTION_SNAPPING ||
5598 action == ACTION_COLLECTING);
5599 boolean action_exploding = ((action == ACTION_EXPLODING ||
5600 action == ACTION_SMASHED_BY_ROCK ||
5601 action == ACTION_SMASHED_BY_SPRING) &&
5602 element != EL_DIAMOND);
5603 boolean action_active = (action == ACTION_ACTIVE);
5604 boolean action_other = (action == ACTION_OTHER);
5606 for (j = 0; j < 8; j++)
5608 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5609 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5611 i == Xdrip_stretch ? element :
5612 i == Xdrip_stretchB ? element :
5613 i == Ydrip_s1 ? element :
5614 i == Ydrip_s1B ? element :
5615 i == Xball_1B ? element :
5616 i == Xball_2 ? element :
5617 i == Xball_2B ? element :
5618 i == Yball_eat ? element :
5619 i == Ykey_1_eat ? element :
5620 i == Ykey_2_eat ? element :
5621 i == Ykey_3_eat ? element :
5622 i == Ykey_4_eat ? element :
5623 i == Ykey_5_eat ? element :
5624 i == Ykey_6_eat ? element :
5625 i == Ykey_7_eat ? element :
5626 i == Ykey_8_eat ? element :
5627 i == Ylenses_eat ? element :
5628 i == Ymagnify_eat ? element :
5629 i == Ygrass_eat ? element :
5630 i == Ydirt_eat ? element :
5631 i == Yemerald_stone ? EL_EMERALD :
5632 i == Ydiamond_stone ? EL_ROCK :
5633 i == Xsand_stonein_1 ? element :
5634 i == Xsand_stonein_2 ? element :
5635 i == Xsand_stonein_3 ? element :
5636 i == Xsand_stonein_4 ? element :
5637 is_backside ? EL_EMPTY :
5638 action_removing ? EL_EMPTY :
5640 int effective_action = (j < 7 ? action :
5641 i == Xdrip_stretch ? action :
5642 i == Xdrip_stretchB ? action :
5643 i == Ydrip_s1 ? action :
5644 i == Ydrip_s1B ? action :
5645 i == Xball_1B ? action :
5646 i == Xball_2 ? action :
5647 i == Xball_2B ? action :
5648 i == Yball_eat ? action :
5649 i == Ykey_1_eat ? action :
5650 i == Ykey_2_eat ? action :
5651 i == Ykey_3_eat ? action :
5652 i == Ykey_4_eat ? action :
5653 i == Ykey_5_eat ? action :
5654 i == Ykey_6_eat ? action :
5655 i == Ykey_7_eat ? action :
5656 i == Ykey_8_eat ? action :
5657 i == Ylenses_eat ? action :
5658 i == Ymagnify_eat ? action :
5659 i == Ygrass_eat ? action :
5660 i == Ydirt_eat ? action :
5661 i == Xsand_stonein_1 ? action :
5662 i == Xsand_stonein_2 ? action :
5663 i == Xsand_stonein_3 ? action :
5664 i == Xsand_stonein_4 ? action :
5665 i == Xsand_stoneout_1 ? action :
5666 i == Xsand_stoneout_2 ? action :
5667 i == Xboom_android ? ACTION_EXPLODING :
5668 action_exploding ? ACTION_EXPLODING :
5669 action_active ? action :
5670 action_other ? action :
5672 int graphic = (el_act_dir2img(effective_element, effective_action,
5674 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5676 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5677 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5678 boolean has_action_graphics = (graphic != base_graphic);
5679 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5680 struct GraphicInfo *g = &graphic_info[graphic];
5681 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5684 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5685 boolean special_animation = (action != ACTION_DEFAULT &&
5686 g->anim_frames == 3 &&
5687 g->anim_delay == 2 &&
5688 g->anim_mode & ANIM_LINEAR);
5689 int sync_frame = (i == Xdrip_stretch ? 7 :
5690 i == Xdrip_stretchB ? 7 :
5691 i == Ydrip_s2 ? j + 8 :
5692 i == Ydrip_s2B ? j + 8 :
5701 i == Xfake_acid_1 ? 0 :
5702 i == Xfake_acid_2 ? 10 :
5703 i == Xfake_acid_3 ? 20 :
5704 i == Xfake_acid_4 ? 30 :
5705 i == Xfake_acid_5 ? 40 :
5706 i == Xfake_acid_6 ? 50 :
5707 i == Xfake_acid_7 ? 60 :
5708 i == Xfake_acid_8 ? 70 :
5710 i == Xball_2B ? j + 8 :
5711 i == Yball_eat ? j + 1 :
5712 i == Ykey_1_eat ? j + 1 :
5713 i == Ykey_2_eat ? j + 1 :
5714 i == Ykey_3_eat ? j + 1 :
5715 i == Ykey_4_eat ? j + 1 :
5716 i == Ykey_5_eat ? j + 1 :
5717 i == Ykey_6_eat ? j + 1 :
5718 i == Ykey_7_eat ? j + 1 :
5719 i == Ykey_8_eat ? j + 1 :
5720 i == Ylenses_eat ? j + 1 :
5721 i == Ymagnify_eat ? j + 1 :
5722 i == Ygrass_eat ? j + 1 :
5723 i == Ydirt_eat ? j + 1 :
5724 i == Xamoeba_1 ? 0 :
5725 i == Xamoeba_2 ? 1 :
5726 i == Xamoeba_3 ? 2 :
5727 i == Xamoeba_4 ? 3 :
5728 i == Xamoeba_5 ? 0 :
5729 i == Xamoeba_6 ? 1 :
5730 i == Xamoeba_7 ? 2 :
5731 i == Xamoeba_8 ? 3 :
5732 i == Xexit_2 ? j + 8 :
5733 i == Xexit_3 ? j + 16 :
5734 i == Xdynamite_1 ? 0 :
5735 i == Xdynamite_2 ? 8 :
5736 i == Xdynamite_3 ? 16 :
5737 i == Xdynamite_4 ? 24 :
5738 i == Xsand_stonein_1 ? j + 1 :
5739 i == Xsand_stonein_2 ? j + 9 :
5740 i == Xsand_stonein_3 ? j + 17 :
5741 i == Xsand_stonein_4 ? j + 25 :
5742 i == Xsand_stoneout_1 && j == 0 ? 0 :
5743 i == Xsand_stoneout_1 && j == 1 ? 0 :
5744 i == Xsand_stoneout_1 && j == 2 ? 1 :
5745 i == Xsand_stoneout_1 && j == 3 ? 2 :
5746 i == Xsand_stoneout_1 && j == 4 ? 2 :
5747 i == Xsand_stoneout_1 && j == 5 ? 3 :
5748 i == Xsand_stoneout_1 && j == 6 ? 4 :
5749 i == Xsand_stoneout_1 && j == 7 ? 4 :
5750 i == Xsand_stoneout_2 && j == 0 ? 5 :
5751 i == Xsand_stoneout_2 && j == 1 ? 6 :
5752 i == Xsand_stoneout_2 && j == 2 ? 7 :
5753 i == Xsand_stoneout_2 && j == 3 ? 8 :
5754 i == Xsand_stoneout_2 && j == 4 ? 9 :
5755 i == Xsand_stoneout_2 && j == 5 ? 11 :
5756 i == Xsand_stoneout_2 && j == 6 ? 13 :
5757 i == Xsand_stoneout_2 && j == 7 ? 15 :
5758 i == Xboom_bug && j == 1 ? 2 :
5759 i == Xboom_bug && j == 2 ? 2 :
5760 i == Xboom_bug && j == 3 ? 4 :
5761 i == Xboom_bug && j == 4 ? 4 :
5762 i == Xboom_bug && j == 5 ? 2 :
5763 i == Xboom_bug && j == 6 ? 2 :
5764 i == Xboom_bug && j == 7 ? 0 :
5765 i == Xboom_bomb && j == 1 ? 2 :
5766 i == Xboom_bomb && j == 2 ? 2 :
5767 i == Xboom_bomb && j == 3 ? 4 :
5768 i == Xboom_bomb && j == 4 ? 4 :
5769 i == Xboom_bomb && j == 5 ? 2 :
5770 i == Xboom_bomb && j == 6 ? 2 :
5771 i == Xboom_bomb && j == 7 ? 0 :
5772 i == Xboom_android && j == 7 ? 6 :
5773 i == Xboom_1 && j == 1 ? 2 :
5774 i == Xboom_1 && j == 2 ? 2 :
5775 i == Xboom_1 && j == 3 ? 4 :
5776 i == Xboom_1 && j == 4 ? 4 :
5777 i == Xboom_1 && j == 5 ? 6 :
5778 i == Xboom_1 && j == 6 ? 6 :
5779 i == Xboom_1 && j == 7 ? 8 :
5780 i == Xboom_2 && j == 0 ? 8 :
5781 i == Xboom_2 && j == 1 ? 8 :
5782 i == Xboom_2 && j == 2 ? 10 :
5783 i == Xboom_2 && j == 3 ? 10 :
5784 i == Xboom_2 && j == 4 ? 10 :
5785 i == Xboom_2 && j == 5 ? 12 :
5786 i == Xboom_2 && j == 6 ? 12 :
5787 i == Xboom_2 && j == 7 ? 12 :
5788 special_animation && j == 4 ? 3 :
5789 effective_action != action ? 0 :
5793 Bitmap *debug_bitmap = g_em->bitmap;
5794 int debug_src_x = g_em->src_x;
5795 int debug_src_y = g_em->src_y;
5798 int frame = getAnimationFrame(g->anim_frames,
5801 g->anim_start_frame,
5804 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5805 g->double_movement && is_backside);
5807 g_em->bitmap = src_bitmap;
5808 g_em->src_x = src_x;
5809 g_em->src_y = src_y;
5810 g_em->src_offset_x = 0;
5811 g_em->src_offset_y = 0;
5812 g_em->dst_offset_x = 0;
5813 g_em->dst_offset_y = 0;
5814 g_em->width = TILEX;
5815 g_em->height = TILEY;
5817 g_em->crumbled_bitmap = NULL;
5818 g_em->crumbled_src_x = 0;
5819 g_em->crumbled_src_y = 0;
5820 g_em->crumbled_border_size = 0;
5822 g_em->has_crumbled_graphics = FALSE;
5823 g_em->preserve_background = FALSE;
5826 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5827 printf("::: empty crumbled: %d [%s], %d, %d\n",
5828 effective_element, element_info[effective_element].token_name,
5829 effective_action, direction);
5832 /* if element can be crumbled, but certain action graphics are just empty
5833 space (like snapping sand with the original R'n'D graphics), do not
5834 treat these empty space graphics as crumbled graphics in EMC engine */
5835 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5837 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5839 g_em->has_crumbled_graphics = TRUE;
5840 g_em->crumbled_bitmap = src_bitmap;
5841 g_em->crumbled_src_x = src_x;
5842 g_em->crumbled_src_y = src_y;
5843 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5847 if (element == EL_ROCK &&
5848 effective_action == ACTION_FILLING)
5849 printf("::: has_action_graphics == %d\n", has_action_graphics);
5852 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5853 effective_action == ACTION_MOVING ||
5854 effective_action == ACTION_PUSHING ||
5855 effective_action == ACTION_EATING)) ||
5856 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5857 effective_action == ACTION_EMPTYING)))
5860 (effective_action == ACTION_FALLING ||
5861 effective_action == ACTION_FILLING ||
5862 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5863 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5864 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5865 int num_steps = (i == Ydrip_s1 ? 16 :
5866 i == Ydrip_s1B ? 16 :
5867 i == Ydrip_s2 ? 16 :
5868 i == Ydrip_s2B ? 16 :
5869 i == Xsand_stonein_1 ? 32 :
5870 i == Xsand_stonein_2 ? 32 :
5871 i == Xsand_stonein_3 ? 32 :
5872 i == Xsand_stonein_4 ? 32 :
5873 i == Xsand_stoneout_1 ? 16 :
5874 i == Xsand_stoneout_2 ? 16 : 8);
5875 int cx = ABS(dx) * (TILEX / num_steps);
5876 int cy = ABS(dy) * (TILEY / num_steps);
5877 int step_frame = (i == Ydrip_s2 ? j + 8 :
5878 i == Ydrip_s2B ? j + 8 :
5879 i == Xsand_stonein_2 ? j + 8 :
5880 i == Xsand_stonein_3 ? j + 16 :
5881 i == Xsand_stonein_4 ? j + 24 :
5882 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5883 int step = (is_backside ? step_frame : num_steps - step_frame);
5885 if (is_backside) /* tile where movement starts */
5887 if (dx < 0 || dy < 0)
5889 g_em->src_offset_x = cx * step;
5890 g_em->src_offset_y = cy * step;
5894 g_em->dst_offset_x = cx * step;
5895 g_em->dst_offset_y = cy * step;
5898 else /* tile where movement ends */
5900 if (dx < 0 || dy < 0)
5902 g_em->dst_offset_x = cx * step;
5903 g_em->dst_offset_y = cy * step;
5907 g_em->src_offset_x = cx * step;
5908 g_em->src_offset_y = cy * step;
5912 g_em->width = TILEX - cx * step;
5913 g_em->height = TILEY - cy * step;
5916 /* create unique graphic identifier to decide if tile must be redrawn */
5917 /* bit 31 - 16 (16 bit): EM style graphic
5918 bit 15 - 12 ( 4 bit): EM style frame
5919 bit 11 - 6 ( 6 bit): graphic width
5920 bit 5 - 0 ( 6 bit): graphic height */
5921 g_em->unique_identifier =
5922 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5926 /* skip check for EMC elements not contained in original EMC artwork */
5927 if (element == EL_EMC_FAKE_ACID)
5930 if (g_em->bitmap != debug_bitmap ||
5931 g_em->src_x != debug_src_x ||
5932 g_em->src_y != debug_src_y ||
5933 g_em->src_offset_x != 0 ||
5934 g_em->src_offset_y != 0 ||
5935 g_em->dst_offset_x != 0 ||
5936 g_em->dst_offset_y != 0 ||
5937 g_em->width != TILEX ||
5938 g_em->height != TILEY)
5940 static int last_i = -1;
5948 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5949 i, element, element_info[element].token_name,
5950 element_action_info[effective_action].suffix, direction);
5952 if (element != effective_element)
5953 printf(" [%d ('%s')]",
5955 element_info[effective_element].token_name);
5959 if (g_em->bitmap != debug_bitmap)
5960 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5961 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5963 if (g_em->src_x != debug_src_x ||
5964 g_em->src_y != debug_src_y)
5965 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5966 j, (is_backside ? 'B' : 'F'),
5967 g_em->src_x, g_em->src_y,
5968 g_em->src_x / 32, g_em->src_y / 32,
5969 debug_src_x, debug_src_y,
5970 debug_src_x / 32, debug_src_y / 32);
5972 if (g_em->src_offset_x != 0 ||
5973 g_em->src_offset_y != 0 ||
5974 g_em->dst_offset_x != 0 ||
5975 g_em->dst_offset_y != 0)
5976 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5978 g_em->src_offset_x, g_em->src_offset_y,
5979 g_em->dst_offset_x, g_em->dst_offset_y);
5981 if (g_em->width != TILEX ||
5982 g_em->height != TILEY)
5983 printf(" %d (%d): size %d,%d should be %d,%d\n",
5985 g_em->width, g_em->height, TILEX, TILEY);
5987 num_em_gfx_errors++;
5994 for (i = 0; i < TILE_MAX; i++)
5996 for (j = 0; j < 8; j++)
5998 int element = object_mapping[i].element_rnd;
5999 int action = object_mapping[i].action;
6000 int direction = object_mapping[i].direction;
6001 boolean is_backside = object_mapping[i].is_backside;
6002 int graphic_action = el_act_dir2img(element, action, direction);
6003 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6005 if ((action == ACTION_SMASHED_BY_ROCK ||
6006 action == ACTION_SMASHED_BY_SPRING ||
6007 action == ACTION_EATING) &&
6008 graphic_action == graphic_default)
6010 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6011 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6012 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6013 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6016 /* no separate animation for "smashed by rock" -- use rock instead */
6017 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6018 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6020 g_em->bitmap = g_xx->bitmap;
6021 g_em->src_x = g_xx->src_x;
6022 g_em->src_y = g_xx->src_y;
6023 g_em->src_offset_x = g_xx->src_offset_x;
6024 g_em->src_offset_y = g_xx->src_offset_y;
6025 g_em->dst_offset_x = g_xx->dst_offset_x;
6026 g_em->dst_offset_y = g_xx->dst_offset_y;
6027 g_em->width = g_xx->width;
6028 g_em->height = g_xx->height;
6029 g_em->unique_identifier = g_xx->unique_identifier;
6032 g_em->preserve_background = TRUE;
6037 for (p = 0; p < MAX_PLAYERS; p++)
6039 for (i = 0; i < SPR_MAX; i++)
6041 int element = player_mapping[p][i].element_rnd;
6042 int action = player_mapping[p][i].action;
6043 int direction = player_mapping[p][i].direction;
6045 for (j = 0; j < 8; j++)
6047 int effective_element = element;
6048 int effective_action = action;
6049 int graphic = (direction == MV_NONE ?
6050 el_act2img(effective_element, effective_action) :
6051 el_act_dir2img(effective_element, effective_action,
6053 struct GraphicInfo *g = &graphic_info[graphic];
6054 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6060 Bitmap *debug_bitmap = g_em->bitmap;
6061 int debug_src_x = g_em->src_x;
6062 int debug_src_y = g_em->src_y;
6065 int frame = getAnimationFrame(g->anim_frames,
6068 g->anim_start_frame,
6071 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6073 g_em->bitmap = src_bitmap;
6074 g_em->src_x = src_x;
6075 g_em->src_y = src_y;
6076 g_em->src_offset_x = 0;
6077 g_em->src_offset_y = 0;
6078 g_em->dst_offset_x = 0;
6079 g_em->dst_offset_y = 0;
6080 g_em->width = TILEX;
6081 g_em->height = TILEY;
6085 /* skip check for EMC elements not contained in original EMC artwork */
6086 if (element == EL_PLAYER_3 ||
6087 element == EL_PLAYER_4)
6090 if (g_em->bitmap != debug_bitmap ||
6091 g_em->src_x != debug_src_x ||
6092 g_em->src_y != debug_src_y)
6094 static int last_i = -1;
6102 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6103 p, i, element, element_info[element].token_name,
6104 element_action_info[effective_action].suffix, direction);
6106 if (element != effective_element)
6107 printf(" [%d ('%s')]",
6109 element_info[effective_element].token_name);
6113 if (g_em->bitmap != debug_bitmap)
6114 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6115 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6117 if (g_em->src_x != debug_src_x ||
6118 g_em->src_y != debug_src_y)
6119 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6121 g_em->src_x, g_em->src_y,
6122 g_em->src_x / 32, g_em->src_y / 32,
6123 debug_src_x, debug_src_y,
6124 debug_src_x / 32, debug_src_y / 32);
6126 num_em_gfx_errors++;
6136 printf("::: [%d errors found]\n", num_em_gfx_errors);
6142 void PlayMenuSound()
6144 int sound = menu.sound[game_status];
6146 if (sound == SND_UNDEFINED)
6149 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6150 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6153 if (IS_LOOP_SOUND(sound))
6154 PlaySoundLoop(sound);
6159 void PlayMenuSoundStereo(int sound, int stereo_position)
6161 if (sound == SND_UNDEFINED)
6164 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6165 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6168 if (IS_LOOP_SOUND(sound))
6169 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6171 PlaySoundStereo(sound, stereo_position);
6174 void PlayMenuSoundIfLoop()
6176 int sound = menu.sound[game_status];
6178 if (sound == SND_UNDEFINED)
6181 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6182 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6185 if (IS_LOOP_SOUND(sound))
6186 PlaySoundLoop(sound);
6189 void PlayMenuMusic()
6191 int music = menu.music[game_status];
6193 if (music == MUS_UNDEFINED)
6196 if (!setup.sound_music)
6202 void PlaySoundActivating()
6205 PlaySound(SND_MENU_ITEM_ACTIVATING);
6209 void PlaySoundSelecting()
6212 PlaySound(SND_MENU_ITEM_SELECTING);
6216 void ToggleFullscreenIfNeeded()
6218 boolean change_fullscreen = (setup.fullscreen !=
6219 video.fullscreen_enabled);
6220 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6221 !strEqual(setup.fullscreen_mode,
6222 video.fullscreen_mode_current));
6224 if (!video.fullscreen_available)
6228 if (change_fullscreen || change_fullscreen_mode)
6230 if (setup.fullscreen != video.fullscreen_enabled ||
6231 setup.fullscreen_mode != video.fullscreen_mode_current)
6234 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6236 /* save backbuffer content which gets lost when toggling fullscreen mode */
6237 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6240 if (change_fullscreen_mode)
6242 if (setup.fullscreen && video.fullscreen_enabled)
6245 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6247 /* (this is now set in sdl.c) */
6249 video.fullscreen_mode_current = setup.fullscreen_mode;
6251 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6254 /* toggle fullscreen */
6255 ChangeVideoModeIfNeeded(setup.fullscreen);
6257 setup.fullscreen = video.fullscreen_enabled;
6259 /* restore backbuffer content from temporary backbuffer backup bitmap */
6260 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6262 FreeBitmap(tmp_backbuffer);
6265 /* update visible window/screen */
6266 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6268 redraw_mask = REDRAW_ALL;