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"
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX 0
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES 0
29 #define TOOL_CTRL_ID_NO 1
30 #define TOOL_CTRL_ID_CONFIRM 2
31 #define TOOL_CTRL_ID_PLAYER_1 3
32 #define TOOL_CTRL_ID_PLAYER_2 4
33 #define TOOL_CTRL_ID_PLAYER_3 5
34 #define TOOL_CTRL_ID_PLAYER_4 6
36 #define NUM_TOOL_BUTTONS 7
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
47 static char *print_if_not_empty(int element)
49 static char *s = NULL;
50 char *token_name = element_info[element].token_name;
55 s = checked_malloc(strlen(token_name) + 10 + 1);
57 if (element != EL_EMPTY)
58 sprintf(s, "%d\t['%s']", element, token_name);
60 sprintf(s, "%d", element);
65 void DumpTile(int x, int y)
70 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
77 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80 if (!IN_LEV_FIELD(x, y))
82 printf("(not in level field)\n");
88 printf(" Feld: %d\t['%s']\n", Feld[x][y],
89 element_info[Feld[x][y]].token_name);
90 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
91 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
92 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
93 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94 printf(" MovPos: %d\n", MovPos[x][y]);
95 printf(" MovDir: %d\n", MovDir[x][y]);
96 printf(" MovDelay: %d\n", MovDelay[x][y]);
97 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
98 printf(" CustomValue: %d\n", CustomValue[x][y]);
99 printf(" GfxElement: %d\n", GfxElement[x][y]);
100 printf(" GfxAction: %d\n", GfxAction[x][y]);
101 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
105 void SetDrawtoField(int mode)
107 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
118 drawto_field = fieldbuffer;
120 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
126 BX2 = SCR_FIELDX - 1;
127 BY2 = SCR_FIELDY - 1;
131 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 if (game_status == GAME_MODE_PLAYING &&
138 level.game_engine_type == GAME_ENGINE_TYPE_EM)
140 /* currently there is no partial redraw -- always redraw whole playfield */
141 RedrawPlayfield_EM(TRUE);
143 /* blit playfield from scroll buffer to normal back buffer for fading in */
144 BlitScreenToBitmap_EM(backbuffer);
146 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
152 width = gfx.sxsize + 2 * TILEX;
153 height = gfx.sysize + 2 * TILEY;
156 if (force_redraw || setup.direct_draw)
159 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
160 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
162 if (setup.direct_draw)
163 SetDrawtoField(DRAW_BACKBUFFER);
165 for (xx = BX1; xx <= BX2; xx++)
166 for (yy = BY1; yy <= BY2; yy++)
167 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
168 DrawScreenField(xx, yy);
171 if (setup.direct_draw)
172 SetDrawtoField(DRAW_DIRECT);
175 if (setup.soft_scrolling)
177 int fx = FX, fy = FY;
179 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
180 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
182 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
194 BlitBitmap(drawto, window, x, y, width, height, x, y);
197 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
199 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
201 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
202 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
205 void DrawMaskedBorder_FIELD()
207 if (game_status >= GAME_MODE_TITLE &&
208 game_status <= GAME_MODE_PLAYING &&
209 border.draw_masked[game_status])
210 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
213 void DrawMaskedBorder_DOOR_1()
215 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
216 (game_status != GAME_MODE_EDITOR ||
217 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
218 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
221 void DrawMaskedBorder_DOOR_2()
223 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
224 game_status != GAME_MODE_EDITOR)
225 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
228 void DrawMaskedBorder_DOOR_3()
230 /* currently not available */
233 void DrawMaskedBorder_ALL()
235 DrawMaskedBorder_FIELD();
236 DrawMaskedBorder_DOOR_1();
237 DrawMaskedBorder_DOOR_2();
238 DrawMaskedBorder_DOOR_3();
241 void DrawMaskedBorder(int redraw_mask)
243 if (redraw_mask & REDRAW_ALL)
244 DrawMaskedBorder_ALL();
247 if (redraw_mask & REDRAW_FIELD)
248 DrawMaskedBorder_FIELD();
249 if (redraw_mask & REDRAW_DOOR_1)
250 DrawMaskedBorder_DOOR_1();
251 if (redraw_mask & REDRAW_DOOR_2)
252 DrawMaskedBorder_DOOR_2();
253 if (redraw_mask & REDRAW_DOOR_3)
254 DrawMaskedBorder_DOOR_3();
261 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
263 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
264 redraw_mask &= ~REDRAW_MAIN;
266 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
267 redraw_mask |= REDRAW_FIELD;
269 if (redraw_mask & REDRAW_FIELD)
270 redraw_mask &= ~REDRAW_TILES;
272 if (redraw_mask == REDRAW_NONE)
275 if (redraw_mask & REDRAW_TILES &&
276 game_status == GAME_MODE_PLAYING &&
277 border.draw_masked[game_status])
278 redraw_mask |= REDRAW_FIELD;
280 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
282 static boolean last_frame_skipped = FALSE;
283 boolean skip_even_when_not_scrolling = TRUE;
284 boolean just_scrolling = (ScreenMovDir != 0);
285 boolean verbose = FALSE;
287 if (global.fps_slowdown_factor > 1 &&
288 (FrameCounter % global.fps_slowdown_factor) &&
289 (just_scrolling || skip_even_when_not_scrolling))
291 redraw_mask &= ~REDRAW_MAIN;
293 last_frame_skipped = TRUE;
296 printf("FRAME SKIPPED\n");
300 if (last_frame_skipped)
301 redraw_mask |= REDRAW_FIELD;
303 last_frame_skipped = FALSE;
306 printf("frame not skipped\n");
310 /* synchronize X11 graphics at this point; if we would synchronize the
311 display immediately after the buffer switching (after the XFlush),
312 this could mean that we have to wait for the graphics to complete,
313 although we could go on doing calculations for the next frame */
318 DrawMaskedBorder(redraw_mask);
321 if (redraw_mask & REDRAW_ALL)
324 DrawMaskedBorder(REDRAW_ALL);
326 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
328 redraw_mask = REDRAW_NONE;
331 if (redraw_mask & REDRAW_FIELD)
333 if (game_status != GAME_MODE_PLAYING ||
334 redraw_mask & REDRAW_FROM_BACKBUFFER)
337 DrawMaskedBorder(REDRAW_FIELD);
339 BlitBitmap(backbuffer, window,
340 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
344 int fx = FX, fy = FY;
346 if (setup.soft_scrolling)
348 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
349 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
352 if (setup.soft_scrolling ||
353 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
354 ABS(ScreenMovPos) == ScrollStepSize ||
355 redraw_tiles > REDRAWTILES_THRESHOLD)
358 if (border.draw_masked[GFX_SPECIAL_ARG_MAIN])
360 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
362 DrawMaskedBorder(REDRAW_FIELD);
363 BlitBitmap(backbuffer, window,
364 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
368 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
370 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
375 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
377 (setup.soft_scrolling ?
378 "setup.soft_scrolling" :
379 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
380 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
381 ABS(ScreenGfxPos) == ScrollStepSize ?
382 "ABS(ScreenGfxPos) == ScrollStepSize" :
383 "redraw_tiles > REDRAWTILES_THRESHOLD"));
389 redraw_mask &= ~REDRAW_MAIN;
392 if (redraw_mask & REDRAW_DOORS)
394 if (redraw_mask & REDRAW_DOOR_1)
397 DrawMaskedBorder(REDRAW_DOOR_1);
399 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
402 if (redraw_mask & REDRAW_DOOR_2)
405 DrawMaskedBorder(REDRAW_DOOR_2);
407 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
410 if (redraw_mask & REDRAW_DOOR_3)
413 DrawMaskedBorder(REDRAW_DOOR_3);
415 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
418 redraw_mask &= ~REDRAW_DOORS;
421 if (redraw_mask & REDRAW_MICROLEVEL)
423 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
424 SX, SY + 10 * TILEY);
426 redraw_mask &= ~REDRAW_MICROLEVEL;
429 if (redraw_mask & REDRAW_TILES)
431 for (x = 0; x < SCR_FIELDX; x++)
432 for (y = 0 ; y < SCR_FIELDY; y++)
433 if (redraw[redraw_x1 + x][redraw_y1 + y])
434 BlitBitmap(buffer, window,
435 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
436 SX + x * TILEX, SY + y * TILEY);
439 if (redraw_mask & REDRAW_FPS) /* display frames per second */
444 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
445 if (!global.fps_slowdown)
448 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
449 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
454 for (x = 0; x < MAX_BUF_XSIZE; x++)
455 for (y = 0; y < MAX_BUF_YSIZE; y++)
458 redraw_mask = REDRAW_NONE;
464 long fading_delay = 300;
466 if (setup.fading && (redraw_mask & REDRAW_FIELD))
473 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
476 for (i = 0; i < 2 * FULL_SYSIZE; i++)
478 for (y = 0; y < FULL_SYSIZE; y++)
480 BlitBitmap(backbuffer, window,
481 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
489 for (i = 1; i < FULL_SYSIZE; i+=2)
490 BlitBitmap(backbuffer, window,
491 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
497 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
498 BlitBitmapMasked(backbuffer, window,
499 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
504 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
505 BlitBitmapMasked(backbuffer, window,
506 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
511 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
512 BlitBitmapMasked(backbuffer, window,
513 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
518 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
519 BlitBitmapMasked(backbuffer, window,
520 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
525 redraw_mask &= ~REDRAW_MAIN;
532 void FadeExt(int fade_mask, int fade_mode)
534 void (*draw_border_function)(void) = NULL;
535 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
536 int x, y, width, height;
537 int fade_delay, post_delay;
539 if (fade_mask & REDRAW_FIELD)
544 height = FULL_SYSIZE;
546 fade_delay = menu.fade_delay;
547 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
549 draw_border_function = DrawMaskedBorder_FIELD;
551 else /* REDRAW_ALL */
558 fade_delay = title.fade_delay_final;
559 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? title.post_delay_final : 0);
562 redraw_mask |= fade_mask;
564 if (!setup.fade_screens || fade_delay == 0)
566 if (fade_mode == FADE_MODE_FADE_OUT)
567 ClearRectangle(backbuffer, x, y, width, height);
574 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
575 draw_border_function);
577 redraw_mask &= ~fade_mask;
580 void FadeIn(int fade_mask)
582 FadeExt(fade_mask, FADE_MODE_FADE_IN);
585 void FadeOut(int fade_mask)
587 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
590 void FadeCross(int fade_mask)
592 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
595 void FadeCrossSaveBackbuffer()
597 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
600 void SetMainBackgroundImageIfDefined(int graphic)
602 if (graphic_info[graphic].bitmap)
603 SetMainBackgroundImage(graphic);
606 void SetMainBackgroundImage(int graphic)
608 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
609 graphic_info[graphic].bitmap ?
610 graphic_info[graphic].bitmap :
611 graphic_info[IMG_BACKGROUND].bitmap);
614 void SetDoorBackgroundImage(int graphic)
616 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
617 graphic_info[graphic].bitmap ?
618 graphic_info[graphic].bitmap :
619 graphic_info[IMG_BACKGROUND].bitmap);
622 void SetPanelBackground()
624 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
625 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
627 SetDoorBackgroundBitmap(bitmap_db_panel);
630 void DrawBackground(int x, int y, int width, int height)
632 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
633 /* (when entering hall of fame after playing) */
635 ClearRectangleOnBackground(drawto, x, y, width, height);
637 ClearRectangleOnBackground(backbuffer, x, y, width, height);
640 redraw_mask |= REDRAW_FIELD;
643 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
645 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
647 if (font->bitmap == NULL)
650 DrawBackground(x, y, width, height);
653 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
655 struct GraphicInfo *g = &graphic_info[graphic];
657 if (g->bitmap == NULL)
660 DrawBackground(x, y, width, height);
665 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
666 /* (when entering hall of fame after playing) */
667 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
669 /* !!! maybe this should be done before clearing the background !!! */
670 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
672 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
673 SetDrawtoField(DRAW_BUFFERED);
676 SetDrawtoField(DRAW_BACKBUFFER);
678 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
680 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
681 SetDrawtoField(DRAW_DIRECT);
685 void MarkTileDirty(int x, int y)
687 int xx = redraw_x1 + x;
688 int yy = redraw_y1 + y;
693 redraw[xx][yy] = TRUE;
694 redraw_mask |= REDRAW_TILES;
697 void SetBorderElement()
701 BorderElement = EL_EMPTY;
703 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
705 for (x = 0; x < lev_fieldx; x++)
707 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
708 BorderElement = EL_STEELWALL;
710 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
716 void SetRandomAnimationValue(int x, int y)
718 gfx.anim_random_frame = GfxRandom[x][y];
721 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
723 /* animation synchronized with global frame counter, not move position */
724 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
725 sync_frame = FrameCounter;
727 return getAnimationFrame(graphic_info[graphic].anim_frames,
728 graphic_info[graphic].anim_delay,
729 graphic_info[graphic].anim_mode,
730 graphic_info[graphic].anim_start_frame,
734 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
735 int *x, int *y, boolean get_backside)
737 struct GraphicInfo *g = &graphic_info[graphic];
738 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
739 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
743 if (g->offset_y == 0) /* frames are ordered horizontally */
745 int max_width = g->anim_frames_per_line * g->width;
746 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
748 *x = pos % max_width;
749 *y = src_y % g->height + pos / max_width * g->height;
751 else if (g->offset_x == 0) /* frames are ordered vertically */
753 int max_height = g->anim_frames_per_line * g->height;
754 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
756 *x = src_x % g->width + pos / max_height * g->width;
757 *y = pos % max_height;
759 else /* frames are ordered diagonally */
761 *x = src_x + frame * g->offset_x;
762 *y = src_y + frame * g->offset_y;
766 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
768 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
771 void DrawGraphic(int x, int y, int graphic, int frame)
774 if (!IN_SCR_FIELD(x, y))
776 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
777 printf("DrawGraphic(): This should never happen!\n");
782 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
786 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
792 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
793 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
796 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
799 if (!IN_SCR_FIELD(x, y))
801 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
802 printf("DrawGraphicThruMask(): This should never happen!\n");
807 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
812 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
818 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
820 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
821 dst_x - src_x, dst_y - src_y);
822 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
825 void DrawMiniGraphic(int x, int y, int graphic)
827 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
828 MarkTileDirty(x / 2, y / 2);
831 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
833 struct GraphicInfo *g = &graphic_info[graphic];
835 int mini_starty = g->bitmap->height * 2 / 3;
838 *x = mini_startx + g->src_x / 2;
839 *y = mini_starty + g->src_y / 2;
842 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
847 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
848 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
851 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
852 int graphic, int frame,
853 int cut_mode, int mask_mode)
858 int width = TILEX, height = TILEY;
861 if (dx || dy) /* shifted graphic */
863 if (x < BX1) /* object enters playfield from the left */
870 else if (x > BX2) /* object enters playfield from the right */
876 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
882 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
884 else if (dx) /* general horizontal movement */
885 MarkTileDirty(x + SIGN(dx), y);
887 if (y < BY1) /* object enters playfield from the top */
889 if (cut_mode==CUT_BELOW) /* object completely above top border */
897 else if (y > BY2) /* object enters playfield from the bottom */
903 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
909 else if (dy > 0 && cut_mode == CUT_ABOVE)
911 if (y == BY2) /* object completely above bottom border */
917 MarkTileDirty(x, y + 1);
918 } /* object leaves playfield to the bottom */
919 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
921 else if (dy) /* general vertical movement */
922 MarkTileDirty(x, y + SIGN(dy));
926 if (!IN_SCR_FIELD(x, y))
928 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
929 printf("DrawGraphicShifted(): This should never happen!\n");
934 if (width > 0 && height > 0)
936 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
941 dst_x = FX + x * TILEX + dx;
942 dst_y = FY + y * TILEY + dy;
944 if (mask_mode == USE_MASKING)
946 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
947 dst_x - src_x, dst_y - src_y);
948 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
952 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
959 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
960 int graphic, int frame,
961 int cut_mode, int mask_mode)
966 int width = TILEX, height = TILEY;
969 int x2 = x + SIGN(dx);
970 int y2 = y + SIGN(dy);
971 int anim_frames = graphic_info[graphic].anim_frames;
972 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
973 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
974 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
976 /* re-calculate animation frame for two-tile movement animation */
977 frame = getGraphicAnimationFrame(graphic, sync_frame);
979 /* check if movement start graphic inside screen area and should be drawn */
980 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
982 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
984 dst_x = FX + x1 * TILEX;
985 dst_y = FY + y1 * TILEY;
987 if (mask_mode == USE_MASKING)
989 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
990 dst_x - src_x, dst_y - src_y);
991 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
995 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
998 MarkTileDirty(x1, y1);
1001 /* check if movement end graphic inside screen area and should be drawn */
1002 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1004 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1006 dst_x = FX + x2 * TILEX;
1007 dst_y = FY + y2 * TILEY;
1009 if (mask_mode == USE_MASKING)
1011 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1012 dst_x - src_x, dst_y - src_y);
1013 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1017 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1020 MarkTileDirty(x2, y2);
1024 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1025 int graphic, int frame,
1026 int cut_mode, int mask_mode)
1030 DrawGraphic(x, y, graphic, frame);
1035 if (graphic_info[graphic].double_movement) /* EM style movement images */
1036 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1038 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1041 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1042 int frame, int cut_mode)
1044 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1047 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1048 int cut_mode, int mask_mode)
1050 int lx = LEVELX(x), ly = LEVELY(y);
1054 if (IN_LEV_FIELD(lx, ly))
1056 SetRandomAnimationValue(lx, ly);
1058 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1059 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1061 /* do not use double (EM style) movement graphic when not moving */
1062 if (graphic_info[graphic].double_movement && !dx && !dy)
1064 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1065 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1068 else /* border element */
1070 graphic = el2img(element);
1071 frame = getGraphicAnimationFrame(graphic, -1);
1074 if (element == EL_EXPANDABLE_WALL)
1076 boolean left_stopped = FALSE, right_stopped = FALSE;
1078 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1079 left_stopped = TRUE;
1080 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1081 right_stopped = TRUE;
1083 if (left_stopped && right_stopped)
1085 else if (left_stopped)
1087 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1088 frame = graphic_info[graphic].anim_frames - 1;
1090 else if (right_stopped)
1092 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1093 frame = graphic_info[graphic].anim_frames - 1;
1098 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1099 else if (mask_mode == USE_MASKING)
1100 DrawGraphicThruMask(x, y, graphic, frame);
1102 DrawGraphic(x, y, graphic, frame);
1105 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1106 int cut_mode, int mask_mode)
1108 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1109 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1110 cut_mode, mask_mode);
1113 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1116 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1119 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1122 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1125 void DrawLevelElementThruMask(int x, int y, int element)
1127 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1130 void DrawLevelFieldThruMask(int x, int y)
1132 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1135 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1139 int sx = SCREENX(x), sy = SCREENY(y);
1141 int width, height, cx, cy, i;
1142 int crumbled_border_size = graphic_info[graphic].border_size;
1143 static int xy[4][2] =
1151 if (!IN_LEV_FIELD(x, y))
1154 element = TILE_GFX_ELEMENT(x, y);
1156 /* crumble field itself */
1157 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1159 if (!IN_SCR_FIELD(sx, sy))
1162 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1164 for (i = 0; i < 4; i++)
1166 int xx = x + xy[i][0];
1167 int yy = y + xy[i][1];
1169 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1172 /* check if neighbour field is of same type */
1173 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1176 if (i == 1 || i == 2)
1178 width = crumbled_border_size;
1180 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1186 height = crumbled_border_size;
1188 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1191 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1192 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1195 MarkTileDirty(sx, sy);
1197 else /* crumble neighbour fields */
1199 for (i = 0; i < 4; i++)
1201 int xx = x + xy[i][0];
1202 int yy = y + xy[i][1];
1203 int sxx = sx + xy[i][0];
1204 int syy = sy + xy[i][1];
1206 if (!IN_LEV_FIELD(xx, yy) ||
1207 !IN_SCR_FIELD(sxx, syy) ||
1211 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1214 element = TILE_GFX_ELEMENT(xx, yy);
1216 if (!GFX_CRUMBLED(element))
1219 graphic = el_act2crm(element, ACTION_DEFAULT);
1220 crumbled_border_size = graphic_info[graphic].border_size;
1222 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1224 if (i == 1 || i == 2)
1226 width = crumbled_border_size;
1228 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1234 height = crumbled_border_size;
1236 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1239 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1240 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1242 MarkTileDirty(sxx, syy);
1247 void DrawLevelFieldCrumbledSand(int x, int y)
1251 if (!IN_LEV_FIELD(x, y))
1255 /* !!! CHECK THIS !!! */
1258 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1259 GFX_CRUMBLED(GfxElement[x][y]))
1262 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1263 GfxElement[x][y] != EL_UNDEFINED &&
1264 GFX_CRUMBLED(GfxElement[x][y]))
1266 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1273 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1275 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1278 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1281 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1284 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1285 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1286 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1287 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1288 int sx = SCREENX(x), sy = SCREENY(y);
1290 DrawGraphic(sx, sy, graphic1, frame1);
1291 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1294 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1296 int sx = SCREENX(x), sy = SCREENY(y);
1297 static int xy[4][2] =
1306 for (i = 0; i < 4; i++)
1308 int xx = x + xy[i][0];
1309 int yy = y + xy[i][1];
1310 int sxx = sx + xy[i][0];
1311 int syy = sy + xy[i][1];
1313 if (!IN_LEV_FIELD(xx, yy) ||
1314 !IN_SCR_FIELD(sxx, syy) ||
1315 !GFX_CRUMBLED(Feld[xx][yy]) ||
1319 DrawLevelField(xx, yy);
1323 static int getBorderElement(int x, int y)
1327 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1328 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1329 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1330 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1331 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1332 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1333 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1335 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1336 int steel_position = (x == -1 && y == -1 ? 0 :
1337 x == lev_fieldx && y == -1 ? 1 :
1338 x == -1 && y == lev_fieldy ? 2 :
1339 x == lev_fieldx && y == lev_fieldy ? 3 :
1340 x == -1 || x == lev_fieldx ? 4 :
1341 y == -1 || y == lev_fieldy ? 5 : 6);
1343 return border[steel_position][steel_type];
1346 void DrawScreenElement(int x, int y, int element)
1348 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1349 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1352 void DrawLevelElement(int x, int y, int element)
1354 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1355 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1358 void DrawScreenField(int x, int y)
1360 int lx = LEVELX(x), ly = LEVELY(y);
1361 int element, content;
1363 if (!IN_LEV_FIELD(lx, ly))
1365 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1368 element = getBorderElement(lx, ly);
1370 DrawScreenElement(x, y, element);
1374 element = Feld[lx][ly];
1375 content = Store[lx][ly];
1377 if (IS_MOVING(lx, ly))
1379 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1380 boolean cut_mode = NO_CUTTING;
1382 if (element == EL_QUICKSAND_EMPTYING ||
1383 element == EL_MAGIC_WALL_EMPTYING ||
1384 element == EL_BD_MAGIC_WALL_EMPTYING ||
1385 element == EL_AMOEBA_DROPPING)
1386 cut_mode = CUT_ABOVE;
1387 else if (element == EL_QUICKSAND_FILLING ||
1388 element == EL_MAGIC_WALL_FILLING ||
1389 element == EL_BD_MAGIC_WALL_FILLING)
1390 cut_mode = CUT_BELOW;
1392 if (cut_mode == CUT_ABOVE)
1393 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1395 DrawScreenElement(x, y, EL_EMPTY);
1398 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1399 else if (cut_mode == NO_CUTTING)
1400 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1402 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1404 if (content == EL_ACID)
1406 int dir = MovDir[lx][ly];
1407 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1408 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1410 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1413 else if (IS_BLOCKED(lx, ly))
1418 boolean cut_mode = NO_CUTTING;
1419 int element_old, content_old;
1421 Blocked2Moving(lx, ly, &oldx, &oldy);
1424 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1425 MovDir[oldx][oldy] == MV_RIGHT);
1427 element_old = Feld[oldx][oldy];
1428 content_old = Store[oldx][oldy];
1430 if (element_old == EL_QUICKSAND_EMPTYING ||
1431 element_old == EL_MAGIC_WALL_EMPTYING ||
1432 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1433 element_old == EL_AMOEBA_DROPPING)
1434 cut_mode = CUT_ABOVE;
1436 DrawScreenElement(x, y, EL_EMPTY);
1439 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1441 else if (cut_mode == NO_CUTTING)
1442 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1445 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1448 else if (IS_DRAWABLE(element))
1449 DrawScreenElement(x, y, element);
1451 DrawScreenElement(x, y, EL_EMPTY);
1454 void DrawLevelField(int x, int y)
1456 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1457 DrawScreenField(SCREENX(x), SCREENY(y));
1458 else if (IS_MOVING(x, y))
1462 Moving2Blocked(x, y, &newx, &newy);
1463 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1464 DrawScreenField(SCREENX(newx), SCREENY(newy));
1466 else if (IS_BLOCKED(x, y))
1470 Blocked2Moving(x, y, &oldx, &oldy);
1471 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1472 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1476 void DrawMiniElement(int x, int y, int element)
1480 graphic = el2edimg(element);
1481 DrawMiniGraphic(x, y, graphic);
1484 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1486 int x = sx + scroll_x, y = sy + scroll_y;
1488 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1489 DrawMiniElement(sx, sy, EL_EMPTY);
1490 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1491 DrawMiniElement(sx, sy, Feld[x][y]);
1493 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1496 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1497 int x, int y, int xsize, int ysize, int font_nr)
1499 int font_width = getFontWidth(font_nr);
1500 int font_height = getFontHeight(font_nr);
1501 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1504 int dst_x = SX + startx + x * font_width;
1505 int dst_y = SY + starty + y * font_height;
1506 int width = graphic_info[graphic].width;
1507 int height = graphic_info[graphic].height;
1508 int inner_width = MAX(width - 2 * font_width, font_width);
1509 int inner_height = MAX(height - 2 * font_height, font_height);
1510 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1511 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1512 boolean draw_masked = graphic_info[graphic].draw_masked;
1514 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1516 if (src_bitmap == NULL || width < font_width || height < font_height)
1518 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1522 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1523 inner_sx + (x - 1) * font_width % inner_width);
1524 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1525 inner_sy + (y - 1) * font_height % inner_height);
1529 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1530 dst_x - src_x, dst_y - src_y);
1531 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1535 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1539 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1541 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1542 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1543 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1544 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1545 boolean no_delay = (tape.warp_forward);
1546 unsigned long anim_delay = 0;
1547 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1548 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1549 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1550 int font_width = getFontWidth(font_nr);
1551 int font_height = getFontHeight(font_nr);
1552 int max_xsize = level.envelope[envelope_nr].xsize;
1553 int max_ysize = level.envelope[envelope_nr].ysize;
1554 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1555 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1556 int xend = max_xsize;
1557 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1558 int xstep = (xstart < xend ? 1 : 0);
1559 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1562 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1564 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1565 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1566 int sx = (SXSIZE - xsize * font_width) / 2;
1567 int sy = (SYSIZE - ysize * font_height) / 2;
1570 SetDrawtoField(DRAW_BUFFERED);
1572 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1574 SetDrawtoField(DRAW_BACKBUFFER);
1576 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1577 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1579 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1580 level.envelope[envelope_nr].text, font_nr, max_xsize,
1581 xsize - 2, ysize - 2, mask_mode);
1583 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1586 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1590 void ShowEnvelope(int envelope_nr)
1592 int element = EL_ENVELOPE_1 + envelope_nr;
1593 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1594 int sound_opening = element_info[element].sound[ACTION_OPENING];
1595 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1596 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1597 boolean no_delay = (tape.warp_forward);
1598 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1599 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1600 int anim_mode = graphic_info[graphic].anim_mode;
1601 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1602 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1604 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1606 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1608 if (anim_mode == ANIM_DEFAULT)
1609 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1611 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1614 Delay(wait_delay_value);
1616 WaitForEventToContinue();
1618 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1620 if (anim_mode != ANIM_NONE)
1621 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1623 if (anim_mode == ANIM_DEFAULT)
1624 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1626 game.envelope_active = FALSE;
1628 SetDrawtoField(DRAW_BUFFERED);
1630 redraw_mask |= REDRAW_FIELD;
1634 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1639 int width_mult, width_div;
1640 int height_mult, height_div;
1648 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1649 5 - log_2(tilesize));
1650 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1651 int width_mult = offset_calc[offset_calc_pos].width_mult;
1652 int width_div = offset_calc[offset_calc_pos].width_div;
1653 int height_mult = offset_calc[offset_calc_pos].height_mult;
1654 int height_div = offset_calc[offset_calc_pos].height_div;
1655 int mini_startx = src_bitmap->width * width_mult / width_div;
1656 int mini_starty = src_bitmap->height * height_mult / height_div;
1657 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1658 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1660 *bitmap = src_bitmap;
1665 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1669 int graphic = el2preimg(element);
1671 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1672 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1679 SetDrawBackgroundMask(REDRAW_NONE);
1682 for (x = BX1; x <= BX2; x++)
1683 for (y = BY1; y <= BY2; y++)
1684 DrawScreenField(x, y);
1686 redraw_mask |= REDRAW_FIELD;
1689 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1693 for (x = 0; x < size_x; x++)
1694 for (y = 0; y < size_y; y++)
1695 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1697 redraw_mask |= REDRAW_FIELD;
1700 static void DrawPreviewLevelExt(int from_x, int from_y)
1702 boolean show_level_border = (BorderElement != EL_EMPTY);
1703 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1704 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1705 int tile_size = preview.tile_size;
1706 int preview_width = preview.xsize * tile_size;
1707 int preview_height = preview.ysize * tile_size;
1708 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1709 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1710 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1711 int dst_y = SY + preview.y;
1714 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1716 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1717 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1719 for (x = 0; x < real_preview_xsize; x++)
1721 for (y = 0; y < real_preview_ysize; y++)
1723 int lx = from_x + x + (show_level_border ? -1 : 0);
1724 int ly = from_y + y + (show_level_border ? -1 : 0);
1725 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1726 getBorderElement(lx, ly));
1728 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1729 element, tile_size);
1733 redraw_mask |= REDRAW_MICROLEVEL;
1736 #define MICROLABEL_EMPTY 0
1737 #define MICROLABEL_LEVEL_NAME 1
1738 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1739 #define MICROLABEL_LEVEL_AUTHOR 3
1740 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1741 #define MICROLABEL_IMPORTED_FROM 5
1742 #define MICROLABEL_IMPORTED_BY_HEAD 6
1743 #define MICROLABEL_IMPORTED_BY 7
1745 static int getMaxTextLength(struct MenuPosInfo *pos, int font_nr)
1747 int max_text_width = SXSIZE;
1748 int font_width = getFontWidth(font_nr);
1750 if (pos->align == ALIGN_CENTER)
1751 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1752 else if (pos->align == ALIGN_RIGHT)
1753 max_text_width = pos->x;
1755 max_text_width = SXSIZE - pos->x;
1757 return max_text_width / font_width;
1760 static void DrawPreviewLevelLabelExt(int mode)
1762 struct MenuPosInfo *pos = &menu.main.text.level_info_2;
1763 char label_text[MAX_OUTPUT_LINESIZE + 1];
1764 int max_len_label_text;
1765 int font_nr = FONT_TEXT_2;
1768 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1769 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1770 mode == MICROLABEL_IMPORTED_BY_HEAD)
1771 font_nr = FONT_TEXT_3;
1774 max_len_label_text = getMaxTextLength(pos, font_nr);
1776 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1779 for (i = 0; i < max_len_label_text; i++)
1780 label_text[i] = ' ';
1781 label_text[max_len_label_text] = '\0';
1783 if (strlen(label_text) > 0)
1786 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1788 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1789 int lypos = MICROLABEL2_YPOS;
1791 DrawText(lxpos, lypos, label_text, font_nr);
1796 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1797 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1798 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1799 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1800 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1801 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1802 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1803 max_len_label_text);
1804 label_text[max_len_label_text] = '\0';
1806 if (strlen(label_text) > 0)
1809 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1811 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1812 int lypos = MICROLABEL2_YPOS;
1814 DrawText(lxpos, lypos, label_text, font_nr);
1818 redraw_mask |= REDRAW_MICROLEVEL;
1821 void DrawPreviewLevel(boolean restart)
1823 static unsigned long scroll_delay = 0;
1824 static unsigned long label_delay = 0;
1825 static int from_x, from_y, scroll_direction;
1826 static int label_state, label_counter;
1827 unsigned long scroll_delay_value = preview.step_delay;
1828 boolean show_level_border = (BorderElement != EL_EMPTY);
1829 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1830 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1831 int last_game_status = game_status; /* save current game status */
1833 /* force PREVIEW font on preview level */
1834 game_status = GAME_MODE_PSEUDO_PREVIEW;
1841 if (preview.anim_mode == ANIM_CENTERED)
1843 if (level_xsize > preview.xsize)
1844 from_x = (level_xsize - preview.xsize) / 2;
1845 if (level_ysize > preview.ysize)
1846 from_y = (level_ysize - preview.ysize) / 2;
1849 from_x += preview.xoffset;
1850 from_y += preview.yoffset;
1852 scroll_direction = MV_RIGHT;
1856 DrawPreviewLevelExt(from_x, from_y);
1857 DrawPreviewLevelLabelExt(label_state);
1859 /* initialize delay counters */
1860 DelayReached(&scroll_delay, 0);
1861 DelayReached(&label_delay, 0);
1863 if (leveldir_current->name)
1865 struct MenuPosInfo *pos = &menu.main.text.level_info_1;
1866 char label_text[MAX_OUTPUT_LINESIZE + 1];
1867 int font_nr = FONT_TEXT_1;
1869 int max_len_label_text = getMaxTextLength(pos, font_nr);
1871 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1878 strncpy(label_text, leveldir_current->name, max_len_label_text);
1879 label_text[max_len_label_text] = '\0';
1882 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1884 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1885 lypos = SY + MICROLABEL1_YPOS;
1887 DrawText(lxpos, lypos, label_text, font_nr);
1891 game_status = last_game_status; /* restore current game status */
1896 /* scroll preview level, if needed */
1897 if (preview.anim_mode != ANIM_NONE &&
1898 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1899 DelayReached(&scroll_delay, scroll_delay_value))
1901 switch (scroll_direction)
1906 from_x -= preview.step_offset;
1907 from_x = (from_x < 0 ? 0 : from_x);
1910 scroll_direction = MV_UP;
1914 if (from_x < level_xsize - preview.xsize)
1916 from_x += preview.step_offset;
1917 from_x = (from_x > level_xsize - preview.xsize ?
1918 level_xsize - preview.xsize : from_x);
1921 scroll_direction = MV_DOWN;
1927 from_y -= preview.step_offset;
1928 from_y = (from_y < 0 ? 0 : from_y);
1931 scroll_direction = MV_RIGHT;
1935 if (from_y < level_ysize - preview.ysize)
1937 from_y += preview.step_offset;
1938 from_y = (from_y > level_ysize - preview.ysize ?
1939 level_ysize - preview.ysize : from_y);
1942 scroll_direction = MV_LEFT;
1949 DrawPreviewLevelExt(from_x, from_y);
1952 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1953 /* redraw micro level label, if needed */
1954 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1955 !strEqual(level.author, ANONYMOUS_NAME) &&
1956 !strEqual(level.author, leveldir_current->name) &&
1957 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1959 int max_label_counter = 23;
1961 if (leveldir_current->imported_from != NULL &&
1962 strlen(leveldir_current->imported_from) > 0)
1963 max_label_counter += 14;
1964 if (leveldir_current->imported_by != NULL &&
1965 strlen(leveldir_current->imported_by) > 0)
1966 max_label_counter += 14;
1968 label_counter = (label_counter + 1) % max_label_counter;
1969 label_state = (label_counter >= 0 && label_counter <= 7 ?
1970 MICROLABEL_LEVEL_NAME :
1971 label_counter >= 9 && label_counter <= 12 ?
1972 MICROLABEL_LEVEL_AUTHOR_HEAD :
1973 label_counter >= 14 && label_counter <= 21 ?
1974 MICROLABEL_LEVEL_AUTHOR :
1975 label_counter >= 23 && label_counter <= 26 ?
1976 MICROLABEL_IMPORTED_FROM_HEAD :
1977 label_counter >= 28 && label_counter <= 35 ?
1978 MICROLABEL_IMPORTED_FROM :
1979 label_counter >= 37 && label_counter <= 40 ?
1980 MICROLABEL_IMPORTED_BY_HEAD :
1981 label_counter >= 42 && label_counter <= 49 ?
1982 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1984 if (leveldir_current->imported_from == NULL &&
1985 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1986 label_state == MICROLABEL_IMPORTED_FROM))
1987 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1988 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1990 DrawPreviewLevelLabelExt(label_state);
1993 game_status = last_game_status; /* restore current game status */
1996 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1997 int graphic, int sync_frame, int mask_mode)
1999 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2001 if (mask_mode == USE_MASKING)
2002 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2004 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2007 inline void DrawGraphicAnimation(int x, int y, int graphic)
2009 int lx = LEVELX(x), ly = LEVELY(y);
2011 if (!IN_SCR_FIELD(x, y))
2014 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2015 graphic, GfxFrame[lx][ly], NO_MASKING);
2016 MarkTileDirty(x, y);
2019 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2021 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2024 void DrawLevelElementAnimation(int x, int y, int element)
2026 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2028 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2031 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2033 int sx = SCREENX(x), sy = SCREENY(y);
2035 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2038 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2041 DrawGraphicAnimation(sx, sy, graphic);
2044 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2045 DrawLevelFieldCrumbledSand(x, y);
2047 if (GFX_CRUMBLED(Feld[x][y]))
2048 DrawLevelFieldCrumbledSand(x, y);
2052 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2054 int sx = SCREENX(x), sy = SCREENY(y);
2057 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2060 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2062 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2065 DrawGraphicAnimation(sx, sy, graphic);
2067 if (GFX_CRUMBLED(element))
2068 DrawLevelFieldCrumbledSand(x, y);
2071 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2073 if (player->use_murphy)
2075 /* this works only because currently only one player can be "murphy" ... */
2076 static int last_horizontal_dir = MV_LEFT;
2077 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2079 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2080 last_horizontal_dir = move_dir;
2082 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2084 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2086 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2092 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2095 static boolean equalGraphics(int graphic1, int graphic2)
2097 struct GraphicInfo *g1 = &graphic_info[graphic1];
2098 struct GraphicInfo *g2 = &graphic_info[graphic2];
2100 return (g1->bitmap == g2->bitmap &&
2101 g1->src_x == g2->src_x &&
2102 g1->src_y == g2->src_y &&
2103 g1->anim_frames == g2->anim_frames &&
2104 g1->anim_delay == g2->anim_delay &&
2105 g1->anim_mode == g2->anim_mode);
2108 void DrawAllPlayers()
2112 for (i = 0; i < MAX_PLAYERS; i++)
2113 if (stored_player[i].active)
2114 DrawPlayer(&stored_player[i]);
2117 void DrawPlayerField(int x, int y)
2119 if (!IS_PLAYER(x, y))
2122 DrawPlayer(PLAYERINFO(x, y));
2125 void DrawPlayer(struct PlayerInfo *player)
2127 int jx = player->jx;
2128 int jy = player->jy;
2129 int move_dir = player->MovDir;
2130 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2131 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2132 int last_jx = (player->is_moving ? jx - dx : jx);
2133 int last_jy = (player->is_moving ? jy - dy : jy);
2134 int next_jx = jx + dx;
2135 int next_jy = jy + dy;
2136 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2137 boolean player_is_opaque = FALSE;
2138 int sx = SCREENX(jx), sy = SCREENY(jy);
2139 int sxx = 0, syy = 0;
2140 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2142 int action = ACTION_DEFAULT;
2143 int last_player_graphic = getPlayerGraphic(player, move_dir);
2144 int last_player_frame = player->Frame;
2147 /* GfxElement[][] is set to the element the player is digging or collecting;
2148 remove also for off-screen player if the player is not moving anymore */
2149 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2150 GfxElement[jx][jy] = EL_UNDEFINED;
2152 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2156 if (!IN_LEV_FIELD(jx, jy))
2158 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2159 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2160 printf("DrawPlayerField(): This should never happen!\n");
2165 if (element == EL_EXPLOSION)
2168 action = (player->is_pushing ? ACTION_PUSHING :
2169 player->is_digging ? ACTION_DIGGING :
2170 player->is_collecting ? ACTION_COLLECTING :
2171 player->is_moving ? ACTION_MOVING :
2172 player->is_snapping ? ACTION_SNAPPING :
2173 player->is_dropping ? ACTION_DROPPING :
2174 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2176 if (player->is_waiting)
2177 move_dir = player->dir_waiting;
2179 InitPlayerGfxAnimation(player, action, move_dir);
2181 /* ----------------------------------------------------------------------- */
2182 /* draw things in the field the player is leaving, if needed */
2183 /* ----------------------------------------------------------------------- */
2185 if (player->is_moving)
2187 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2189 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2191 if (last_element == EL_DYNAMITE_ACTIVE ||
2192 last_element == EL_EM_DYNAMITE_ACTIVE ||
2193 last_element == EL_SP_DISK_RED_ACTIVE)
2194 DrawDynamite(last_jx, last_jy);
2196 DrawLevelFieldThruMask(last_jx, last_jy);
2198 else if (last_element == EL_DYNAMITE_ACTIVE ||
2199 last_element == EL_EM_DYNAMITE_ACTIVE ||
2200 last_element == EL_SP_DISK_RED_ACTIVE)
2201 DrawDynamite(last_jx, last_jy);
2203 /* !!! this is not enough to prevent flickering of players which are
2204 moving next to each others without a free tile between them -- this
2205 can only be solved by drawing all players layer by layer (first the
2206 background, then the foreground etc.) !!! => TODO */
2207 else if (!IS_PLAYER(last_jx, last_jy))
2208 DrawLevelField(last_jx, last_jy);
2211 DrawLevelField(last_jx, last_jy);
2214 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2215 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2218 if (!IN_SCR_FIELD(sx, sy))
2221 if (setup.direct_draw)
2222 SetDrawtoField(DRAW_BUFFERED);
2224 /* ----------------------------------------------------------------------- */
2225 /* draw things behind the player, if needed */
2226 /* ----------------------------------------------------------------------- */
2229 DrawLevelElement(jx, jy, Back[jx][jy]);
2230 else if (IS_ACTIVE_BOMB(element))
2231 DrawLevelElement(jx, jy, EL_EMPTY);
2234 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2236 int old_element = GfxElement[jx][jy];
2237 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2238 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2240 if (GFX_CRUMBLED(old_element))
2241 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2243 DrawGraphic(sx, sy, old_graphic, frame);
2245 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2246 player_is_opaque = TRUE;
2250 GfxElement[jx][jy] = EL_UNDEFINED;
2252 /* make sure that pushed elements are drawn with correct frame rate */
2254 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2256 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2257 GfxFrame[jx][jy] = player->StepFrame;
2259 if (player->is_pushing && player->is_moving)
2260 GfxFrame[jx][jy] = player->StepFrame;
2263 DrawLevelField(jx, jy);
2267 /* ----------------------------------------------------------------------- */
2268 /* draw player himself */
2269 /* ----------------------------------------------------------------------- */
2271 graphic = getPlayerGraphic(player, move_dir);
2273 /* in the case of changed player action or direction, prevent the current
2274 animation frame from being restarted for identical animations */
2275 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2276 player->Frame = last_player_frame;
2278 frame = getGraphicAnimationFrame(graphic, player->Frame);
2282 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2283 sxx = player->GfxPos;
2285 syy = player->GfxPos;
2288 if (!setup.soft_scrolling && ScreenMovPos)
2291 if (player_is_opaque)
2292 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2294 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2296 if (SHIELD_ON(player))
2298 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2299 IMG_SHIELD_NORMAL_ACTIVE);
2300 int frame = getGraphicAnimationFrame(graphic, -1);
2302 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2305 /* ----------------------------------------------------------------------- */
2306 /* draw things the player is pushing, if needed */
2307 /* ----------------------------------------------------------------------- */
2310 printf("::: %d, %d [%d, %d] [%d]\n",
2311 player->is_pushing, player_is_moving, player->GfxAction,
2312 player->is_moving, player_is_moving);
2316 if (player->is_pushing && player->is_moving)
2318 int px = SCREENX(jx), py = SCREENY(jy);
2319 int pxx = (TILEX - ABS(sxx)) * dx;
2320 int pyy = (TILEY - ABS(syy)) * dy;
2321 int gfx_frame = GfxFrame[jx][jy];
2327 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2329 element = Feld[next_jx][next_jy];
2330 gfx_frame = GfxFrame[next_jx][next_jy];
2333 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2336 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2337 frame = getGraphicAnimationFrame(graphic, sync_frame);
2339 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2342 /* draw background element under pushed element (like the Sokoban field) */
2343 if (Back[next_jx][next_jy])
2344 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2346 /* masked drawing is needed for EMC style (double) movement graphics */
2347 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2351 /* ----------------------------------------------------------------------- */
2352 /* draw things in front of player (active dynamite or dynabombs) */
2353 /* ----------------------------------------------------------------------- */
2355 if (IS_ACTIVE_BOMB(element))
2357 graphic = el2img(element);
2358 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2360 if (game.emulation == EMU_SUPAPLEX)
2361 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2363 DrawGraphicThruMask(sx, sy, graphic, frame);
2366 if (player_is_moving && last_element == EL_EXPLOSION)
2368 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2369 GfxElement[last_jx][last_jy] : EL_EMPTY);
2370 int graphic = el_act2img(element, ACTION_EXPLODING);
2371 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2372 int phase = ExplodePhase[last_jx][last_jy] - 1;
2373 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2376 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2379 /* ----------------------------------------------------------------------- */
2380 /* draw elements the player is just walking/passing through/under */
2381 /* ----------------------------------------------------------------------- */
2383 if (player_is_moving)
2385 /* handle the field the player is leaving ... */
2386 if (IS_ACCESSIBLE_INSIDE(last_element))
2387 DrawLevelField(last_jx, last_jy);
2388 else if (IS_ACCESSIBLE_UNDER(last_element))
2389 DrawLevelFieldThruMask(last_jx, last_jy);
2392 /* do not redraw accessible elements if the player is just pushing them */
2393 if (!player_is_moving || !player->is_pushing)
2395 /* ... and the field the player is entering */
2396 if (IS_ACCESSIBLE_INSIDE(element))
2397 DrawLevelField(jx, jy);
2398 else if (IS_ACCESSIBLE_UNDER(element))
2399 DrawLevelFieldThruMask(jx, jy);
2402 if (setup.direct_draw)
2404 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2405 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2406 int x_size = TILEX * (1 + ABS(jx - last_jx));
2407 int y_size = TILEY * (1 + ABS(jy - last_jy));
2409 BlitBitmap(drawto_field, window,
2410 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2411 SetDrawtoField(DRAW_DIRECT);
2414 MarkTileDirty(sx, sy);
2417 /* ------------------------------------------------------------------------- */
2419 void WaitForEventToContinue()
2421 boolean still_wait = TRUE;
2423 /* simulate releasing mouse button over last gadget, if still pressed */
2425 HandleGadgets(-1, -1, 0);
2427 button_status = MB_RELEASED;
2443 case EVENT_BUTTONPRESS:
2444 case EVENT_KEYPRESS:
2448 case EVENT_KEYRELEASE:
2449 ClearPlayerAction();
2453 HandleOtherEvents(&event);
2457 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2464 /* don't eat all CPU time */
2469 #define MAX_REQUEST_LINES 13
2470 #define MAX_REQUEST_LINE_FONT1_LEN 7
2471 #define MAX_REQUEST_LINE_FONT2_LEN 10
2473 boolean Request(char *text, unsigned int req_state)
2475 int mx, my, ty, result = -1;
2476 unsigned int old_door_state;
2477 int last_game_status = game_status; /* save current game status */
2478 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2479 int font_nr = FONT_TEXT_2;
2480 int max_word_len = 0;
2483 for (text_ptr = text; *text_ptr; text_ptr++)
2485 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2487 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2489 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2490 font_nr = FONT_LEVEL_NUMBER;
2496 if (game_status == GAME_MODE_PLAYING &&
2497 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2498 BlitScreenToBitmap_EM(backbuffer);
2500 /* disable deactivated drawing when quick-loading level tape recording */
2501 if (tape.playing && tape.deactivate_display)
2502 TapeDeactivateDisplayOff(TRUE);
2504 SetMouseCursor(CURSOR_DEFAULT);
2506 #if defined(NETWORK_AVALIABLE)
2507 /* pause network game while waiting for request to answer */
2508 if (options.network &&
2509 game_status == GAME_MODE_PLAYING &&
2510 req_state & REQUEST_WAIT_FOR_INPUT)
2511 SendToServer_PausePlaying();
2514 old_door_state = GetDoorState();
2516 /* simulate releasing mouse button over last gadget, if still pressed */
2518 HandleGadgets(-1, -1, 0);
2522 if (old_door_state & DOOR_OPEN_1)
2524 CloseDoor(DOOR_CLOSE_1);
2526 /* save old door content */
2527 BlitBitmap(bitmap_db_door, bitmap_db_door,
2528 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2529 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2533 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2536 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2538 /* clear door drawing field */
2539 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2541 /* force DOOR font on preview level */
2542 game_status = GAME_MODE_PSEUDO_DOOR;
2544 /* write text for request */
2545 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2547 char text_line[max_request_line_len + 1];
2553 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2556 if (!tc || tc == ' ')
2567 strncpy(text_line, text, tl);
2570 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2571 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2572 text_line, font_nr);
2574 text += tl + (tc == ' ' ? 1 : 0);
2577 game_status = last_game_status; /* restore current game status */
2579 if (req_state & REQ_ASK)
2581 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2582 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2584 else if (req_state & REQ_CONFIRM)
2586 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2588 else if (req_state & REQ_PLAYER)
2590 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2591 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2592 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2593 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2596 /* copy request gadgets to door backbuffer */
2597 BlitBitmap(drawto, bitmap_db_door,
2598 DX, DY, DXSIZE, DYSIZE,
2599 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2601 OpenDoor(DOOR_OPEN_1);
2603 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2605 if (game_status == GAME_MODE_PLAYING)
2607 SetPanelBackground();
2608 SetDrawBackgroundMask(REDRAW_DOOR_1);
2612 SetDrawBackgroundMask(REDRAW_FIELD);
2618 if (game_status != GAME_MODE_MAIN)
2621 button_status = MB_RELEASED;
2623 request_gadget_id = -1;
2625 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2637 case EVENT_BUTTONPRESS:
2638 case EVENT_BUTTONRELEASE:
2639 case EVENT_MOTIONNOTIFY:
2641 if (event.type == EVENT_MOTIONNOTIFY)
2643 if (!PointerInWindow(window))
2644 continue; /* window and pointer are on different screens */
2649 motion_status = TRUE;
2650 mx = ((MotionEvent *) &event)->x;
2651 my = ((MotionEvent *) &event)->y;
2655 motion_status = FALSE;
2656 mx = ((ButtonEvent *) &event)->x;
2657 my = ((ButtonEvent *) &event)->y;
2658 if (event.type == EVENT_BUTTONPRESS)
2659 button_status = ((ButtonEvent *) &event)->button;
2661 button_status = MB_RELEASED;
2664 /* this sets 'request_gadget_id' */
2665 HandleGadgets(mx, my, button_status);
2667 switch (request_gadget_id)
2669 case TOOL_CTRL_ID_YES:
2672 case TOOL_CTRL_ID_NO:
2675 case TOOL_CTRL_ID_CONFIRM:
2676 result = TRUE | FALSE;
2679 case TOOL_CTRL_ID_PLAYER_1:
2682 case TOOL_CTRL_ID_PLAYER_2:
2685 case TOOL_CTRL_ID_PLAYER_3:
2688 case TOOL_CTRL_ID_PLAYER_4:
2699 case EVENT_KEYPRESS:
2700 switch (GetEventKey((KeyEvent *)&event, TRUE))
2713 if (req_state & REQ_PLAYER)
2717 case EVENT_KEYRELEASE:
2718 ClearPlayerAction();
2722 HandleOtherEvents(&event);
2726 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2728 int joy = AnyJoystick();
2730 if (joy & JOY_BUTTON_1)
2732 else if (joy & JOY_BUTTON_2)
2739 if (!PendingEvent()) /* delay only if no pending events */
2742 /* don't eat all CPU time */
2747 if (game_status != GAME_MODE_MAIN)
2752 if (!(req_state & REQ_STAY_OPEN))
2754 CloseDoor(DOOR_CLOSE_1);
2756 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2757 (req_state & REQ_REOPEN))
2758 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2763 if (game_status == GAME_MODE_PLAYING)
2765 SetPanelBackground();
2766 SetDrawBackgroundMask(REDRAW_DOOR_1);
2770 SetDrawBackgroundMask(REDRAW_FIELD);
2773 #if defined(NETWORK_AVALIABLE)
2774 /* continue network game after request */
2775 if (options.network &&
2776 game_status == GAME_MODE_PLAYING &&
2777 req_state & REQUEST_WAIT_FOR_INPUT)
2778 SendToServer_ContinuePlaying();
2781 /* restore deactivated drawing when quick-loading level tape recording */
2782 if (tape.playing && tape.deactivate_display)
2783 TapeDeactivateDisplayOn();
2788 unsigned int OpenDoor(unsigned int door_state)
2790 if (door_state & DOOR_COPY_BACK)
2792 if (door_state & DOOR_OPEN_1)
2793 BlitBitmap(bitmap_db_door, bitmap_db_door,
2794 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2795 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2797 if (door_state & DOOR_OPEN_2)
2798 BlitBitmap(bitmap_db_door, bitmap_db_door,
2799 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2800 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2802 door_state &= ~DOOR_COPY_BACK;
2805 return MoveDoor(door_state);
2808 unsigned int CloseDoor(unsigned int door_state)
2810 unsigned int old_door_state = GetDoorState();
2812 if (!(door_state & DOOR_NO_COPY_BACK))
2814 if (old_door_state & DOOR_OPEN_1)
2815 BlitBitmap(backbuffer, bitmap_db_door,
2816 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2818 if (old_door_state & DOOR_OPEN_2)
2819 BlitBitmap(backbuffer, bitmap_db_door,
2820 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2822 door_state &= ~DOOR_NO_COPY_BACK;
2825 return MoveDoor(door_state);
2828 unsigned int GetDoorState()
2830 return MoveDoor(DOOR_GET_STATE);
2833 unsigned int SetDoorState(unsigned int door_state)
2835 return MoveDoor(door_state | DOOR_SET_STATE);
2838 unsigned int MoveDoor(unsigned int door_state)
2840 static int door1 = DOOR_OPEN_1;
2841 static int door2 = DOOR_CLOSE_2;
2842 unsigned long door_delay = 0;
2843 unsigned long door_delay_value;
2846 if (door_1.width < 0 || door_1.width > DXSIZE)
2847 door_1.width = DXSIZE;
2848 if (door_1.height < 0 || door_1.height > DYSIZE)
2849 door_1.height = DYSIZE;
2850 if (door_2.width < 0 || door_2.width > VXSIZE)
2851 door_2.width = VXSIZE;
2852 if (door_2.height < 0 || door_2.height > VYSIZE)
2853 door_2.height = VYSIZE;
2855 if (door_state == DOOR_GET_STATE)
2856 return (door1 | door2);
2858 if (door_state & DOOR_SET_STATE)
2860 if (door_state & DOOR_ACTION_1)
2861 door1 = door_state & DOOR_ACTION_1;
2862 if (door_state & DOOR_ACTION_2)
2863 door2 = door_state & DOOR_ACTION_2;
2865 return (door1 | door2);
2868 if (!(door_state & DOOR_FORCE_REDRAW))
2870 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2871 door_state &= ~DOOR_OPEN_1;
2872 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2873 door_state &= ~DOOR_CLOSE_1;
2874 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2875 door_state &= ~DOOR_OPEN_2;
2876 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2877 door_state &= ~DOOR_CLOSE_2;
2880 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2883 if (setup.quick_doors)
2885 stepsize = 20; /* must be choosen to always draw last frame */
2886 door_delay_value = 0;
2889 if (global.autoplay_leveldir)
2891 door_state |= DOOR_NO_DELAY;
2892 door_state &= ~DOOR_CLOSE_ALL;
2895 if (door_state & DOOR_ACTION)
2897 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2898 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2899 boolean door_1_done = (!handle_door_1);
2900 boolean door_2_done = (!handle_door_2);
2901 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2902 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2903 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2904 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2905 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2906 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2907 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2908 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2909 int door_skip = max_door_size - door_size;
2910 int end = door_size;
2911 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2914 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2916 /* opening door sound has priority over simultaneously closing door */
2917 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2918 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2919 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2920 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2923 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2926 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2927 GC gc = bitmap->stored_clip_gc;
2929 if (door_state & DOOR_ACTION_1)
2931 int a = MIN(x * door_1.step_offset, end);
2932 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2933 int i = p + door_skip;
2935 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2937 BlitBitmap(bitmap_db_door, drawto,
2938 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2939 DXSIZE, DYSIZE, DX, DY);
2943 BlitBitmap(bitmap_db_door, drawto,
2944 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2945 DXSIZE, DYSIZE - p / 2, DX, DY);
2947 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2950 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2952 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2953 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2954 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2955 int dst2_x = DX, dst2_y = DY;
2956 int width = i, height = DYSIZE;
2958 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2959 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2962 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2963 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2966 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2968 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2969 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2970 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2971 int dst2_x = DX, dst2_y = DY;
2972 int width = DXSIZE, height = i;
2974 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2975 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2978 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2979 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2982 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2984 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2986 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2987 BlitBitmapMasked(bitmap, drawto,
2988 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2989 DX + DXSIZE - i, DY + j);
2990 BlitBitmapMasked(bitmap, drawto,
2991 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2992 DX + DXSIZE - i, DY + 140 + j);
2993 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2994 DY - (DOOR_GFX_PAGEY1 + j));
2995 BlitBitmapMasked(bitmap, drawto,
2996 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2998 BlitBitmapMasked(bitmap, drawto,
2999 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3002 BlitBitmapMasked(bitmap, drawto,
3003 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3005 BlitBitmapMasked(bitmap, drawto,
3006 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3008 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3009 BlitBitmapMasked(bitmap, drawto,
3010 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3011 DX + DXSIZE - i, DY + 77 + j);
3012 BlitBitmapMasked(bitmap, drawto,
3013 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3014 DX + DXSIZE - i, DY + 203 + j);
3017 redraw_mask |= REDRAW_DOOR_1;
3018 door_1_done = (a == end);
3021 if (door_state & DOOR_ACTION_2)
3023 int a = MIN(x * door_2.step_offset, door_size);
3024 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3025 int i = p + door_skip;
3027 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3029 BlitBitmap(bitmap_db_door, drawto,
3030 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3031 VXSIZE, VYSIZE, VX, VY);
3033 else if (x <= VYSIZE)
3035 BlitBitmap(bitmap_db_door, drawto,
3036 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3037 VXSIZE, VYSIZE - p / 2, VX, VY);
3039 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3042 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3044 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3045 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3046 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3047 int dst2_x = VX, dst2_y = VY;
3048 int width = i, height = VYSIZE;
3050 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3051 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3054 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3055 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3058 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3060 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3061 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3062 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3063 int dst2_x = VX, dst2_y = VY;
3064 int width = VXSIZE, height = i;
3066 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3067 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3070 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3071 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3074 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3076 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3078 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3079 BlitBitmapMasked(bitmap, drawto,
3080 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3081 VX + VXSIZE - i, VY + j);
3082 SetClipOrigin(bitmap, gc,
3083 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3084 BlitBitmapMasked(bitmap, drawto,
3085 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3088 BlitBitmapMasked(bitmap, drawto,
3089 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3090 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3091 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3092 BlitBitmapMasked(bitmap, drawto,
3093 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3095 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3098 redraw_mask |= REDRAW_DOOR_2;
3099 door_2_done = (a == VXSIZE);
3102 if (!(door_state & DOOR_NO_DELAY))
3106 if (game_status == GAME_MODE_MAIN)
3109 WaitUntilDelayReached(&door_delay, door_delay_value);
3114 if (door_state & DOOR_ACTION_1)
3115 door1 = door_state & DOOR_ACTION_1;
3116 if (door_state & DOOR_ACTION_2)
3117 door2 = door_state & DOOR_ACTION_2;
3119 return (door1 | door2);
3122 void DrawSpecialEditorDoor()
3124 /* draw bigger toolbox window */
3125 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3126 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3128 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3129 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3132 redraw_mask |= REDRAW_ALL;
3135 void UndrawSpecialEditorDoor()
3137 /* draw normal tape recorder window */
3138 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3139 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3142 redraw_mask |= REDRAW_ALL;
3146 /* ---------- new tool button stuff ---------------------------------------- */
3148 /* graphic position values for tool buttons */
3149 #define TOOL_BUTTON_YES_XPOS 2
3150 #define TOOL_BUTTON_YES_YPOS 250
3151 #define TOOL_BUTTON_YES_GFX_YPOS 0
3152 #define TOOL_BUTTON_YES_XSIZE 46
3153 #define TOOL_BUTTON_YES_YSIZE 28
3154 #define TOOL_BUTTON_NO_XPOS 52
3155 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3156 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3157 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3158 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3159 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3160 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3161 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3162 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3163 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3164 #define TOOL_BUTTON_PLAYER_XSIZE 30
3165 #define TOOL_BUTTON_PLAYER_YSIZE 30
3166 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3167 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3168 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3169 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3170 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3171 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3172 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3173 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3174 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3175 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3176 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3177 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3178 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3179 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3180 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3181 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3182 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3183 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3184 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3185 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3194 } toolbutton_info[NUM_TOOL_BUTTONS] =
3197 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3198 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3199 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3204 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3205 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3206 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3211 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3212 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3213 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3214 TOOL_CTRL_ID_CONFIRM,
3218 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3219 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3220 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3221 TOOL_CTRL_ID_PLAYER_1,
3225 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3226 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3227 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3228 TOOL_CTRL_ID_PLAYER_2,
3232 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3233 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3234 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3235 TOOL_CTRL_ID_PLAYER_3,
3239 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3240 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3241 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3242 TOOL_CTRL_ID_PLAYER_4,
3247 void CreateToolButtons()
3251 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3253 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3254 Bitmap *deco_bitmap = None;
3255 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3256 struct GadgetInfo *gi;
3257 unsigned long event_mask;
3258 int gd_xoffset, gd_yoffset;
3259 int gd_x1, gd_x2, gd_y;
3262 event_mask = GD_EVENT_RELEASED;
3264 gd_xoffset = toolbutton_info[i].xpos;
3265 gd_yoffset = toolbutton_info[i].ypos;
3266 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3267 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3268 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3270 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3272 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3274 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3275 &deco_bitmap, &deco_x, &deco_y);
3276 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3277 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3280 gi = CreateGadget(GDI_CUSTOM_ID, id,
3281 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3282 GDI_X, DX + toolbutton_info[i].x,
3283 GDI_Y, DY + toolbutton_info[i].y,
3284 GDI_WIDTH, toolbutton_info[i].width,
3285 GDI_HEIGHT, toolbutton_info[i].height,
3286 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3287 GDI_STATE, GD_BUTTON_UNPRESSED,
3288 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3289 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3290 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3291 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3292 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3293 GDI_DECORATION_SHIFTING, 1, 1,
3294 GDI_DIRECT_DRAW, FALSE,
3295 GDI_EVENT_MASK, event_mask,
3296 GDI_CALLBACK_ACTION, HandleToolButtons,
3300 Error(ERR_EXIT, "cannot create gadget");
3302 tool_gadget[id] = gi;
3306 void FreeToolButtons()
3310 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3311 FreeGadget(tool_gadget[i]);
3314 static void UnmapToolButtons()
3318 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3319 UnmapGadget(tool_gadget[i]);
3322 static void HandleToolButtons(struct GadgetInfo *gi)
3324 request_gadget_id = gi->custom_id;
3327 static struct Mapping_EM_to_RND_object
3330 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3331 boolean is_backside; /* backside of moving element */
3337 em_object_mapping_list[] =
3340 Xblank, TRUE, FALSE,
3344 Yacid_splash_eB, FALSE, FALSE,
3345 EL_ACID_SPLASH_RIGHT, -1, -1
3348 Yacid_splash_wB, FALSE, FALSE,
3349 EL_ACID_SPLASH_LEFT, -1, -1
3352 #ifdef EM_ENGINE_BAD_ROLL
3354 Xstone_force_e, FALSE, FALSE,
3355 EL_ROCK, -1, MV_BIT_RIGHT
3358 Xstone_force_w, FALSE, FALSE,
3359 EL_ROCK, -1, MV_BIT_LEFT
3362 Xnut_force_e, FALSE, FALSE,
3363 EL_NUT, -1, MV_BIT_RIGHT
3366 Xnut_force_w, FALSE, FALSE,
3367 EL_NUT, -1, MV_BIT_LEFT
3370 Xspring_force_e, FALSE, FALSE,
3371 EL_SPRING, -1, MV_BIT_RIGHT
3374 Xspring_force_w, FALSE, FALSE,
3375 EL_SPRING, -1, MV_BIT_LEFT
3378 Xemerald_force_e, FALSE, FALSE,
3379 EL_EMERALD, -1, MV_BIT_RIGHT
3382 Xemerald_force_w, FALSE, FALSE,
3383 EL_EMERALD, -1, MV_BIT_LEFT
3386 Xdiamond_force_e, FALSE, FALSE,
3387 EL_DIAMOND, -1, MV_BIT_RIGHT
3390 Xdiamond_force_w, FALSE, FALSE,
3391 EL_DIAMOND, -1, MV_BIT_LEFT
3394 Xbomb_force_e, FALSE, FALSE,
3395 EL_BOMB, -1, MV_BIT_RIGHT
3398 Xbomb_force_w, FALSE, FALSE,
3399 EL_BOMB, -1, MV_BIT_LEFT
3401 #endif /* EM_ENGINE_BAD_ROLL */
3404 Xstone, TRUE, FALSE,
3408 Xstone_pause, FALSE, FALSE,
3412 Xstone_fall, FALSE, FALSE,
3416 Ystone_s, FALSE, FALSE,
3417 EL_ROCK, ACTION_FALLING, -1
3420 Ystone_sB, FALSE, TRUE,
3421 EL_ROCK, ACTION_FALLING, -1
3424 Ystone_e, FALSE, FALSE,
3425 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3428 Ystone_eB, FALSE, TRUE,
3429 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3432 Ystone_w, FALSE, FALSE,
3433 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3436 Ystone_wB, FALSE, TRUE,
3437 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3444 Xnut_pause, FALSE, FALSE,
3448 Xnut_fall, FALSE, FALSE,
3452 Ynut_s, FALSE, FALSE,
3453 EL_NUT, ACTION_FALLING, -1
3456 Ynut_sB, FALSE, TRUE,
3457 EL_NUT, ACTION_FALLING, -1
3460 Ynut_e, FALSE, FALSE,
3461 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3464 Ynut_eB, FALSE, TRUE,
3465 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3468 Ynut_w, FALSE, FALSE,
3469 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3472 Ynut_wB, FALSE, TRUE,
3473 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3476 Xbug_n, TRUE, FALSE,
3480 Xbug_e, TRUE, FALSE,
3481 EL_BUG_RIGHT, -1, -1
3484 Xbug_s, TRUE, FALSE,
3488 Xbug_w, TRUE, FALSE,
3492 Xbug_gon, FALSE, FALSE,
3496 Xbug_goe, FALSE, FALSE,
3497 EL_BUG_RIGHT, -1, -1
3500 Xbug_gos, FALSE, FALSE,
3504 Xbug_gow, FALSE, FALSE,
3508 Ybug_n, FALSE, FALSE,
3509 EL_BUG, ACTION_MOVING, MV_BIT_UP
3512 Ybug_nB, FALSE, TRUE,
3513 EL_BUG, ACTION_MOVING, MV_BIT_UP
3516 Ybug_e, FALSE, FALSE,
3517 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3520 Ybug_eB, FALSE, TRUE,
3521 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3524 Ybug_s, FALSE, FALSE,
3525 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3528 Ybug_sB, FALSE, TRUE,
3529 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3532 Ybug_w, FALSE, FALSE,
3533 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3536 Ybug_wB, FALSE, TRUE,
3537 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3540 Ybug_w_n, FALSE, FALSE,
3541 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3544 Ybug_n_e, FALSE, FALSE,
3545 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3548 Ybug_e_s, FALSE, FALSE,
3549 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3552 Ybug_s_w, FALSE, FALSE,
3553 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3556 Ybug_e_n, FALSE, FALSE,
3557 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3560 Ybug_s_e, FALSE, FALSE,
3561 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3564 Ybug_w_s, FALSE, FALSE,
3565 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3568 Ybug_n_w, FALSE, FALSE,
3569 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3572 Ybug_stone, FALSE, FALSE,
3573 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3576 Ybug_spring, FALSE, FALSE,
3577 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3580 Xtank_n, TRUE, FALSE,
3581 EL_SPACESHIP_UP, -1, -1
3584 Xtank_e, TRUE, FALSE,
3585 EL_SPACESHIP_RIGHT, -1, -1
3588 Xtank_s, TRUE, FALSE,
3589 EL_SPACESHIP_DOWN, -1, -1
3592 Xtank_w, TRUE, FALSE,
3593 EL_SPACESHIP_LEFT, -1, -1
3596 Xtank_gon, FALSE, FALSE,
3597 EL_SPACESHIP_UP, -1, -1
3600 Xtank_goe, FALSE, FALSE,
3601 EL_SPACESHIP_RIGHT, -1, -1
3604 Xtank_gos, FALSE, FALSE,
3605 EL_SPACESHIP_DOWN, -1, -1
3608 Xtank_gow, FALSE, FALSE,
3609 EL_SPACESHIP_LEFT, -1, -1
3612 Ytank_n, FALSE, FALSE,
3613 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3616 Ytank_nB, FALSE, TRUE,
3617 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3620 Ytank_e, FALSE, FALSE,
3621 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3624 Ytank_eB, FALSE, TRUE,
3625 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3628 Ytank_s, FALSE, FALSE,
3629 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3632 Ytank_sB, FALSE, TRUE,
3633 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3636 Ytank_w, FALSE, FALSE,
3637 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3640 Ytank_wB, FALSE, TRUE,
3641 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3644 Ytank_w_n, FALSE, FALSE,
3645 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3648 Ytank_n_e, FALSE, FALSE,
3649 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3652 Ytank_e_s, FALSE, FALSE,
3653 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3656 Ytank_s_w, FALSE, FALSE,
3657 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3660 Ytank_e_n, FALSE, FALSE,
3661 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3664 Ytank_s_e, FALSE, FALSE,
3665 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3668 Ytank_w_s, FALSE, FALSE,
3669 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3672 Ytank_n_w, FALSE, FALSE,
3673 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3676 Ytank_stone, FALSE, FALSE,
3677 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3680 Ytank_spring, FALSE, FALSE,
3681 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3684 Xandroid, TRUE, FALSE,
3685 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3688 Xandroid_1_n, FALSE, FALSE,
3689 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3692 Xandroid_2_n, FALSE, FALSE,
3693 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3696 Xandroid_1_e, FALSE, FALSE,
3697 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3700 Xandroid_2_e, FALSE, FALSE,
3701 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3704 Xandroid_1_w, FALSE, FALSE,
3705 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3708 Xandroid_2_w, FALSE, FALSE,
3709 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3712 Xandroid_1_s, FALSE, FALSE,
3713 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3716 Xandroid_2_s, FALSE, FALSE,
3717 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3720 Yandroid_n, FALSE, FALSE,
3721 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3724 Yandroid_nB, FALSE, TRUE,
3725 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3728 Yandroid_ne, FALSE, FALSE,
3729 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3732 Yandroid_neB, FALSE, TRUE,
3733 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3736 Yandroid_e, FALSE, FALSE,
3737 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3740 Yandroid_eB, FALSE, TRUE,
3741 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3744 Yandroid_se, FALSE, FALSE,
3745 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3748 Yandroid_seB, FALSE, TRUE,
3749 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3752 Yandroid_s, FALSE, FALSE,
3753 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3756 Yandroid_sB, FALSE, TRUE,
3757 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3760 Yandroid_sw, FALSE, FALSE,
3761 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3764 Yandroid_swB, FALSE, TRUE,
3765 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3768 Yandroid_w, FALSE, FALSE,
3769 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3772 Yandroid_wB, FALSE, TRUE,
3773 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3776 Yandroid_nw, FALSE, FALSE,
3777 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3780 Yandroid_nwB, FALSE, TRUE,
3781 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3784 Xspring, TRUE, FALSE,
3788 Xspring_pause, FALSE, FALSE,
3792 Xspring_e, FALSE, FALSE,
3796 Xspring_w, FALSE, FALSE,
3800 Xspring_fall, FALSE, FALSE,
3804 Yspring_s, FALSE, FALSE,
3805 EL_SPRING, ACTION_FALLING, -1
3808 Yspring_sB, FALSE, TRUE,
3809 EL_SPRING, ACTION_FALLING, -1
3812 Yspring_e, FALSE, FALSE,
3813 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3816 Yspring_eB, FALSE, TRUE,
3817 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3820 Yspring_w, FALSE, FALSE,
3821 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3824 Yspring_wB, FALSE, TRUE,
3825 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3828 Yspring_kill_e, FALSE, FALSE,
3829 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3832 Yspring_kill_eB, FALSE, TRUE,
3833 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3836 Yspring_kill_w, FALSE, FALSE,
3837 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3840 Yspring_kill_wB, FALSE, TRUE,
3841 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3844 Xeater_n, TRUE, FALSE,
3845 EL_YAMYAM_UP, -1, -1
3848 Xeater_e, TRUE, FALSE,
3849 EL_YAMYAM_RIGHT, -1, -1
3852 Xeater_w, TRUE, FALSE,
3853 EL_YAMYAM_LEFT, -1, -1
3856 Xeater_s, TRUE, FALSE,
3857 EL_YAMYAM_DOWN, -1, -1
3860 Yeater_n, FALSE, FALSE,
3861 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3864 Yeater_nB, FALSE, TRUE,
3865 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3868 Yeater_e, FALSE, FALSE,
3869 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3872 Yeater_eB, FALSE, TRUE,
3873 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3876 Yeater_s, FALSE, FALSE,
3877 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3880 Yeater_sB, FALSE, TRUE,
3881 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3884 Yeater_w, FALSE, FALSE,
3885 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3888 Yeater_wB, FALSE, TRUE,
3889 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3892 Yeater_stone, FALSE, FALSE,
3893 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3896 Yeater_spring, FALSE, FALSE,
3897 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3900 Xalien, TRUE, FALSE,
3904 Xalien_pause, FALSE, FALSE,
3908 Yalien_n, FALSE, FALSE,
3909 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3912 Yalien_nB, FALSE, TRUE,
3913 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3916 Yalien_e, FALSE, FALSE,
3917 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3920 Yalien_eB, FALSE, TRUE,
3921 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3924 Yalien_s, FALSE, FALSE,
3925 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3928 Yalien_sB, FALSE, TRUE,
3929 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3932 Yalien_w, FALSE, FALSE,
3933 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3936 Yalien_wB, FALSE, TRUE,
3937 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3940 Yalien_stone, FALSE, FALSE,
3941 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3944 Yalien_spring, FALSE, FALSE,
3945 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3948 Xemerald, TRUE, FALSE,
3952 Xemerald_pause, FALSE, FALSE,
3956 Xemerald_fall, FALSE, FALSE,
3960 Xemerald_shine, FALSE, FALSE,
3961 EL_EMERALD, ACTION_TWINKLING, -1
3964 Yemerald_s, FALSE, FALSE,
3965 EL_EMERALD, ACTION_FALLING, -1
3968 Yemerald_sB, FALSE, TRUE,
3969 EL_EMERALD, ACTION_FALLING, -1
3972 Yemerald_e, FALSE, FALSE,
3973 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3976 Yemerald_eB, FALSE, TRUE,
3977 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3980 Yemerald_w, FALSE, FALSE,
3981 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3984 Yemerald_wB, FALSE, TRUE,
3985 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3988 Yemerald_eat, FALSE, FALSE,
3989 EL_EMERALD, ACTION_COLLECTING, -1
3992 Yemerald_stone, FALSE, FALSE,
3993 EL_NUT, ACTION_BREAKING, -1
3996 Xdiamond, TRUE, FALSE,
4000 Xdiamond_pause, FALSE, FALSE,
4004 Xdiamond_fall, FALSE, FALSE,
4008 Xdiamond_shine, FALSE, FALSE,
4009 EL_DIAMOND, ACTION_TWINKLING, -1
4012 Ydiamond_s, FALSE, FALSE,
4013 EL_DIAMOND, ACTION_FALLING, -1
4016 Ydiamond_sB, FALSE, TRUE,
4017 EL_DIAMOND, ACTION_FALLING, -1
4020 Ydiamond_e, FALSE, FALSE,
4021 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4024 Ydiamond_eB, FALSE, TRUE,
4025 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4028 Ydiamond_w, FALSE, FALSE,
4029 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4032 Ydiamond_wB, FALSE, TRUE,
4033 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4036 Ydiamond_eat, FALSE, FALSE,
4037 EL_DIAMOND, ACTION_COLLECTING, -1
4040 Ydiamond_stone, FALSE, FALSE,
4041 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4044 Xdrip_fall, TRUE, FALSE,
4045 EL_AMOEBA_DROP, -1, -1
4048 Xdrip_stretch, FALSE, FALSE,
4049 EL_AMOEBA_DROP, ACTION_FALLING, -1
4052 Xdrip_stretchB, FALSE, TRUE,
4053 EL_AMOEBA_DROP, ACTION_FALLING, -1
4056 Xdrip_eat, FALSE, FALSE,
4057 EL_AMOEBA_DROP, ACTION_GROWING, -1
4060 Ydrip_s1, FALSE, FALSE,
4061 EL_AMOEBA_DROP, ACTION_FALLING, -1
4064 Ydrip_s1B, FALSE, TRUE,
4065 EL_AMOEBA_DROP, ACTION_FALLING, -1
4068 Ydrip_s2, FALSE, FALSE,
4069 EL_AMOEBA_DROP, ACTION_FALLING, -1
4072 Ydrip_s2B, FALSE, TRUE,
4073 EL_AMOEBA_DROP, ACTION_FALLING, -1
4080 Xbomb_pause, FALSE, FALSE,
4084 Xbomb_fall, FALSE, FALSE,
4088 Ybomb_s, FALSE, FALSE,
4089 EL_BOMB, ACTION_FALLING, -1
4092 Ybomb_sB, FALSE, TRUE,
4093 EL_BOMB, ACTION_FALLING, -1
4096 Ybomb_e, FALSE, FALSE,
4097 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4100 Ybomb_eB, FALSE, TRUE,
4101 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4104 Ybomb_w, FALSE, FALSE,
4105 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4108 Ybomb_wB, FALSE, TRUE,
4109 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4112 Ybomb_eat, FALSE, FALSE,
4113 EL_BOMB, ACTION_ACTIVATING, -1
4116 Xballoon, TRUE, FALSE,
4120 Yballoon_n, FALSE, FALSE,
4121 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4124 Yballoon_nB, FALSE, TRUE,
4125 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4128 Yballoon_e, FALSE, FALSE,
4129 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4132 Yballoon_eB, FALSE, TRUE,
4133 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4136 Yballoon_s, FALSE, FALSE,
4137 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4140 Yballoon_sB, FALSE, TRUE,
4141 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4144 Yballoon_w, FALSE, FALSE,
4145 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4148 Yballoon_wB, FALSE, TRUE,
4149 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4152 Xgrass, TRUE, FALSE,
4153 EL_EMC_GRASS, -1, -1
4156 Ygrass_nB, FALSE, FALSE,
4157 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4160 Ygrass_eB, FALSE, FALSE,
4161 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4164 Ygrass_sB, FALSE, FALSE,
4165 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4168 Ygrass_wB, FALSE, FALSE,
4169 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4176 Ydirt_nB, FALSE, FALSE,
4177 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4180 Ydirt_eB, FALSE, FALSE,
4181 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4184 Ydirt_sB, FALSE, FALSE,
4185 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4188 Ydirt_wB, FALSE, FALSE,
4189 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4192 Xacid_ne, TRUE, FALSE,
4193 EL_ACID_POOL_TOPRIGHT, -1, -1
4196 Xacid_se, TRUE, FALSE,
4197 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4200 Xacid_s, TRUE, FALSE,
4201 EL_ACID_POOL_BOTTOM, -1, -1
4204 Xacid_sw, TRUE, FALSE,
4205 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4208 Xacid_nw, TRUE, FALSE,
4209 EL_ACID_POOL_TOPLEFT, -1, -1
4212 Xacid_1, TRUE, FALSE,
4216 Xacid_2, FALSE, FALSE,
4220 Xacid_3, FALSE, FALSE,
4224 Xacid_4, FALSE, FALSE,
4228 Xacid_5, FALSE, FALSE,
4232 Xacid_6, FALSE, FALSE,
4236 Xacid_7, FALSE, FALSE,
4240 Xacid_8, FALSE, FALSE,
4244 Xball_1, TRUE, FALSE,
4245 EL_EMC_MAGIC_BALL, -1, -1
4248 Xball_1B, FALSE, FALSE,
4249 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4252 Xball_2, FALSE, FALSE,
4253 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4256 Xball_2B, FALSE, FALSE,
4257 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4260 Yball_eat, FALSE, FALSE,
4261 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4264 Ykey_1_eat, FALSE, FALSE,
4265 EL_EM_KEY_1, ACTION_COLLECTING, -1
4268 Ykey_2_eat, FALSE, FALSE,
4269 EL_EM_KEY_2, ACTION_COLLECTING, -1
4272 Ykey_3_eat, FALSE, FALSE,
4273 EL_EM_KEY_3, ACTION_COLLECTING, -1
4276 Ykey_4_eat, FALSE, FALSE,
4277 EL_EM_KEY_4, ACTION_COLLECTING, -1
4280 Ykey_5_eat, FALSE, FALSE,
4281 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4284 Ykey_6_eat, FALSE, FALSE,
4285 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4288 Ykey_7_eat, FALSE, FALSE,
4289 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4292 Ykey_8_eat, FALSE, FALSE,
4293 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4296 Ylenses_eat, FALSE, FALSE,
4297 EL_EMC_LENSES, ACTION_COLLECTING, -1
4300 Ymagnify_eat, FALSE, FALSE,
4301 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4304 Ygrass_eat, FALSE, FALSE,
4305 EL_EMC_GRASS, ACTION_SNAPPING, -1
4308 Ydirt_eat, FALSE, FALSE,
4309 EL_SAND, ACTION_SNAPPING, -1
4312 Xgrow_ns, TRUE, FALSE,
4313 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4316 Ygrow_ns_eat, FALSE, FALSE,
4317 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4320 Xgrow_ew, TRUE, FALSE,
4321 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4324 Ygrow_ew_eat, FALSE, FALSE,
4325 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4328 Xwonderwall, TRUE, FALSE,
4329 EL_MAGIC_WALL, -1, -1
4332 XwonderwallB, FALSE, FALSE,
4333 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4336 Xamoeba_1, TRUE, FALSE,
4337 EL_AMOEBA_DRY, ACTION_OTHER, -1
4340 Xamoeba_2, FALSE, FALSE,
4341 EL_AMOEBA_DRY, ACTION_OTHER, -1
4344 Xamoeba_3, FALSE, FALSE,
4345 EL_AMOEBA_DRY, ACTION_OTHER, -1
4348 Xamoeba_4, FALSE, FALSE,
4349 EL_AMOEBA_DRY, ACTION_OTHER, -1
4352 Xamoeba_5, TRUE, FALSE,
4353 EL_AMOEBA_WET, ACTION_OTHER, -1
4356 Xamoeba_6, FALSE, FALSE,
4357 EL_AMOEBA_WET, ACTION_OTHER, -1
4360 Xamoeba_7, FALSE, FALSE,
4361 EL_AMOEBA_WET, ACTION_OTHER, -1
4364 Xamoeba_8, FALSE, FALSE,
4365 EL_AMOEBA_WET, ACTION_OTHER, -1
4368 Xdoor_1, TRUE, FALSE,
4369 EL_EM_GATE_1, -1, -1
4372 Xdoor_2, TRUE, FALSE,
4373 EL_EM_GATE_2, -1, -1
4376 Xdoor_3, TRUE, FALSE,
4377 EL_EM_GATE_3, -1, -1
4380 Xdoor_4, TRUE, FALSE,
4381 EL_EM_GATE_4, -1, -1
4384 Xdoor_5, TRUE, FALSE,
4385 EL_EMC_GATE_5, -1, -1
4388 Xdoor_6, TRUE, FALSE,
4389 EL_EMC_GATE_6, -1, -1
4392 Xdoor_7, TRUE, FALSE,
4393 EL_EMC_GATE_7, -1, -1
4396 Xdoor_8, TRUE, FALSE,
4397 EL_EMC_GATE_8, -1, -1
4400 Xkey_1, TRUE, FALSE,
4404 Xkey_2, TRUE, FALSE,
4408 Xkey_3, TRUE, FALSE,
4412 Xkey_4, TRUE, FALSE,
4416 Xkey_5, TRUE, FALSE,
4417 EL_EMC_KEY_5, -1, -1
4420 Xkey_6, TRUE, FALSE,
4421 EL_EMC_KEY_6, -1, -1
4424 Xkey_7, TRUE, FALSE,
4425 EL_EMC_KEY_7, -1, -1
4428 Xkey_8, TRUE, FALSE,
4429 EL_EMC_KEY_8, -1, -1
4432 Xwind_n, TRUE, FALSE,
4433 EL_BALLOON_SWITCH_UP, -1, -1
4436 Xwind_e, TRUE, FALSE,
4437 EL_BALLOON_SWITCH_RIGHT, -1, -1
4440 Xwind_s, TRUE, FALSE,
4441 EL_BALLOON_SWITCH_DOWN, -1, -1
4444 Xwind_w, TRUE, FALSE,
4445 EL_BALLOON_SWITCH_LEFT, -1, -1
4448 Xwind_nesw, TRUE, FALSE,
4449 EL_BALLOON_SWITCH_ANY, -1, -1
4452 Xwind_stop, TRUE, FALSE,
4453 EL_BALLOON_SWITCH_NONE, -1, -1
4457 EL_EXIT_CLOSED, -1, -1
4460 Xexit_1, TRUE, FALSE,
4461 EL_EXIT_OPEN, -1, -1
4464 Xexit_2, FALSE, FALSE,
4465 EL_EXIT_OPEN, -1, -1
4468 Xexit_3, FALSE, FALSE,
4469 EL_EXIT_OPEN, -1, -1
4472 Xdynamite, TRUE, FALSE,
4473 EL_EM_DYNAMITE, -1, -1
4476 Ydynamite_eat, FALSE, FALSE,
4477 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4480 Xdynamite_1, TRUE, FALSE,
4481 EL_EM_DYNAMITE_ACTIVE, -1, -1
4484 Xdynamite_2, FALSE, FALSE,
4485 EL_EM_DYNAMITE_ACTIVE, -1, -1
4488 Xdynamite_3, FALSE, FALSE,
4489 EL_EM_DYNAMITE_ACTIVE, -1, -1
4492 Xdynamite_4, FALSE, FALSE,
4493 EL_EM_DYNAMITE_ACTIVE, -1, -1
4496 Xbumper, TRUE, FALSE,
4497 EL_EMC_SPRING_BUMPER, -1, -1
4500 XbumperB, FALSE, FALSE,
4501 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4504 Xwheel, TRUE, FALSE,
4505 EL_ROBOT_WHEEL, -1, -1
4508 XwheelB, FALSE, FALSE,
4509 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4512 Xswitch, TRUE, FALSE,
4513 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4516 XswitchB, FALSE, FALSE,
4517 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4521 EL_QUICKSAND_EMPTY, -1, -1
4524 Xsand_stone, TRUE, FALSE,
4525 EL_QUICKSAND_FULL, -1, -1
4528 Xsand_stonein_1, FALSE, TRUE,
4529 EL_ROCK, ACTION_FILLING, -1
4532 Xsand_stonein_2, FALSE, TRUE,
4533 EL_ROCK, ACTION_FILLING, -1
4536 Xsand_stonein_3, FALSE, TRUE,
4537 EL_ROCK, ACTION_FILLING, -1
4540 Xsand_stonein_4, FALSE, TRUE,
4541 EL_ROCK, ACTION_FILLING, -1
4544 Xsand_stonesand_1, FALSE, FALSE,
4545 EL_QUICKSAND_FULL, -1, -1
4548 Xsand_stonesand_2, FALSE, FALSE,
4549 EL_QUICKSAND_FULL, -1, -1
4552 Xsand_stonesand_3, FALSE, FALSE,
4553 EL_QUICKSAND_FULL, -1, -1
4556 Xsand_stonesand_4, FALSE, FALSE,
4557 EL_QUICKSAND_FULL, -1, -1
4560 Xsand_stoneout_1, FALSE, FALSE,
4561 EL_ROCK, ACTION_EMPTYING, -1
4564 Xsand_stoneout_2, FALSE, FALSE,
4565 EL_ROCK, ACTION_EMPTYING, -1
4568 Xsand_sandstone_1, FALSE, FALSE,
4569 EL_QUICKSAND_FULL, -1, -1
4572 Xsand_sandstone_2, FALSE, FALSE,
4573 EL_QUICKSAND_FULL, -1, -1
4576 Xsand_sandstone_3, FALSE, FALSE,
4577 EL_QUICKSAND_FULL, -1, -1
4580 Xsand_sandstone_4, FALSE, FALSE,
4581 EL_QUICKSAND_FULL, -1, -1
4584 Xplant, TRUE, FALSE,
4585 EL_EMC_PLANT, -1, -1
4588 Yplant, FALSE, FALSE,
4589 EL_EMC_PLANT, -1, -1
4592 Xlenses, TRUE, FALSE,
4593 EL_EMC_LENSES, -1, -1
4596 Xmagnify, TRUE, FALSE,
4597 EL_EMC_MAGNIFIER, -1, -1
4600 Xdripper, TRUE, FALSE,
4601 EL_EMC_DRIPPER, -1, -1
4604 XdripperB, FALSE, FALSE,
4605 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4608 Xfake_blank, TRUE, FALSE,
4609 EL_INVISIBLE_WALL, -1, -1
4612 Xfake_blankB, FALSE, FALSE,
4613 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4616 Xfake_grass, TRUE, FALSE,
4617 EL_EMC_FAKE_GRASS, -1, -1
4620 Xfake_grassB, FALSE, FALSE,
4621 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4624 Xfake_door_1, TRUE, FALSE,
4625 EL_EM_GATE_1_GRAY, -1, -1
4628 Xfake_door_2, TRUE, FALSE,
4629 EL_EM_GATE_2_GRAY, -1, -1
4632 Xfake_door_3, TRUE, FALSE,
4633 EL_EM_GATE_3_GRAY, -1, -1
4636 Xfake_door_4, TRUE, FALSE,
4637 EL_EM_GATE_4_GRAY, -1, -1
4640 Xfake_door_5, TRUE, FALSE,
4641 EL_EMC_GATE_5_GRAY, -1, -1
4644 Xfake_door_6, TRUE, FALSE,
4645 EL_EMC_GATE_6_GRAY, -1, -1
4648 Xfake_door_7, TRUE, FALSE,
4649 EL_EMC_GATE_7_GRAY, -1, -1
4652 Xfake_door_8, TRUE, FALSE,
4653 EL_EMC_GATE_8_GRAY, -1, -1
4656 Xfake_acid_1, TRUE, FALSE,
4657 EL_EMC_FAKE_ACID, -1, -1
4660 Xfake_acid_2, FALSE, FALSE,
4661 EL_EMC_FAKE_ACID, -1, -1
4664 Xfake_acid_3, FALSE, FALSE,
4665 EL_EMC_FAKE_ACID, -1, -1
4668 Xfake_acid_4, FALSE, FALSE,
4669 EL_EMC_FAKE_ACID, -1, -1
4672 Xfake_acid_5, FALSE, FALSE,
4673 EL_EMC_FAKE_ACID, -1, -1
4676 Xfake_acid_6, FALSE, FALSE,
4677 EL_EMC_FAKE_ACID, -1, -1
4680 Xfake_acid_7, FALSE, FALSE,
4681 EL_EMC_FAKE_ACID, -1, -1
4684 Xfake_acid_8, FALSE, FALSE,
4685 EL_EMC_FAKE_ACID, -1, -1
4688 Xsteel_1, TRUE, FALSE,
4689 EL_STEELWALL, -1, -1
4692 Xsteel_2, TRUE, FALSE,
4693 EL_EMC_STEELWALL_2, -1, -1
4696 Xsteel_3, TRUE, FALSE,
4697 EL_EMC_STEELWALL_3, -1, -1
4700 Xsteel_4, TRUE, FALSE,
4701 EL_EMC_STEELWALL_4, -1, -1
4704 Xwall_1, TRUE, FALSE,
4708 Xwall_2, TRUE, FALSE,
4709 EL_EMC_WALL_14, -1, -1
4712 Xwall_3, TRUE, FALSE,
4713 EL_EMC_WALL_15, -1, -1
4716 Xwall_4, TRUE, FALSE,
4717 EL_EMC_WALL_16, -1, -1
4720 Xround_wall_1, TRUE, FALSE,
4721 EL_WALL_SLIPPERY, -1, -1
4724 Xround_wall_2, TRUE, FALSE,
4725 EL_EMC_WALL_SLIPPERY_2, -1, -1
4728 Xround_wall_3, TRUE, FALSE,
4729 EL_EMC_WALL_SLIPPERY_3, -1, -1
4732 Xround_wall_4, TRUE, FALSE,
4733 EL_EMC_WALL_SLIPPERY_4, -1, -1
4736 Xdecor_1, TRUE, FALSE,
4737 EL_EMC_WALL_8, -1, -1
4740 Xdecor_2, TRUE, FALSE,
4741 EL_EMC_WALL_6, -1, -1
4744 Xdecor_3, TRUE, FALSE,
4745 EL_EMC_WALL_4, -1, -1
4748 Xdecor_4, TRUE, FALSE,
4749 EL_EMC_WALL_7, -1, -1
4752 Xdecor_5, TRUE, FALSE,
4753 EL_EMC_WALL_5, -1, -1
4756 Xdecor_6, TRUE, FALSE,
4757 EL_EMC_WALL_9, -1, -1
4760 Xdecor_7, TRUE, FALSE,
4761 EL_EMC_WALL_10, -1, -1
4764 Xdecor_8, TRUE, FALSE,
4765 EL_EMC_WALL_1, -1, -1
4768 Xdecor_9, TRUE, FALSE,
4769 EL_EMC_WALL_2, -1, -1
4772 Xdecor_10, TRUE, FALSE,
4773 EL_EMC_WALL_3, -1, -1
4776 Xdecor_11, TRUE, FALSE,
4777 EL_EMC_WALL_11, -1, -1
4780 Xdecor_12, TRUE, FALSE,
4781 EL_EMC_WALL_12, -1, -1
4784 Xalpha_0, TRUE, FALSE,
4785 EL_CHAR('0'), -1, -1
4788 Xalpha_1, TRUE, FALSE,
4789 EL_CHAR('1'), -1, -1
4792 Xalpha_2, TRUE, FALSE,
4793 EL_CHAR('2'), -1, -1
4796 Xalpha_3, TRUE, FALSE,
4797 EL_CHAR('3'), -1, -1
4800 Xalpha_4, TRUE, FALSE,
4801 EL_CHAR('4'), -1, -1
4804 Xalpha_5, TRUE, FALSE,
4805 EL_CHAR('5'), -1, -1
4808 Xalpha_6, TRUE, FALSE,
4809 EL_CHAR('6'), -1, -1
4812 Xalpha_7, TRUE, FALSE,
4813 EL_CHAR('7'), -1, -1
4816 Xalpha_8, TRUE, FALSE,
4817 EL_CHAR('8'), -1, -1
4820 Xalpha_9, TRUE, FALSE,
4821 EL_CHAR('9'), -1, -1
4824 Xalpha_excla, TRUE, FALSE,
4825 EL_CHAR('!'), -1, -1
4828 Xalpha_quote, TRUE, FALSE,
4829 EL_CHAR('"'), -1, -1
4832 Xalpha_comma, TRUE, FALSE,
4833 EL_CHAR(','), -1, -1
4836 Xalpha_minus, TRUE, FALSE,
4837 EL_CHAR('-'), -1, -1
4840 Xalpha_perio, TRUE, FALSE,
4841 EL_CHAR('.'), -1, -1
4844 Xalpha_colon, TRUE, FALSE,
4845 EL_CHAR(':'), -1, -1
4848 Xalpha_quest, TRUE, FALSE,
4849 EL_CHAR('?'), -1, -1
4852 Xalpha_a, TRUE, FALSE,
4853 EL_CHAR('A'), -1, -1
4856 Xalpha_b, TRUE, FALSE,
4857 EL_CHAR('B'), -1, -1
4860 Xalpha_c, TRUE, FALSE,
4861 EL_CHAR('C'), -1, -1
4864 Xalpha_d, TRUE, FALSE,
4865 EL_CHAR('D'), -1, -1
4868 Xalpha_e, TRUE, FALSE,
4869 EL_CHAR('E'), -1, -1
4872 Xalpha_f, TRUE, FALSE,
4873 EL_CHAR('F'), -1, -1
4876 Xalpha_g, TRUE, FALSE,
4877 EL_CHAR('G'), -1, -1
4880 Xalpha_h, TRUE, FALSE,
4881 EL_CHAR('H'), -1, -1
4884 Xalpha_i, TRUE, FALSE,
4885 EL_CHAR('I'), -1, -1
4888 Xalpha_j, TRUE, FALSE,
4889 EL_CHAR('J'), -1, -1
4892 Xalpha_k, TRUE, FALSE,
4893 EL_CHAR('K'), -1, -1
4896 Xalpha_l, TRUE, FALSE,
4897 EL_CHAR('L'), -1, -1
4900 Xalpha_m, TRUE, FALSE,
4901 EL_CHAR('M'), -1, -1
4904 Xalpha_n, TRUE, FALSE,
4905 EL_CHAR('N'), -1, -1
4908 Xalpha_o, TRUE, FALSE,
4909 EL_CHAR('O'), -1, -1
4912 Xalpha_p, TRUE, FALSE,
4913 EL_CHAR('P'), -1, -1
4916 Xalpha_q, TRUE, FALSE,
4917 EL_CHAR('Q'), -1, -1
4920 Xalpha_r, TRUE, FALSE,
4921 EL_CHAR('R'), -1, -1
4924 Xalpha_s, TRUE, FALSE,
4925 EL_CHAR('S'), -1, -1
4928 Xalpha_t, TRUE, FALSE,
4929 EL_CHAR('T'), -1, -1
4932 Xalpha_u, TRUE, FALSE,
4933 EL_CHAR('U'), -1, -1
4936 Xalpha_v, TRUE, FALSE,
4937 EL_CHAR('V'), -1, -1
4940 Xalpha_w, TRUE, FALSE,
4941 EL_CHAR('W'), -1, -1
4944 Xalpha_x, TRUE, FALSE,
4945 EL_CHAR('X'), -1, -1
4948 Xalpha_y, TRUE, FALSE,
4949 EL_CHAR('Y'), -1, -1
4952 Xalpha_z, TRUE, FALSE,
4953 EL_CHAR('Z'), -1, -1
4956 Xalpha_arrow_e, TRUE, FALSE,
4957 EL_CHAR('>'), -1, -1
4960 Xalpha_arrow_w, TRUE, FALSE,
4961 EL_CHAR('<'), -1, -1
4964 Xalpha_copyr, TRUE, FALSE,
4965 EL_CHAR('©'), -1, -1
4969 Xboom_bug, FALSE, FALSE,
4970 EL_BUG, ACTION_EXPLODING, -1
4973 Xboom_bomb, FALSE, FALSE,
4974 EL_BOMB, ACTION_EXPLODING, -1
4977 Xboom_android, FALSE, FALSE,
4978 EL_EMC_ANDROID, ACTION_OTHER, -1
4981 Xboom_1, FALSE, FALSE,
4982 EL_DEFAULT, ACTION_EXPLODING, -1
4985 Xboom_2, FALSE, FALSE,
4986 EL_DEFAULT, ACTION_EXPLODING, -1
4989 Znormal, FALSE, FALSE,
4993 Zdynamite, FALSE, FALSE,
4997 Zplayer, FALSE, FALSE,
5001 ZBORDER, FALSE, FALSE,
5011 static struct Mapping_EM_to_RND_player
5020 em_player_mapping_list[] =
5024 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5028 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5032 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5036 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5040 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5044 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5048 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5052 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5056 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5060 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5064 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5068 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5072 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5076 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5080 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5084 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5088 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5092 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5096 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5100 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5104 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5108 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5112 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5116 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5120 EL_PLAYER_1, ACTION_DEFAULT, -1,
5124 EL_PLAYER_2, ACTION_DEFAULT, -1,
5128 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5132 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5136 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5140 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5144 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5148 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5152 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5156 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5160 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5164 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5168 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5172 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5176 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5180 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5184 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5188 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5192 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5196 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5200 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5204 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5208 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5212 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5216 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5220 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5224 EL_PLAYER_3, ACTION_DEFAULT, -1,
5228 EL_PLAYER_4, ACTION_DEFAULT, -1,
5237 int map_element_RND_to_EM(int element_rnd)
5239 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5240 static boolean mapping_initialized = FALSE;
5242 if (!mapping_initialized)
5246 /* return "Xalpha_quest" for all undefined elements in mapping array */
5247 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5248 mapping_RND_to_EM[i] = Xalpha_quest;
5250 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5251 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5252 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5253 em_object_mapping_list[i].element_em;
5255 mapping_initialized = TRUE;
5258 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5259 return mapping_RND_to_EM[element_rnd];
5261 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5266 int map_element_EM_to_RND(int element_em)
5268 static unsigned short mapping_EM_to_RND[TILE_MAX];
5269 static boolean mapping_initialized = FALSE;
5271 if (!mapping_initialized)
5275 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5276 for (i = 0; i < TILE_MAX; i++)
5277 mapping_EM_to_RND[i] = EL_UNKNOWN;
5279 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5280 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5281 em_object_mapping_list[i].element_rnd;
5283 mapping_initialized = TRUE;
5286 if (element_em >= 0 && element_em < TILE_MAX)
5287 return mapping_EM_to_RND[element_em];
5289 Error(ERR_WARN, "invalid EM level element %d", element_em);
5294 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5296 struct LevelInfo_EM *level_em = level->native_em_level;
5297 struct LEVEL *lev = level_em->lev;
5300 for (i = 0; i < TILE_MAX; i++)
5301 lev->android_array[i] = Xblank;
5303 for (i = 0; i < level->num_android_clone_elements; i++)
5305 int element_rnd = level->android_clone_element[i];
5306 int element_em = map_element_RND_to_EM(element_rnd);
5308 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5309 if (em_object_mapping_list[j].element_rnd == element_rnd)
5310 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5314 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5316 struct LevelInfo_EM *level_em = level->native_em_level;
5317 struct LEVEL *lev = level_em->lev;
5320 level->num_android_clone_elements = 0;
5322 for (i = 0; i < TILE_MAX; i++)
5324 int element_em = lev->android_array[i];
5326 boolean element_found = FALSE;
5328 if (element_em == Xblank)
5331 element_rnd = map_element_EM_to_RND(element_em);
5333 for (j = 0; j < level->num_android_clone_elements; j++)
5334 if (level->android_clone_element[j] == element_rnd)
5335 element_found = TRUE;
5339 level->android_clone_element[level->num_android_clone_elements++] =
5342 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5347 if (level->num_android_clone_elements == 0)
5349 level->num_android_clone_elements = 1;
5350 level->android_clone_element[0] = EL_EMPTY;
5354 int map_direction_RND_to_EM(int direction)
5356 return (direction == MV_UP ? 0 :
5357 direction == MV_RIGHT ? 1 :
5358 direction == MV_DOWN ? 2 :
5359 direction == MV_LEFT ? 3 :
5363 int map_direction_EM_to_RND(int direction)
5365 return (direction == 0 ? MV_UP :
5366 direction == 1 ? MV_RIGHT :
5367 direction == 2 ? MV_DOWN :
5368 direction == 3 ? MV_LEFT :
5372 int get_next_element(int element)
5376 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5377 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5378 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5379 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5380 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5381 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5382 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5384 default: return element;
5389 int el_act_dir2img(int element, int action, int direction)
5391 element = GFX_ELEMENT(element);
5393 if (direction == MV_NONE)
5394 return element_info[element].graphic[action];
5396 direction = MV_DIR_TO_BIT(direction);
5398 return element_info[element].direction_graphic[action][direction];
5401 int el_act_dir2img(int element, int action, int direction)
5403 element = GFX_ELEMENT(element);
5404 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5406 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5407 return element_info[element].direction_graphic[action][direction];
5412 static int el_act_dir2crm(int element, int action, int direction)
5414 element = GFX_ELEMENT(element);
5416 if (direction == MV_NONE)
5417 return element_info[element].crumbled[action];
5419 direction = MV_DIR_TO_BIT(direction);
5421 return element_info[element].direction_crumbled[action][direction];
5424 static int el_act_dir2crm(int element, int action, int direction)
5426 element = GFX_ELEMENT(element);
5427 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5429 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5430 return element_info[element].direction_crumbled[action][direction];
5434 int el_act2img(int element, int action)
5436 element = GFX_ELEMENT(element);
5438 return element_info[element].graphic[action];
5441 int el_act2crm(int element, int action)
5443 element = GFX_ELEMENT(element);
5445 return element_info[element].crumbled[action];
5448 int el_dir2img(int element, int direction)
5450 element = GFX_ELEMENT(element);
5452 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5455 int el2baseimg(int element)
5457 return element_info[element].graphic[ACTION_DEFAULT];
5460 int el2img(int element)
5462 element = GFX_ELEMENT(element);
5464 return element_info[element].graphic[ACTION_DEFAULT];
5467 int el2edimg(int element)
5469 element = GFX_ELEMENT(element);
5471 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5474 int el2preimg(int element)
5476 element = GFX_ELEMENT(element);
5478 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5481 int font2baseimg(int font_nr)
5483 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5486 int getNumActivePlayers_EM()
5488 int num_players = 0;
5494 for (i = 0; i < MAX_PLAYERS; i++)
5495 if (tape.player_participates[i])
5501 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5503 int game_frame_delay_value;
5505 game_frame_delay_value =
5506 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5507 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5510 if (tape.playing && tape.warp_forward && !tape.pausing)
5511 game_frame_delay_value = 0;
5513 return game_frame_delay_value;
5516 unsigned int InitRND(long seed)
5518 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5519 return InitEngineRandom_EM(seed);
5521 return InitEngineRandom_RND(seed);
5524 void InitGraphicInfo_EM(void)
5526 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5527 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5531 int num_em_gfx_errors = 0;
5533 if (graphic_info_em_object[0][0].bitmap == NULL)
5535 /* EM graphics not yet initialized in em_open_all() */
5540 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5543 /* always start with reliable default values */
5544 for (i = 0; i < TILE_MAX; i++)
5546 object_mapping[i].element_rnd = EL_UNKNOWN;
5547 object_mapping[i].is_backside = FALSE;
5548 object_mapping[i].action = ACTION_DEFAULT;
5549 object_mapping[i].direction = MV_NONE;
5552 /* always start with reliable default values */
5553 for (p = 0; p < MAX_PLAYERS; p++)
5555 for (i = 0; i < SPR_MAX; i++)
5557 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5558 player_mapping[p][i].action = ACTION_DEFAULT;
5559 player_mapping[p][i].direction = MV_NONE;
5563 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5565 int e = em_object_mapping_list[i].element_em;
5567 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5568 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5570 if (em_object_mapping_list[i].action != -1)
5571 object_mapping[e].action = em_object_mapping_list[i].action;
5573 if (em_object_mapping_list[i].direction != -1)
5574 object_mapping[e].direction =
5575 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5578 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5580 int a = em_player_mapping_list[i].action_em;
5581 int p = em_player_mapping_list[i].player_nr;
5583 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5585 if (em_player_mapping_list[i].action != -1)
5586 player_mapping[p][a].action = em_player_mapping_list[i].action;
5588 if (em_player_mapping_list[i].direction != -1)
5589 player_mapping[p][a].direction =
5590 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5593 for (i = 0; i < TILE_MAX; i++)
5595 int element = object_mapping[i].element_rnd;
5596 int action = object_mapping[i].action;
5597 int direction = object_mapping[i].direction;
5598 boolean is_backside = object_mapping[i].is_backside;
5599 boolean action_removing = (action == ACTION_DIGGING ||
5600 action == ACTION_SNAPPING ||
5601 action == ACTION_COLLECTING);
5602 boolean action_exploding = ((action == ACTION_EXPLODING ||
5603 action == ACTION_SMASHED_BY_ROCK ||
5604 action == ACTION_SMASHED_BY_SPRING) &&
5605 element != EL_DIAMOND);
5606 boolean action_active = (action == ACTION_ACTIVE);
5607 boolean action_other = (action == ACTION_OTHER);
5609 for (j = 0; j < 8; j++)
5611 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5612 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5614 i == Xdrip_stretch ? element :
5615 i == Xdrip_stretchB ? element :
5616 i == Ydrip_s1 ? element :
5617 i == Ydrip_s1B ? element :
5618 i == Xball_1B ? element :
5619 i == Xball_2 ? element :
5620 i == Xball_2B ? element :
5621 i == Yball_eat ? element :
5622 i == Ykey_1_eat ? element :
5623 i == Ykey_2_eat ? element :
5624 i == Ykey_3_eat ? element :
5625 i == Ykey_4_eat ? element :
5626 i == Ykey_5_eat ? element :
5627 i == Ykey_6_eat ? element :
5628 i == Ykey_7_eat ? element :
5629 i == Ykey_8_eat ? element :
5630 i == Ylenses_eat ? element :
5631 i == Ymagnify_eat ? element :
5632 i == Ygrass_eat ? element :
5633 i == Ydirt_eat ? element :
5634 i == Yemerald_stone ? EL_EMERALD :
5635 i == Ydiamond_stone ? EL_ROCK :
5636 i == Xsand_stonein_1 ? element :
5637 i == Xsand_stonein_2 ? element :
5638 i == Xsand_stonein_3 ? element :
5639 i == Xsand_stonein_4 ? element :
5640 is_backside ? EL_EMPTY :
5641 action_removing ? EL_EMPTY :
5643 int effective_action = (j < 7 ? action :
5644 i == Xdrip_stretch ? action :
5645 i == Xdrip_stretchB ? action :
5646 i == Ydrip_s1 ? action :
5647 i == Ydrip_s1B ? action :
5648 i == Xball_1B ? action :
5649 i == Xball_2 ? action :
5650 i == Xball_2B ? action :
5651 i == Yball_eat ? action :
5652 i == Ykey_1_eat ? action :
5653 i == Ykey_2_eat ? action :
5654 i == Ykey_3_eat ? action :
5655 i == Ykey_4_eat ? action :
5656 i == Ykey_5_eat ? action :
5657 i == Ykey_6_eat ? action :
5658 i == Ykey_7_eat ? action :
5659 i == Ykey_8_eat ? action :
5660 i == Ylenses_eat ? action :
5661 i == Ymagnify_eat ? action :
5662 i == Ygrass_eat ? action :
5663 i == Ydirt_eat ? action :
5664 i == Xsand_stonein_1 ? action :
5665 i == Xsand_stonein_2 ? action :
5666 i == Xsand_stonein_3 ? action :
5667 i == Xsand_stonein_4 ? action :
5668 i == Xsand_stoneout_1 ? action :
5669 i == Xsand_stoneout_2 ? action :
5670 i == Xboom_android ? ACTION_EXPLODING :
5671 action_exploding ? ACTION_EXPLODING :
5672 action_active ? action :
5673 action_other ? action :
5675 int graphic = (el_act_dir2img(effective_element, effective_action,
5677 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5679 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5680 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5681 boolean has_action_graphics = (graphic != base_graphic);
5682 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5683 struct GraphicInfo *g = &graphic_info[graphic];
5684 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5687 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5688 boolean special_animation = (action != ACTION_DEFAULT &&
5689 g->anim_frames == 3 &&
5690 g->anim_delay == 2 &&
5691 g->anim_mode & ANIM_LINEAR);
5692 int sync_frame = (i == Xdrip_stretch ? 7 :
5693 i == Xdrip_stretchB ? 7 :
5694 i == Ydrip_s2 ? j + 8 :
5695 i == Ydrip_s2B ? j + 8 :
5704 i == Xfake_acid_1 ? 0 :
5705 i == Xfake_acid_2 ? 10 :
5706 i == Xfake_acid_3 ? 20 :
5707 i == Xfake_acid_4 ? 30 :
5708 i == Xfake_acid_5 ? 40 :
5709 i == Xfake_acid_6 ? 50 :
5710 i == Xfake_acid_7 ? 60 :
5711 i == Xfake_acid_8 ? 70 :
5713 i == Xball_2B ? j + 8 :
5714 i == Yball_eat ? j + 1 :
5715 i == Ykey_1_eat ? j + 1 :
5716 i == Ykey_2_eat ? j + 1 :
5717 i == Ykey_3_eat ? j + 1 :
5718 i == Ykey_4_eat ? j + 1 :
5719 i == Ykey_5_eat ? j + 1 :
5720 i == Ykey_6_eat ? j + 1 :
5721 i == Ykey_7_eat ? j + 1 :
5722 i == Ykey_8_eat ? j + 1 :
5723 i == Ylenses_eat ? j + 1 :
5724 i == Ymagnify_eat ? j + 1 :
5725 i == Ygrass_eat ? j + 1 :
5726 i == Ydirt_eat ? j + 1 :
5727 i == Xamoeba_1 ? 0 :
5728 i == Xamoeba_2 ? 1 :
5729 i == Xamoeba_3 ? 2 :
5730 i == Xamoeba_4 ? 3 :
5731 i == Xamoeba_5 ? 0 :
5732 i == Xamoeba_6 ? 1 :
5733 i == Xamoeba_7 ? 2 :
5734 i == Xamoeba_8 ? 3 :
5735 i == Xexit_2 ? j + 8 :
5736 i == Xexit_3 ? j + 16 :
5737 i == Xdynamite_1 ? 0 :
5738 i == Xdynamite_2 ? 8 :
5739 i == Xdynamite_3 ? 16 :
5740 i == Xdynamite_4 ? 24 :
5741 i == Xsand_stonein_1 ? j + 1 :
5742 i == Xsand_stonein_2 ? j + 9 :
5743 i == Xsand_stonein_3 ? j + 17 :
5744 i == Xsand_stonein_4 ? j + 25 :
5745 i == Xsand_stoneout_1 && j == 0 ? 0 :
5746 i == Xsand_stoneout_1 && j == 1 ? 0 :
5747 i == Xsand_stoneout_1 && j == 2 ? 1 :
5748 i == Xsand_stoneout_1 && j == 3 ? 2 :
5749 i == Xsand_stoneout_1 && j == 4 ? 2 :
5750 i == Xsand_stoneout_1 && j == 5 ? 3 :
5751 i == Xsand_stoneout_1 && j == 6 ? 4 :
5752 i == Xsand_stoneout_1 && j == 7 ? 4 :
5753 i == Xsand_stoneout_2 && j == 0 ? 5 :
5754 i == Xsand_stoneout_2 && j == 1 ? 6 :
5755 i == Xsand_stoneout_2 && j == 2 ? 7 :
5756 i == Xsand_stoneout_2 && j == 3 ? 8 :
5757 i == Xsand_stoneout_2 && j == 4 ? 9 :
5758 i == Xsand_stoneout_2 && j == 5 ? 11 :
5759 i == Xsand_stoneout_2 && j == 6 ? 13 :
5760 i == Xsand_stoneout_2 && j == 7 ? 15 :
5761 i == Xboom_bug && j == 1 ? 2 :
5762 i == Xboom_bug && j == 2 ? 2 :
5763 i == Xboom_bug && j == 3 ? 4 :
5764 i == Xboom_bug && j == 4 ? 4 :
5765 i == Xboom_bug && j == 5 ? 2 :
5766 i == Xboom_bug && j == 6 ? 2 :
5767 i == Xboom_bug && j == 7 ? 0 :
5768 i == Xboom_bomb && j == 1 ? 2 :
5769 i == Xboom_bomb && j == 2 ? 2 :
5770 i == Xboom_bomb && j == 3 ? 4 :
5771 i == Xboom_bomb && j == 4 ? 4 :
5772 i == Xboom_bomb && j == 5 ? 2 :
5773 i == Xboom_bomb && j == 6 ? 2 :
5774 i == Xboom_bomb && j == 7 ? 0 :
5775 i == Xboom_android && j == 7 ? 6 :
5776 i == Xboom_1 && j == 1 ? 2 :
5777 i == Xboom_1 && j == 2 ? 2 :
5778 i == Xboom_1 && j == 3 ? 4 :
5779 i == Xboom_1 && j == 4 ? 4 :
5780 i == Xboom_1 && j == 5 ? 6 :
5781 i == Xboom_1 && j == 6 ? 6 :
5782 i == Xboom_1 && j == 7 ? 8 :
5783 i == Xboom_2 && j == 0 ? 8 :
5784 i == Xboom_2 && j == 1 ? 8 :
5785 i == Xboom_2 && j == 2 ? 10 :
5786 i == Xboom_2 && j == 3 ? 10 :
5787 i == Xboom_2 && j == 4 ? 10 :
5788 i == Xboom_2 && j == 5 ? 12 :
5789 i == Xboom_2 && j == 6 ? 12 :
5790 i == Xboom_2 && j == 7 ? 12 :
5791 special_animation && j == 4 ? 3 :
5792 effective_action != action ? 0 :
5796 Bitmap *debug_bitmap = g_em->bitmap;
5797 int debug_src_x = g_em->src_x;
5798 int debug_src_y = g_em->src_y;
5801 int frame = getAnimationFrame(g->anim_frames,
5804 g->anim_start_frame,
5807 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5808 g->double_movement && is_backside);
5810 g_em->bitmap = src_bitmap;
5811 g_em->src_x = src_x;
5812 g_em->src_y = src_y;
5813 g_em->src_offset_x = 0;
5814 g_em->src_offset_y = 0;
5815 g_em->dst_offset_x = 0;
5816 g_em->dst_offset_y = 0;
5817 g_em->width = TILEX;
5818 g_em->height = TILEY;
5820 g_em->crumbled_bitmap = NULL;
5821 g_em->crumbled_src_x = 0;
5822 g_em->crumbled_src_y = 0;
5823 g_em->crumbled_border_size = 0;
5825 g_em->has_crumbled_graphics = FALSE;
5826 g_em->preserve_background = FALSE;
5829 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5830 printf("::: empty crumbled: %d [%s], %d, %d\n",
5831 effective_element, element_info[effective_element].token_name,
5832 effective_action, direction);
5835 /* if element can be crumbled, but certain action graphics are just empty
5836 space (like snapping sand with the original R'n'D graphics), do not
5837 treat these empty space graphics as crumbled graphics in EMC engine */
5838 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5840 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5842 g_em->has_crumbled_graphics = TRUE;
5843 g_em->crumbled_bitmap = src_bitmap;
5844 g_em->crumbled_src_x = src_x;
5845 g_em->crumbled_src_y = src_y;
5846 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5850 if (element == EL_ROCK &&
5851 effective_action == ACTION_FILLING)
5852 printf("::: has_action_graphics == %d\n", has_action_graphics);
5855 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5856 effective_action == ACTION_MOVING ||
5857 effective_action == ACTION_PUSHING ||
5858 effective_action == ACTION_EATING)) ||
5859 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5860 effective_action == ACTION_EMPTYING)))
5863 (effective_action == ACTION_FALLING ||
5864 effective_action == ACTION_FILLING ||
5865 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5866 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5867 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5868 int num_steps = (i == Ydrip_s1 ? 16 :
5869 i == Ydrip_s1B ? 16 :
5870 i == Ydrip_s2 ? 16 :
5871 i == Ydrip_s2B ? 16 :
5872 i == Xsand_stonein_1 ? 32 :
5873 i == Xsand_stonein_2 ? 32 :
5874 i == Xsand_stonein_3 ? 32 :
5875 i == Xsand_stonein_4 ? 32 :
5876 i == Xsand_stoneout_1 ? 16 :
5877 i == Xsand_stoneout_2 ? 16 : 8);
5878 int cx = ABS(dx) * (TILEX / num_steps);
5879 int cy = ABS(dy) * (TILEY / num_steps);
5880 int step_frame = (i == Ydrip_s2 ? j + 8 :
5881 i == Ydrip_s2B ? j + 8 :
5882 i == Xsand_stonein_2 ? j + 8 :
5883 i == Xsand_stonein_3 ? j + 16 :
5884 i == Xsand_stonein_4 ? j + 24 :
5885 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5886 int step = (is_backside ? step_frame : num_steps - step_frame);
5888 if (is_backside) /* tile where movement starts */
5890 if (dx < 0 || dy < 0)
5892 g_em->src_offset_x = cx * step;
5893 g_em->src_offset_y = cy * step;
5897 g_em->dst_offset_x = cx * step;
5898 g_em->dst_offset_y = cy * step;
5901 else /* tile where movement ends */
5903 if (dx < 0 || dy < 0)
5905 g_em->dst_offset_x = cx * step;
5906 g_em->dst_offset_y = cy * step;
5910 g_em->src_offset_x = cx * step;
5911 g_em->src_offset_y = cy * step;
5915 g_em->width = TILEX - cx * step;
5916 g_em->height = TILEY - cy * step;
5919 /* create unique graphic identifier to decide if tile must be redrawn */
5920 /* bit 31 - 16 (16 bit): EM style graphic
5921 bit 15 - 12 ( 4 bit): EM style frame
5922 bit 11 - 6 ( 6 bit): graphic width
5923 bit 5 - 0 ( 6 bit): graphic height */
5924 g_em->unique_identifier =
5925 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5929 /* skip check for EMC elements not contained in original EMC artwork */
5930 if (element == EL_EMC_FAKE_ACID)
5933 if (g_em->bitmap != debug_bitmap ||
5934 g_em->src_x != debug_src_x ||
5935 g_em->src_y != debug_src_y ||
5936 g_em->src_offset_x != 0 ||
5937 g_em->src_offset_y != 0 ||
5938 g_em->dst_offset_x != 0 ||
5939 g_em->dst_offset_y != 0 ||
5940 g_em->width != TILEX ||
5941 g_em->height != TILEY)
5943 static int last_i = -1;
5951 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5952 i, element, element_info[element].token_name,
5953 element_action_info[effective_action].suffix, direction);
5955 if (element != effective_element)
5956 printf(" [%d ('%s')]",
5958 element_info[effective_element].token_name);
5962 if (g_em->bitmap != debug_bitmap)
5963 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5964 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5966 if (g_em->src_x != debug_src_x ||
5967 g_em->src_y != debug_src_y)
5968 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5969 j, (is_backside ? 'B' : 'F'),
5970 g_em->src_x, g_em->src_y,
5971 g_em->src_x / 32, g_em->src_y / 32,
5972 debug_src_x, debug_src_y,
5973 debug_src_x / 32, debug_src_y / 32);
5975 if (g_em->src_offset_x != 0 ||
5976 g_em->src_offset_y != 0 ||
5977 g_em->dst_offset_x != 0 ||
5978 g_em->dst_offset_y != 0)
5979 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5981 g_em->src_offset_x, g_em->src_offset_y,
5982 g_em->dst_offset_x, g_em->dst_offset_y);
5984 if (g_em->width != TILEX ||
5985 g_em->height != TILEY)
5986 printf(" %d (%d): size %d,%d should be %d,%d\n",
5988 g_em->width, g_em->height, TILEX, TILEY);
5990 num_em_gfx_errors++;
5997 for (i = 0; i < TILE_MAX; i++)
5999 for (j = 0; j < 8; j++)
6001 int element = object_mapping[i].element_rnd;
6002 int action = object_mapping[i].action;
6003 int direction = object_mapping[i].direction;
6004 boolean is_backside = object_mapping[i].is_backside;
6005 int graphic_action = el_act_dir2img(element, action, direction);
6006 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6008 if ((action == ACTION_SMASHED_BY_ROCK ||
6009 action == ACTION_SMASHED_BY_SPRING ||
6010 action == ACTION_EATING) &&
6011 graphic_action == graphic_default)
6013 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6014 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6015 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6016 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6019 /* no separate animation for "smashed by rock" -- use rock instead */
6020 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6021 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6023 g_em->bitmap = g_xx->bitmap;
6024 g_em->src_x = g_xx->src_x;
6025 g_em->src_y = g_xx->src_y;
6026 g_em->src_offset_x = g_xx->src_offset_x;
6027 g_em->src_offset_y = g_xx->src_offset_y;
6028 g_em->dst_offset_x = g_xx->dst_offset_x;
6029 g_em->dst_offset_y = g_xx->dst_offset_y;
6030 g_em->width = g_xx->width;
6031 g_em->height = g_xx->height;
6032 g_em->unique_identifier = g_xx->unique_identifier;
6035 g_em->preserve_background = TRUE;
6040 for (p = 0; p < MAX_PLAYERS; p++)
6042 for (i = 0; i < SPR_MAX; i++)
6044 int element = player_mapping[p][i].element_rnd;
6045 int action = player_mapping[p][i].action;
6046 int direction = player_mapping[p][i].direction;
6048 for (j = 0; j < 8; j++)
6050 int effective_element = element;
6051 int effective_action = action;
6052 int graphic = (direction == MV_NONE ?
6053 el_act2img(effective_element, effective_action) :
6054 el_act_dir2img(effective_element, effective_action,
6056 struct GraphicInfo *g = &graphic_info[graphic];
6057 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6063 Bitmap *debug_bitmap = g_em->bitmap;
6064 int debug_src_x = g_em->src_x;
6065 int debug_src_y = g_em->src_y;
6068 int frame = getAnimationFrame(g->anim_frames,
6071 g->anim_start_frame,
6074 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6076 g_em->bitmap = src_bitmap;
6077 g_em->src_x = src_x;
6078 g_em->src_y = src_y;
6079 g_em->src_offset_x = 0;
6080 g_em->src_offset_y = 0;
6081 g_em->dst_offset_x = 0;
6082 g_em->dst_offset_y = 0;
6083 g_em->width = TILEX;
6084 g_em->height = TILEY;
6088 /* skip check for EMC elements not contained in original EMC artwork */
6089 if (element == EL_PLAYER_3 ||
6090 element == EL_PLAYER_4)
6093 if (g_em->bitmap != debug_bitmap ||
6094 g_em->src_x != debug_src_x ||
6095 g_em->src_y != debug_src_y)
6097 static int last_i = -1;
6105 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6106 p, i, element, element_info[element].token_name,
6107 element_action_info[effective_action].suffix, direction);
6109 if (element != effective_element)
6110 printf(" [%d ('%s')]",
6112 element_info[effective_element].token_name);
6116 if (g_em->bitmap != debug_bitmap)
6117 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6118 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6120 if (g_em->src_x != debug_src_x ||
6121 g_em->src_y != debug_src_y)
6122 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6124 g_em->src_x, g_em->src_y,
6125 g_em->src_x / 32, g_em->src_y / 32,
6126 debug_src_x, debug_src_y,
6127 debug_src_x / 32, debug_src_y / 32);
6129 num_em_gfx_errors++;
6139 printf("::: [%d errors found]\n", num_em_gfx_errors);
6145 void PlayMenuSound()
6147 int sound = menu.sound[game_status];
6149 if (sound == SND_UNDEFINED)
6152 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6153 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6156 if (IS_LOOP_SOUND(sound))
6157 PlaySoundLoop(sound);
6162 void PlayMenuSoundStereo(int sound, int stereo_position)
6164 if (sound == SND_UNDEFINED)
6167 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6168 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6171 if (IS_LOOP_SOUND(sound))
6172 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6174 PlaySoundStereo(sound, stereo_position);
6177 void PlayMenuSoundIfLoop()
6179 int sound = menu.sound[game_status];
6181 if (sound == SND_UNDEFINED)
6184 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6185 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6188 if (IS_LOOP_SOUND(sound))
6189 PlaySoundLoop(sound);
6192 void PlayMenuMusic()
6194 int music = menu.music[game_status];
6196 if (music == MUS_UNDEFINED)
6202 void ToggleFullscreenIfNeeded()
6204 boolean change_fullscreen = (setup.fullscreen !=
6205 video.fullscreen_enabled);
6206 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6207 !strEqual(setup.fullscreen_mode,
6208 video.fullscreen_mode_current));
6210 if (!video.fullscreen_available)
6214 if (change_fullscreen || change_fullscreen_mode)
6216 if (setup.fullscreen != video.fullscreen_enabled ||
6217 setup.fullscreen_mode != video.fullscreen_mode_current)
6220 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6222 /* save backbuffer content which gets lost when toggling fullscreen mode */
6223 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6226 if (change_fullscreen_mode)
6228 if (setup.fullscreen && video.fullscreen_enabled)
6231 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6233 /* (this is now set in sdl.c) */
6235 video.fullscreen_mode_current = setup.fullscreen_mode;
6237 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6240 /* toggle fullscreen */
6241 ChangeVideoModeIfNeeded(setup.fullscreen);
6243 setup.fullscreen = video.fullscreen_enabled;
6245 /* restore backbuffer content from temporary backbuffer backup bitmap */
6246 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6248 FreeBitmap(tmp_backbuffer);
6251 /* update visible window/screen */
6252 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6254 redraw_mask = REDRAW_ALL;