1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX 0
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES 0
30 #define TOOL_CTRL_ID_NO 1
31 #define TOOL_CTRL_ID_CONFIRM 2
32 #define TOOL_CTRL_ID_PLAYER_1 3
33 #define TOOL_CTRL_ID_PLAYER_2 4
34 #define TOOL_CTRL_ID_PLAYER_3 5
35 #define TOOL_CTRL_ID_PLAYER_4 6
37 #define NUM_TOOL_BUTTONS 7
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
48 static char *print_if_not_empty(int element)
50 static char *s = NULL;
51 char *token_name = element_info[element].token_name;
56 s = checked_malloc(strlen(token_name) + 10 + 1);
58 if (element != EL_EMPTY)
59 sprintf(s, "%d\t['%s']", element, token_name);
61 sprintf(s, "%d", element);
66 void DumpTile(int x, int y)
71 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
78 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
81 if (!IN_LEV_FIELD(x, y))
83 printf("(not in level field)\n");
89 printf(" Feld: %d\t['%s']\n", Feld[x][y],
90 element_info[Feld[x][y]].token_name);
91 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
92 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
93 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
94 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95 printf(" MovPos: %d\n", MovPos[x][y]);
96 printf(" MovDir: %d\n", MovDir[x][y]);
97 printf(" MovDelay: %d\n", MovDelay[x][y]);
98 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
99 printf(" CustomValue: %d\n", CustomValue[x][y]);
100 printf(" GfxElement: %d\n", GfxElement[x][y]);
101 printf(" GfxAction: %d\n", GfxAction[x][y]);
102 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
106 void SetDrawtoField(int mode)
108 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
119 drawto_field = fieldbuffer;
121 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
138 if (game_status == GAME_MODE_PLAYING &&
139 level.game_engine_type == GAME_ENGINE_TYPE_EM)
141 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
153 width = gfx.sxsize + 2 * TILEX;
154 height = gfx.sysize + 2 * TILEY;
157 if (force_redraw || setup.direct_draw)
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 if (setup.direct_draw)
164 SetDrawtoField(DRAW_BACKBUFFER);
166 for (xx = BX1; xx <= BX2; xx++)
167 for (yy = BY1; yy <= BY2; yy++)
168 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
169 DrawScreenField(xx, yy);
172 if (setup.direct_draw)
173 SetDrawtoField(DRAW_DIRECT);
176 if (setup.soft_scrolling)
178 int fx = FX, fy = FY;
180 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
181 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
183 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
195 BlitBitmap(drawto, window, x, y, width, height, x, y);
198 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
200 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
202 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
203 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
206 void DrawMaskedBorder_FIELD()
208 if (game_status >= GAME_MODE_TITLE &&
209 game_status <= GAME_MODE_PLAYING &&
210 border.draw_masked[game_status])
211 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
214 void DrawMaskedBorder_DOOR_1()
216 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
217 (game_status != GAME_MODE_EDITOR ||
218 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
219 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
222 void DrawMaskedBorder_DOOR_2()
224 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
225 game_status != GAME_MODE_EDITOR)
226 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
229 void DrawMaskedBorder_DOOR_3()
231 /* currently not available */
234 void DrawMaskedBorder_ALL()
236 DrawMaskedBorder_FIELD();
237 DrawMaskedBorder_DOOR_1();
238 DrawMaskedBorder_DOOR_2();
239 DrawMaskedBorder_DOOR_3();
242 void DrawMaskedBorder(int redraw_mask)
244 /* do not draw masked screen borders when displaying title screens */
245 if (effectiveGameStatus() == GAME_MODE_TITLE)
248 if (redraw_mask & REDRAW_ALL)
249 DrawMaskedBorder_ALL();
252 if (redraw_mask & REDRAW_FIELD)
253 DrawMaskedBorder_FIELD();
254 if (redraw_mask & REDRAW_DOOR_1)
255 DrawMaskedBorder_DOOR_1();
256 if (redraw_mask & REDRAW_DOOR_2)
257 DrawMaskedBorder_DOOR_2();
258 if (redraw_mask & REDRAW_DOOR_3)
259 DrawMaskedBorder_DOOR_3();
266 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
268 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
269 redraw_mask &= ~REDRAW_MAIN;
271 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
272 redraw_mask |= REDRAW_FIELD;
274 if (redraw_mask & REDRAW_FIELD)
275 redraw_mask &= ~REDRAW_TILES;
277 if (redraw_mask == REDRAW_NONE)
280 if (redraw_mask & REDRAW_TILES &&
281 game_status == GAME_MODE_PLAYING &&
282 border.draw_masked[GAME_MODE_PLAYING])
283 redraw_mask |= REDRAW_FIELD;
285 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
287 static boolean last_frame_skipped = FALSE;
288 boolean skip_even_when_not_scrolling = TRUE;
289 boolean just_scrolling = (ScreenMovDir != 0);
290 boolean verbose = FALSE;
292 if (global.fps_slowdown_factor > 1 &&
293 (FrameCounter % global.fps_slowdown_factor) &&
294 (just_scrolling || skip_even_when_not_scrolling))
296 redraw_mask &= ~REDRAW_MAIN;
298 last_frame_skipped = TRUE;
301 printf("FRAME SKIPPED\n");
305 if (last_frame_skipped)
306 redraw_mask |= REDRAW_FIELD;
308 last_frame_skipped = FALSE;
311 printf("frame not skipped\n");
315 /* synchronize X11 graphics at this point; if we would synchronize the
316 display immediately after the buffer switching (after the XFlush),
317 this could mean that we have to wait for the graphics to complete,
318 although we could go on doing calculations for the next frame */
322 /* prevent drawing masked border to backbuffer when using playfield buffer */
323 if (game_status != GAME_MODE_PLAYING ||
324 redraw_mask & REDRAW_FROM_BACKBUFFER ||
325 buffer == backbuffer)
326 DrawMaskedBorder(redraw_mask);
328 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
330 if (redraw_mask & REDRAW_ALL)
332 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
334 redraw_mask = REDRAW_NONE;
337 if (redraw_mask & REDRAW_FIELD)
339 if (game_status != GAME_MODE_PLAYING ||
340 redraw_mask & REDRAW_FROM_BACKBUFFER)
342 BlitBitmap(backbuffer, window,
343 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
347 int fx = FX, fy = FY;
349 if (setup.soft_scrolling)
351 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
352 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
355 if (setup.soft_scrolling ||
356 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
357 ABS(ScreenMovPos) == ScrollStepSize ||
358 redraw_tiles > REDRAWTILES_THRESHOLD)
360 if (border.draw_masked[GAME_MODE_PLAYING])
362 if (buffer != backbuffer)
364 /* copy playfield buffer to backbuffer to add masked border */
365 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
366 DrawMaskedBorder(REDRAW_FIELD);
369 BlitBitmap(backbuffer, window,
370 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
375 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
380 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
382 (setup.soft_scrolling ?
383 "setup.soft_scrolling" :
384 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
385 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
386 ABS(ScreenGfxPos) == ScrollStepSize ?
387 "ABS(ScreenGfxPos) == ScrollStepSize" :
388 "redraw_tiles > REDRAWTILES_THRESHOLD"));
394 redraw_mask &= ~REDRAW_MAIN;
397 if (redraw_mask & REDRAW_DOORS)
399 if (redraw_mask & REDRAW_DOOR_1)
400 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
402 if (redraw_mask & REDRAW_DOOR_2)
403 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
405 if (redraw_mask & REDRAW_DOOR_3)
406 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
408 redraw_mask &= ~REDRAW_DOORS;
411 if (redraw_mask & REDRAW_MICROLEVEL)
413 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
414 SX, SY + 10 * TILEY);
416 redraw_mask &= ~REDRAW_MICROLEVEL;
419 if (redraw_mask & REDRAW_TILES)
421 for (x = 0; x < SCR_FIELDX; x++)
422 for (y = 0 ; y < SCR_FIELDY; y++)
423 if (redraw[redraw_x1 + x][redraw_y1 + y])
424 BlitBitmap(buffer, window,
425 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
426 SX + x * TILEX, SY + y * TILEY);
429 if (redraw_mask & REDRAW_FPS) /* display frames per second */
434 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
435 if (!global.fps_slowdown)
438 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
439 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
444 for (x = 0; x < MAX_BUF_XSIZE; x++)
445 for (y = 0; y < MAX_BUF_YSIZE; y++)
448 redraw_mask = REDRAW_NONE;
454 long fading_delay = 300;
456 if (setup.fading && (redraw_mask & REDRAW_FIELD))
463 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
466 for (i = 0; i < 2 * FULL_SYSIZE; i++)
468 for (y = 0; y < FULL_SYSIZE; y++)
470 BlitBitmap(backbuffer, window,
471 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
479 for (i = 1; i < FULL_SYSIZE; i+=2)
480 BlitBitmap(backbuffer, window,
481 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
487 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
488 BlitBitmapMasked(backbuffer, window,
489 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
494 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
495 BlitBitmapMasked(backbuffer, window,
496 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
501 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
502 BlitBitmapMasked(backbuffer, window,
503 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
508 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
509 BlitBitmapMasked(backbuffer, window,
510 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
515 redraw_mask &= ~REDRAW_MAIN;
522 void FadeExt(int fade_mask, int fade_mode)
524 void (*draw_border_function)(void) = NULL;
525 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
526 int x, y, width, height;
527 int fade_delay, post_delay;
529 if (fade_mask & REDRAW_FIELD)
534 height = FULL_SYSIZE;
536 fade_delay = menu.fade_delay;
537 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
539 draw_border_function = DrawMaskedBorder_FIELD;
541 else /* REDRAW_ALL */
548 fade_delay = title.fade_delay_final;
549 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? title.post_delay_final : 0);
552 redraw_mask |= fade_mask;
554 if (!setup.fade_screens || fade_delay == 0)
556 if (fade_mode == FADE_MODE_FADE_OUT)
557 ClearRectangle(backbuffer, x, y, width, height);
564 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
565 draw_border_function);
567 redraw_mask &= ~fade_mask;
570 void FadeIn(int fade_mask)
572 FadeExt(fade_mask, FADE_MODE_FADE_IN);
575 void FadeOut(int fade_mask)
577 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
580 void FadeCross(int fade_mask)
582 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
585 void FadeCrossSaveBackbuffer()
587 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
590 void SetMainBackgroundImageIfDefined(int graphic)
592 if (graphic_info[graphic].bitmap)
593 SetMainBackgroundImage(graphic);
596 void SetMainBackgroundImage(int graphic)
598 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
599 graphic_info[graphic].bitmap ?
600 graphic_info[graphic].bitmap :
601 graphic_info[IMG_BACKGROUND].bitmap);
604 void SetDoorBackgroundImage(int graphic)
606 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
607 graphic_info[graphic].bitmap ?
608 graphic_info[graphic].bitmap :
609 graphic_info[IMG_BACKGROUND].bitmap);
612 void SetPanelBackground()
614 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
615 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
617 SetDoorBackgroundBitmap(bitmap_db_panel);
620 void DrawBackground(int x, int y, int width, int height)
622 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
623 /* (when entering hall of fame after playing) */
625 ClearRectangleOnBackground(drawto, x, y, width, height);
627 ClearRectangleOnBackground(backbuffer, x, y, width, height);
630 redraw_mask |= REDRAW_FIELD;
633 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
635 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
637 if (font->bitmap == NULL)
640 DrawBackground(x, y, width, height);
643 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
645 struct GraphicInfo *g = &graphic_info[graphic];
647 if (g->bitmap == NULL)
650 DrawBackground(x, y, width, height);
655 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
656 /* (when entering hall of fame after playing) */
657 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
659 /* !!! maybe this should be done before clearing the background !!! */
660 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
662 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
663 SetDrawtoField(DRAW_BUFFERED);
666 SetDrawtoField(DRAW_BACKBUFFER);
668 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
670 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
671 SetDrawtoField(DRAW_DIRECT);
675 void MarkTileDirty(int x, int y)
677 int xx = redraw_x1 + x;
678 int yy = redraw_y1 + y;
683 redraw[xx][yy] = TRUE;
684 redraw_mask |= REDRAW_TILES;
687 void SetBorderElement()
691 BorderElement = EL_EMPTY;
693 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
695 for (x = 0; x < lev_fieldx; x++)
697 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
698 BorderElement = EL_STEELWALL;
700 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
706 void SetRandomAnimationValue(int x, int y)
708 gfx.anim_random_frame = GfxRandom[x][y];
711 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
713 /* animation synchronized with global frame counter, not move position */
714 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
715 sync_frame = FrameCounter;
717 return getAnimationFrame(graphic_info[graphic].anim_frames,
718 graphic_info[graphic].anim_delay,
719 graphic_info[graphic].anim_mode,
720 graphic_info[graphic].anim_start_frame,
724 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
725 int *x, int *y, boolean get_backside)
727 struct GraphicInfo *g = &graphic_info[graphic];
728 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
729 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
733 if (g->offset_y == 0) /* frames are ordered horizontally */
735 int max_width = g->anim_frames_per_line * g->width;
736 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
738 *x = pos % max_width;
739 *y = src_y % g->height + pos / max_width * g->height;
741 else if (g->offset_x == 0) /* frames are ordered vertically */
743 int max_height = g->anim_frames_per_line * g->height;
744 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
746 *x = src_x % g->width + pos / max_height * g->width;
747 *y = pos % max_height;
749 else /* frames are ordered diagonally */
751 *x = src_x + frame * g->offset_x;
752 *y = src_y + frame * g->offset_y;
756 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
758 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
761 void DrawGraphic(int x, int y, int graphic, int frame)
764 if (!IN_SCR_FIELD(x, y))
766 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
767 printf("DrawGraphic(): This should never happen!\n");
772 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
776 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
782 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
783 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
786 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
789 if (!IN_SCR_FIELD(x, y))
791 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
792 printf("DrawGraphicThruMask(): This should never happen!\n");
797 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
802 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
808 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
810 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
811 dst_x - src_x, dst_y - src_y);
812 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
815 void DrawMiniGraphic(int x, int y, int graphic)
817 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
818 MarkTileDirty(x / 2, y / 2);
821 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
823 struct GraphicInfo *g = &graphic_info[graphic];
825 int mini_starty = g->bitmap->height * 2 / 3;
828 *x = mini_startx + g->src_x / 2;
829 *y = mini_starty + g->src_y / 2;
832 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
837 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
838 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
841 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
842 int graphic, int frame,
843 int cut_mode, int mask_mode)
848 int width = TILEX, height = TILEY;
851 if (dx || dy) /* shifted graphic */
853 if (x < BX1) /* object enters playfield from the left */
860 else if (x > BX2) /* object enters playfield from the right */
866 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
872 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
874 else if (dx) /* general horizontal movement */
875 MarkTileDirty(x + SIGN(dx), y);
877 if (y < BY1) /* object enters playfield from the top */
879 if (cut_mode==CUT_BELOW) /* object completely above top border */
887 else if (y > BY2) /* object enters playfield from the bottom */
893 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
899 else if (dy > 0 && cut_mode == CUT_ABOVE)
901 if (y == BY2) /* object completely above bottom border */
907 MarkTileDirty(x, y + 1);
908 } /* object leaves playfield to the bottom */
909 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
911 else if (dy) /* general vertical movement */
912 MarkTileDirty(x, y + SIGN(dy));
916 if (!IN_SCR_FIELD(x, y))
918 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
919 printf("DrawGraphicShifted(): This should never happen!\n");
924 if (width > 0 && height > 0)
926 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
931 dst_x = FX + x * TILEX + dx;
932 dst_y = FY + y * TILEY + dy;
934 if (mask_mode == USE_MASKING)
936 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
937 dst_x - src_x, dst_y - src_y);
938 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
942 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
949 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
950 int graphic, int frame,
951 int cut_mode, int mask_mode)
956 int width = TILEX, height = TILEY;
959 int x2 = x + SIGN(dx);
960 int y2 = y + SIGN(dy);
961 int anim_frames = graphic_info[graphic].anim_frames;
962 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
963 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
964 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
966 /* re-calculate animation frame for two-tile movement animation */
967 frame = getGraphicAnimationFrame(graphic, sync_frame);
969 /* check if movement start graphic inside screen area and should be drawn */
970 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
972 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
974 dst_x = FX + x1 * TILEX;
975 dst_y = FY + y1 * TILEY;
977 if (mask_mode == USE_MASKING)
979 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
980 dst_x - src_x, dst_y - src_y);
981 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
985 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
988 MarkTileDirty(x1, y1);
991 /* check if movement end graphic inside screen area and should be drawn */
992 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
994 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
996 dst_x = FX + x2 * TILEX;
997 dst_y = FY + y2 * TILEY;
999 if (mask_mode == USE_MASKING)
1001 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1002 dst_x - src_x, dst_y - src_y);
1003 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1007 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1010 MarkTileDirty(x2, y2);
1014 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1015 int graphic, int frame,
1016 int cut_mode, int mask_mode)
1020 DrawGraphic(x, y, graphic, frame);
1025 if (graphic_info[graphic].double_movement) /* EM style movement images */
1026 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1028 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1031 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1032 int frame, int cut_mode)
1034 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1037 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1038 int cut_mode, int mask_mode)
1040 int lx = LEVELX(x), ly = LEVELY(y);
1044 if (IN_LEV_FIELD(lx, ly))
1046 SetRandomAnimationValue(lx, ly);
1048 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1049 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1051 /* do not use double (EM style) movement graphic when not moving */
1052 if (graphic_info[graphic].double_movement && !dx && !dy)
1054 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1055 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1058 else /* border element */
1060 graphic = el2img(element);
1061 frame = getGraphicAnimationFrame(graphic, -1);
1064 if (element == EL_EXPANDABLE_WALL)
1066 boolean left_stopped = FALSE, right_stopped = FALSE;
1068 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1069 left_stopped = TRUE;
1070 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1071 right_stopped = TRUE;
1073 if (left_stopped && right_stopped)
1075 else if (left_stopped)
1077 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1078 frame = graphic_info[graphic].anim_frames - 1;
1080 else if (right_stopped)
1082 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1083 frame = graphic_info[graphic].anim_frames - 1;
1088 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1089 else if (mask_mode == USE_MASKING)
1090 DrawGraphicThruMask(x, y, graphic, frame);
1092 DrawGraphic(x, y, graphic, frame);
1095 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1096 int cut_mode, int mask_mode)
1098 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1099 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1100 cut_mode, mask_mode);
1103 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1106 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1109 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1112 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1115 void DrawLevelElementThruMask(int x, int y, int element)
1117 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1120 void DrawLevelFieldThruMask(int x, int y)
1122 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1125 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1129 int sx = SCREENX(x), sy = SCREENY(y);
1131 int width, height, cx, cy, i;
1132 int crumbled_border_size = graphic_info[graphic].border_size;
1133 static int xy[4][2] =
1141 if (!IN_LEV_FIELD(x, y))
1144 element = TILE_GFX_ELEMENT(x, y);
1146 /* crumble field itself */
1147 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1149 if (!IN_SCR_FIELD(sx, sy))
1152 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1154 for (i = 0; i < 4; i++)
1156 int xx = x + xy[i][0];
1157 int yy = y + xy[i][1];
1159 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1162 /* check if neighbour field is of same type */
1163 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1166 if (i == 1 || i == 2)
1168 width = crumbled_border_size;
1170 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1176 height = crumbled_border_size;
1178 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1181 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1182 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1185 MarkTileDirty(sx, sy);
1187 else /* crumble neighbour fields */
1189 for (i = 0; i < 4; i++)
1191 int xx = x + xy[i][0];
1192 int yy = y + xy[i][1];
1193 int sxx = sx + xy[i][0];
1194 int syy = sy + xy[i][1];
1196 if (!IN_LEV_FIELD(xx, yy) ||
1197 !IN_SCR_FIELD(sxx, syy) ||
1201 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1204 element = TILE_GFX_ELEMENT(xx, yy);
1206 if (!GFX_CRUMBLED(element))
1209 graphic = el_act2crm(element, ACTION_DEFAULT);
1210 crumbled_border_size = graphic_info[graphic].border_size;
1212 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1214 if (i == 1 || i == 2)
1216 width = crumbled_border_size;
1218 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1224 height = crumbled_border_size;
1226 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1229 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1230 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1232 MarkTileDirty(sxx, syy);
1237 void DrawLevelFieldCrumbledSand(int x, int y)
1241 if (!IN_LEV_FIELD(x, y))
1245 /* !!! CHECK THIS !!! */
1248 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1249 GFX_CRUMBLED(GfxElement[x][y]))
1252 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1253 GfxElement[x][y] != EL_UNDEFINED &&
1254 GFX_CRUMBLED(GfxElement[x][y]))
1256 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1263 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1265 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1268 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1271 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1274 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1275 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1276 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1277 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1278 int sx = SCREENX(x), sy = SCREENY(y);
1280 DrawGraphic(sx, sy, graphic1, frame1);
1281 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1284 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1286 int sx = SCREENX(x), sy = SCREENY(y);
1287 static int xy[4][2] =
1296 for (i = 0; i < 4; i++)
1298 int xx = x + xy[i][0];
1299 int yy = y + xy[i][1];
1300 int sxx = sx + xy[i][0];
1301 int syy = sy + xy[i][1];
1303 if (!IN_LEV_FIELD(xx, yy) ||
1304 !IN_SCR_FIELD(sxx, syy) ||
1305 !GFX_CRUMBLED(Feld[xx][yy]) ||
1309 DrawLevelField(xx, yy);
1313 static int getBorderElement(int x, int y)
1317 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1318 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1319 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1320 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1321 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1322 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1323 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1325 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1326 int steel_position = (x == -1 && y == -1 ? 0 :
1327 x == lev_fieldx && y == -1 ? 1 :
1328 x == -1 && y == lev_fieldy ? 2 :
1329 x == lev_fieldx && y == lev_fieldy ? 3 :
1330 x == -1 || x == lev_fieldx ? 4 :
1331 y == -1 || y == lev_fieldy ? 5 : 6);
1333 return border[steel_position][steel_type];
1336 void DrawScreenElement(int x, int y, int element)
1338 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1339 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1342 void DrawLevelElement(int x, int y, int element)
1344 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1345 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1348 void DrawScreenField(int x, int y)
1350 int lx = LEVELX(x), ly = LEVELY(y);
1351 int element, content;
1353 if (!IN_LEV_FIELD(lx, ly))
1355 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1358 element = getBorderElement(lx, ly);
1360 DrawScreenElement(x, y, element);
1364 element = Feld[lx][ly];
1365 content = Store[lx][ly];
1367 if (IS_MOVING(lx, ly))
1369 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1370 boolean cut_mode = NO_CUTTING;
1372 if (element == EL_QUICKSAND_EMPTYING ||
1373 element == EL_MAGIC_WALL_EMPTYING ||
1374 element == EL_BD_MAGIC_WALL_EMPTYING ||
1375 element == EL_AMOEBA_DROPPING)
1376 cut_mode = CUT_ABOVE;
1377 else if (element == EL_QUICKSAND_FILLING ||
1378 element == EL_MAGIC_WALL_FILLING ||
1379 element == EL_BD_MAGIC_WALL_FILLING)
1380 cut_mode = CUT_BELOW;
1382 if (cut_mode == CUT_ABOVE)
1383 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1385 DrawScreenElement(x, y, EL_EMPTY);
1388 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1389 else if (cut_mode == NO_CUTTING)
1390 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1392 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1394 if (content == EL_ACID)
1396 int dir = MovDir[lx][ly];
1397 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1398 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1400 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1403 else if (IS_BLOCKED(lx, ly))
1408 boolean cut_mode = NO_CUTTING;
1409 int element_old, content_old;
1411 Blocked2Moving(lx, ly, &oldx, &oldy);
1414 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1415 MovDir[oldx][oldy] == MV_RIGHT);
1417 element_old = Feld[oldx][oldy];
1418 content_old = Store[oldx][oldy];
1420 if (element_old == EL_QUICKSAND_EMPTYING ||
1421 element_old == EL_MAGIC_WALL_EMPTYING ||
1422 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1423 element_old == EL_AMOEBA_DROPPING)
1424 cut_mode = CUT_ABOVE;
1426 DrawScreenElement(x, y, EL_EMPTY);
1429 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1431 else if (cut_mode == NO_CUTTING)
1432 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1435 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1438 else if (IS_DRAWABLE(element))
1439 DrawScreenElement(x, y, element);
1441 DrawScreenElement(x, y, EL_EMPTY);
1444 void DrawLevelField(int x, int y)
1446 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1447 DrawScreenField(SCREENX(x), SCREENY(y));
1448 else if (IS_MOVING(x, y))
1452 Moving2Blocked(x, y, &newx, &newy);
1453 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1454 DrawScreenField(SCREENX(newx), SCREENY(newy));
1456 else if (IS_BLOCKED(x, y))
1460 Blocked2Moving(x, y, &oldx, &oldy);
1461 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1462 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1466 void DrawMiniElement(int x, int y, int element)
1470 graphic = el2edimg(element);
1471 DrawMiniGraphic(x, y, graphic);
1474 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1476 int x = sx + scroll_x, y = sy + scroll_y;
1478 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1479 DrawMiniElement(sx, sy, EL_EMPTY);
1480 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1481 DrawMiniElement(sx, sy, Feld[x][y]);
1483 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1486 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1487 int x, int y, int xsize, int ysize, int font_nr)
1489 int font_width = getFontWidth(font_nr);
1490 int font_height = getFontHeight(font_nr);
1491 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1494 int dst_x = SX + startx + x * font_width;
1495 int dst_y = SY + starty + y * font_height;
1496 int width = graphic_info[graphic].width;
1497 int height = graphic_info[graphic].height;
1498 int inner_width = MAX(width - 2 * font_width, font_width);
1499 int inner_height = MAX(height - 2 * font_height, font_height);
1500 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1501 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1502 boolean draw_masked = graphic_info[graphic].draw_masked;
1504 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1506 if (src_bitmap == NULL || width < font_width || height < font_height)
1508 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1512 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1513 inner_sx + (x - 1) * font_width % inner_width);
1514 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1515 inner_sy + (y - 1) * font_height % inner_height);
1519 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1520 dst_x - src_x, dst_y - src_y);
1521 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1525 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1529 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1531 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1532 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1533 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1534 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1535 boolean no_delay = (tape.warp_forward);
1536 unsigned long anim_delay = 0;
1537 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1538 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1539 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1540 int font_width = getFontWidth(font_nr);
1541 int font_height = getFontHeight(font_nr);
1542 int max_xsize = level.envelope[envelope_nr].xsize;
1543 int max_ysize = level.envelope[envelope_nr].ysize;
1544 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1545 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1546 int xend = max_xsize;
1547 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1548 int xstep = (xstart < xend ? 1 : 0);
1549 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1552 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1554 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1555 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1556 int sx = (SXSIZE - xsize * font_width) / 2;
1557 int sy = (SYSIZE - ysize * font_height) / 2;
1560 SetDrawtoField(DRAW_BUFFERED);
1562 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1564 SetDrawtoField(DRAW_BACKBUFFER);
1566 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1567 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1569 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1570 level.envelope[envelope_nr].text, font_nr, max_xsize,
1571 xsize - 2, ysize - 2, mask_mode);
1573 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1576 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1580 void ShowEnvelope(int envelope_nr)
1582 int element = EL_ENVELOPE_1 + envelope_nr;
1583 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1584 int sound_opening = element_info[element].sound[ACTION_OPENING];
1585 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1586 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1587 boolean no_delay = (tape.warp_forward);
1588 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1589 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1590 int anim_mode = graphic_info[graphic].anim_mode;
1591 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1592 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1594 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1596 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1598 if (anim_mode == ANIM_DEFAULT)
1599 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1601 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1604 Delay(wait_delay_value);
1606 WaitForEventToContinue();
1608 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1610 if (anim_mode != ANIM_NONE)
1611 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1613 if (anim_mode == ANIM_DEFAULT)
1614 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1616 game.envelope_active = FALSE;
1618 SetDrawtoField(DRAW_BUFFERED);
1620 redraw_mask |= REDRAW_FIELD;
1624 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1629 int width_mult, width_div;
1630 int height_mult, height_div;
1638 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1639 5 - log_2(tilesize));
1640 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1641 int width_mult = offset_calc[offset_calc_pos].width_mult;
1642 int width_div = offset_calc[offset_calc_pos].width_div;
1643 int height_mult = offset_calc[offset_calc_pos].height_mult;
1644 int height_div = offset_calc[offset_calc_pos].height_div;
1645 int mini_startx = src_bitmap->width * width_mult / width_div;
1646 int mini_starty = src_bitmap->height * height_mult / height_div;
1647 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1648 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1650 *bitmap = src_bitmap;
1655 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1659 int graphic = el2preimg(element);
1661 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1662 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1669 SetDrawBackgroundMask(REDRAW_NONE);
1672 for (x = BX1; x <= BX2; x++)
1673 for (y = BY1; y <= BY2; y++)
1674 DrawScreenField(x, y);
1676 redraw_mask |= REDRAW_FIELD;
1679 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1683 for (x = 0; x < size_x; x++)
1684 for (y = 0; y < size_y; y++)
1685 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1687 redraw_mask |= REDRAW_FIELD;
1690 static void DrawPreviewLevelExt(int from_x, int from_y)
1692 boolean show_level_border = (BorderElement != EL_EMPTY);
1693 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1694 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1695 int tile_size = preview.tile_size;
1696 int preview_width = preview.xsize * tile_size;
1697 int preview_height = preview.ysize * tile_size;
1698 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1699 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1700 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1701 int dst_y = SY + preview.y;
1704 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1706 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1707 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1709 for (x = 0; x < real_preview_xsize; x++)
1711 for (y = 0; y < real_preview_ysize; y++)
1713 int lx = from_x + x + (show_level_border ? -1 : 0);
1714 int ly = from_y + y + (show_level_border ? -1 : 0);
1715 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1716 getBorderElement(lx, ly));
1718 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1719 element, tile_size);
1723 redraw_mask |= REDRAW_MICROLEVEL;
1726 #define MICROLABEL_EMPTY 0
1727 #define MICROLABEL_LEVEL_NAME 1
1728 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1729 #define MICROLABEL_LEVEL_AUTHOR 3
1730 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1731 #define MICROLABEL_IMPORTED_FROM 5
1732 #define MICROLABEL_IMPORTED_BY_HEAD 6
1733 #define MICROLABEL_IMPORTED_BY 7
1735 static int getMaxTextLength(struct MenuPosInfo *pos, int font_nr)
1737 int max_text_width = SXSIZE;
1738 int font_width = getFontWidth(font_nr);
1740 if (pos->align == ALIGN_CENTER)
1741 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1742 else if (pos->align == ALIGN_RIGHT)
1743 max_text_width = pos->x;
1745 max_text_width = SXSIZE - pos->x;
1747 return max_text_width / font_width;
1750 static void DrawPreviewLevelLabelExt(int mode)
1752 struct MenuPosInfo *pos = &menu.main.text.level_info_2;
1753 char label_text[MAX_OUTPUT_LINESIZE + 1];
1754 int max_len_label_text;
1755 int font_nr = FONT_TEXT_2;
1758 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1759 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1760 mode == MICROLABEL_IMPORTED_BY_HEAD)
1761 font_nr = FONT_TEXT_3;
1764 max_len_label_text = getMaxTextLength(pos, font_nr);
1766 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1769 for (i = 0; i < max_len_label_text; i++)
1770 label_text[i] = ' ';
1771 label_text[max_len_label_text] = '\0';
1773 if (strlen(label_text) > 0)
1776 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1778 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1779 int lypos = MICROLABEL2_YPOS;
1781 DrawText(lxpos, lypos, label_text, font_nr);
1786 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1787 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1788 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1789 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1790 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1791 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1792 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1793 max_len_label_text);
1794 label_text[max_len_label_text] = '\0';
1796 if (strlen(label_text) > 0)
1799 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1801 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1802 int lypos = MICROLABEL2_YPOS;
1804 DrawText(lxpos, lypos, label_text, font_nr);
1808 redraw_mask |= REDRAW_MICROLEVEL;
1811 void DrawPreviewLevel(boolean restart)
1813 static unsigned long scroll_delay = 0;
1814 static unsigned long label_delay = 0;
1815 static int from_x, from_y, scroll_direction;
1816 static int label_state, label_counter;
1817 unsigned long scroll_delay_value = preview.step_delay;
1818 boolean show_level_border = (BorderElement != EL_EMPTY);
1819 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1820 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1821 int last_game_status = game_status; /* save current game status */
1823 /* force PREVIEW font on preview level */
1824 game_status = GAME_MODE_PSEUDO_PREVIEW;
1831 if (preview.anim_mode == ANIM_CENTERED)
1833 if (level_xsize > preview.xsize)
1834 from_x = (level_xsize - preview.xsize) / 2;
1835 if (level_ysize > preview.ysize)
1836 from_y = (level_ysize - preview.ysize) / 2;
1839 from_x += preview.xoffset;
1840 from_y += preview.yoffset;
1842 scroll_direction = MV_RIGHT;
1846 DrawPreviewLevelExt(from_x, from_y);
1847 DrawPreviewLevelLabelExt(label_state);
1849 /* initialize delay counters */
1850 DelayReached(&scroll_delay, 0);
1851 DelayReached(&label_delay, 0);
1853 if (leveldir_current->name)
1855 struct MenuPosInfo *pos = &menu.main.text.level_info_1;
1856 char label_text[MAX_OUTPUT_LINESIZE + 1];
1857 int font_nr = FONT_TEXT_1;
1859 int max_len_label_text = getMaxTextLength(pos, font_nr);
1861 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1868 strncpy(label_text, leveldir_current->name, max_len_label_text);
1869 label_text[max_len_label_text] = '\0';
1872 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1874 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1875 lypos = SY + MICROLABEL1_YPOS;
1877 DrawText(lxpos, lypos, label_text, font_nr);
1881 game_status = last_game_status; /* restore current game status */
1886 /* scroll preview level, if needed */
1887 if (preview.anim_mode != ANIM_NONE &&
1888 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1889 DelayReached(&scroll_delay, scroll_delay_value))
1891 switch (scroll_direction)
1896 from_x -= preview.step_offset;
1897 from_x = (from_x < 0 ? 0 : from_x);
1900 scroll_direction = MV_UP;
1904 if (from_x < level_xsize - preview.xsize)
1906 from_x += preview.step_offset;
1907 from_x = (from_x > level_xsize - preview.xsize ?
1908 level_xsize - preview.xsize : from_x);
1911 scroll_direction = MV_DOWN;
1917 from_y -= preview.step_offset;
1918 from_y = (from_y < 0 ? 0 : from_y);
1921 scroll_direction = MV_RIGHT;
1925 if (from_y < level_ysize - preview.ysize)
1927 from_y += preview.step_offset;
1928 from_y = (from_y > level_ysize - preview.ysize ?
1929 level_ysize - preview.ysize : from_y);
1932 scroll_direction = MV_LEFT;
1939 DrawPreviewLevelExt(from_x, from_y);
1942 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1943 /* redraw micro level label, if needed */
1944 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1945 !strEqual(level.author, ANONYMOUS_NAME) &&
1946 !strEqual(level.author, leveldir_current->name) &&
1947 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1949 int max_label_counter = 23;
1951 if (leveldir_current->imported_from != NULL &&
1952 strlen(leveldir_current->imported_from) > 0)
1953 max_label_counter += 14;
1954 if (leveldir_current->imported_by != NULL &&
1955 strlen(leveldir_current->imported_by) > 0)
1956 max_label_counter += 14;
1958 label_counter = (label_counter + 1) % max_label_counter;
1959 label_state = (label_counter >= 0 && label_counter <= 7 ?
1960 MICROLABEL_LEVEL_NAME :
1961 label_counter >= 9 && label_counter <= 12 ?
1962 MICROLABEL_LEVEL_AUTHOR_HEAD :
1963 label_counter >= 14 && label_counter <= 21 ?
1964 MICROLABEL_LEVEL_AUTHOR :
1965 label_counter >= 23 && label_counter <= 26 ?
1966 MICROLABEL_IMPORTED_FROM_HEAD :
1967 label_counter >= 28 && label_counter <= 35 ?
1968 MICROLABEL_IMPORTED_FROM :
1969 label_counter >= 37 && label_counter <= 40 ?
1970 MICROLABEL_IMPORTED_BY_HEAD :
1971 label_counter >= 42 && label_counter <= 49 ?
1972 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1974 if (leveldir_current->imported_from == NULL &&
1975 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1976 label_state == MICROLABEL_IMPORTED_FROM))
1977 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1978 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1980 DrawPreviewLevelLabelExt(label_state);
1983 game_status = last_game_status; /* restore current game status */
1986 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1987 int graphic, int sync_frame, int mask_mode)
1989 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1991 if (mask_mode == USE_MASKING)
1992 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1994 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1997 inline void DrawGraphicAnimation(int x, int y, int graphic)
1999 int lx = LEVELX(x), ly = LEVELY(y);
2001 if (!IN_SCR_FIELD(x, y))
2004 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2005 graphic, GfxFrame[lx][ly], NO_MASKING);
2006 MarkTileDirty(x, y);
2009 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2011 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2014 void DrawLevelElementAnimation(int x, int y, int element)
2016 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2018 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2021 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2023 int sx = SCREENX(x), sy = SCREENY(y);
2025 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2028 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2031 DrawGraphicAnimation(sx, sy, graphic);
2034 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2035 DrawLevelFieldCrumbledSand(x, y);
2037 if (GFX_CRUMBLED(Feld[x][y]))
2038 DrawLevelFieldCrumbledSand(x, y);
2042 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2044 int sx = SCREENX(x), sy = SCREENY(y);
2047 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2050 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2052 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2055 DrawGraphicAnimation(sx, sy, graphic);
2057 if (GFX_CRUMBLED(element))
2058 DrawLevelFieldCrumbledSand(x, y);
2061 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2063 if (player->use_murphy)
2065 /* this works only because currently only one player can be "murphy" ... */
2066 static int last_horizontal_dir = MV_LEFT;
2067 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2069 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2070 last_horizontal_dir = move_dir;
2072 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2074 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2076 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2082 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2085 static boolean equalGraphics(int graphic1, int graphic2)
2087 struct GraphicInfo *g1 = &graphic_info[graphic1];
2088 struct GraphicInfo *g2 = &graphic_info[graphic2];
2090 return (g1->bitmap == g2->bitmap &&
2091 g1->src_x == g2->src_x &&
2092 g1->src_y == g2->src_y &&
2093 g1->anim_frames == g2->anim_frames &&
2094 g1->anim_delay == g2->anim_delay &&
2095 g1->anim_mode == g2->anim_mode);
2098 void DrawAllPlayers()
2102 for (i = 0; i < MAX_PLAYERS; i++)
2103 if (stored_player[i].active)
2104 DrawPlayer(&stored_player[i]);
2107 void DrawPlayerField(int x, int y)
2109 if (!IS_PLAYER(x, y))
2112 DrawPlayer(PLAYERINFO(x, y));
2115 void DrawPlayer(struct PlayerInfo *player)
2117 int jx = player->jx;
2118 int jy = player->jy;
2119 int move_dir = player->MovDir;
2120 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2121 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2122 int last_jx = (player->is_moving ? jx - dx : jx);
2123 int last_jy = (player->is_moving ? jy - dy : jy);
2124 int next_jx = jx + dx;
2125 int next_jy = jy + dy;
2126 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2127 boolean player_is_opaque = FALSE;
2128 int sx = SCREENX(jx), sy = SCREENY(jy);
2129 int sxx = 0, syy = 0;
2130 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2132 int action = ACTION_DEFAULT;
2133 int last_player_graphic = getPlayerGraphic(player, move_dir);
2134 int last_player_frame = player->Frame;
2137 /* GfxElement[][] is set to the element the player is digging or collecting;
2138 remove also for off-screen player if the player is not moving anymore */
2139 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2140 GfxElement[jx][jy] = EL_UNDEFINED;
2142 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2146 if (!IN_LEV_FIELD(jx, jy))
2148 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2149 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2150 printf("DrawPlayerField(): This should never happen!\n");
2155 if (element == EL_EXPLOSION)
2158 action = (player->is_pushing ? ACTION_PUSHING :
2159 player->is_digging ? ACTION_DIGGING :
2160 player->is_collecting ? ACTION_COLLECTING :
2161 player->is_moving ? ACTION_MOVING :
2162 player->is_snapping ? ACTION_SNAPPING :
2163 player->is_dropping ? ACTION_DROPPING :
2164 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2166 if (player->is_waiting)
2167 move_dir = player->dir_waiting;
2169 InitPlayerGfxAnimation(player, action, move_dir);
2171 /* ----------------------------------------------------------------------- */
2172 /* draw things in the field the player is leaving, if needed */
2173 /* ----------------------------------------------------------------------- */
2175 if (player->is_moving)
2177 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2179 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2181 if (last_element == EL_DYNAMITE_ACTIVE ||
2182 last_element == EL_EM_DYNAMITE_ACTIVE ||
2183 last_element == EL_SP_DISK_RED_ACTIVE)
2184 DrawDynamite(last_jx, last_jy);
2186 DrawLevelFieldThruMask(last_jx, last_jy);
2188 else if (last_element == EL_DYNAMITE_ACTIVE ||
2189 last_element == EL_EM_DYNAMITE_ACTIVE ||
2190 last_element == EL_SP_DISK_RED_ACTIVE)
2191 DrawDynamite(last_jx, last_jy);
2193 /* !!! this is not enough to prevent flickering of players which are
2194 moving next to each others without a free tile between them -- this
2195 can only be solved by drawing all players layer by layer (first the
2196 background, then the foreground etc.) !!! => TODO */
2197 else if (!IS_PLAYER(last_jx, last_jy))
2198 DrawLevelField(last_jx, last_jy);
2201 DrawLevelField(last_jx, last_jy);
2204 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2205 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2208 if (!IN_SCR_FIELD(sx, sy))
2211 if (setup.direct_draw)
2212 SetDrawtoField(DRAW_BUFFERED);
2214 /* ----------------------------------------------------------------------- */
2215 /* draw things behind the player, if needed */
2216 /* ----------------------------------------------------------------------- */
2219 DrawLevelElement(jx, jy, Back[jx][jy]);
2220 else if (IS_ACTIVE_BOMB(element))
2221 DrawLevelElement(jx, jy, EL_EMPTY);
2224 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2226 int old_element = GfxElement[jx][jy];
2227 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2228 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2230 if (GFX_CRUMBLED(old_element))
2231 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2233 DrawGraphic(sx, sy, old_graphic, frame);
2235 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2236 player_is_opaque = TRUE;
2240 GfxElement[jx][jy] = EL_UNDEFINED;
2242 /* make sure that pushed elements are drawn with correct frame rate */
2244 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2246 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2247 GfxFrame[jx][jy] = player->StepFrame;
2249 if (player->is_pushing && player->is_moving)
2250 GfxFrame[jx][jy] = player->StepFrame;
2253 DrawLevelField(jx, jy);
2257 /* ----------------------------------------------------------------------- */
2258 /* draw player himself */
2259 /* ----------------------------------------------------------------------- */
2261 graphic = getPlayerGraphic(player, move_dir);
2263 /* in the case of changed player action or direction, prevent the current
2264 animation frame from being restarted for identical animations */
2265 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2266 player->Frame = last_player_frame;
2268 frame = getGraphicAnimationFrame(graphic, player->Frame);
2272 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2273 sxx = player->GfxPos;
2275 syy = player->GfxPos;
2278 if (!setup.soft_scrolling && ScreenMovPos)
2281 if (player_is_opaque)
2282 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2284 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2286 if (SHIELD_ON(player))
2288 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2289 IMG_SHIELD_NORMAL_ACTIVE);
2290 int frame = getGraphicAnimationFrame(graphic, -1);
2292 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2295 /* ----------------------------------------------------------------------- */
2296 /* draw things the player is pushing, if needed */
2297 /* ----------------------------------------------------------------------- */
2300 printf("::: %d, %d [%d, %d] [%d]\n",
2301 player->is_pushing, player_is_moving, player->GfxAction,
2302 player->is_moving, player_is_moving);
2306 if (player->is_pushing && player->is_moving)
2308 int px = SCREENX(jx), py = SCREENY(jy);
2309 int pxx = (TILEX - ABS(sxx)) * dx;
2310 int pyy = (TILEY - ABS(syy)) * dy;
2311 int gfx_frame = GfxFrame[jx][jy];
2317 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2319 element = Feld[next_jx][next_jy];
2320 gfx_frame = GfxFrame[next_jx][next_jy];
2323 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2326 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2327 frame = getGraphicAnimationFrame(graphic, sync_frame);
2329 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2332 /* draw background element under pushed element (like the Sokoban field) */
2333 if (Back[next_jx][next_jy])
2334 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2336 /* masked drawing is needed for EMC style (double) movement graphics */
2337 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2341 /* ----------------------------------------------------------------------- */
2342 /* draw things in front of player (active dynamite or dynabombs) */
2343 /* ----------------------------------------------------------------------- */
2345 if (IS_ACTIVE_BOMB(element))
2347 graphic = el2img(element);
2348 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2350 if (game.emulation == EMU_SUPAPLEX)
2351 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2353 DrawGraphicThruMask(sx, sy, graphic, frame);
2356 if (player_is_moving && last_element == EL_EXPLOSION)
2358 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2359 GfxElement[last_jx][last_jy] : EL_EMPTY);
2360 int graphic = el_act2img(element, ACTION_EXPLODING);
2361 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2362 int phase = ExplodePhase[last_jx][last_jy] - 1;
2363 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2366 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2369 /* ----------------------------------------------------------------------- */
2370 /* draw elements the player is just walking/passing through/under */
2371 /* ----------------------------------------------------------------------- */
2373 if (player_is_moving)
2375 /* handle the field the player is leaving ... */
2376 if (IS_ACCESSIBLE_INSIDE(last_element))
2377 DrawLevelField(last_jx, last_jy);
2378 else if (IS_ACCESSIBLE_UNDER(last_element))
2379 DrawLevelFieldThruMask(last_jx, last_jy);
2382 /* do not redraw accessible elements if the player is just pushing them */
2383 if (!player_is_moving || !player->is_pushing)
2385 /* ... and the field the player is entering */
2386 if (IS_ACCESSIBLE_INSIDE(element))
2387 DrawLevelField(jx, jy);
2388 else if (IS_ACCESSIBLE_UNDER(element))
2389 DrawLevelFieldThruMask(jx, jy);
2392 if (setup.direct_draw)
2394 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2395 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2396 int x_size = TILEX * (1 + ABS(jx - last_jx));
2397 int y_size = TILEY * (1 + ABS(jy - last_jy));
2399 BlitBitmap(drawto_field, window,
2400 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2401 SetDrawtoField(DRAW_DIRECT);
2404 MarkTileDirty(sx, sy);
2407 /* ------------------------------------------------------------------------- */
2409 void WaitForEventToContinue()
2411 boolean still_wait = TRUE;
2413 /* simulate releasing mouse button over last gadget, if still pressed */
2415 HandleGadgets(-1, -1, 0);
2417 button_status = MB_RELEASED;
2433 case EVENT_BUTTONPRESS:
2434 case EVENT_KEYPRESS:
2438 case EVENT_KEYRELEASE:
2439 ClearPlayerAction();
2443 HandleOtherEvents(&event);
2447 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2454 /* don't eat all CPU time */
2459 #define MAX_REQUEST_LINES 13
2460 #define MAX_REQUEST_LINE_FONT1_LEN 7
2461 #define MAX_REQUEST_LINE_FONT2_LEN 10
2463 boolean Request(char *text, unsigned int req_state)
2465 int mx, my, ty, result = -1;
2466 unsigned int old_door_state;
2467 int last_game_status = game_status; /* save current game status */
2468 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2469 int font_nr = FONT_TEXT_2;
2470 int max_word_len = 0;
2473 for (text_ptr = text; *text_ptr; text_ptr++)
2475 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2477 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2479 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2480 font_nr = FONT_LEVEL_NUMBER;
2486 if (game_status == GAME_MODE_PLAYING &&
2487 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2488 BlitScreenToBitmap_EM(backbuffer);
2490 /* disable deactivated drawing when quick-loading level tape recording */
2491 if (tape.playing && tape.deactivate_display)
2492 TapeDeactivateDisplayOff(TRUE);
2494 SetMouseCursor(CURSOR_DEFAULT);
2496 #if defined(NETWORK_AVALIABLE)
2497 /* pause network game while waiting for request to answer */
2498 if (options.network &&
2499 game_status == GAME_MODE_PLAYING &&
2500 req_state & REQUEST_WAIT_FOR_INPUT)
2501 SendToServer_PausePlaying();
2504 old_door_state = GetDoorState();
2506 /* simulate releasing mouse button over last gadget, if still pressed */
2508 HandleGadgets(-1, -1, 0);
2512 if (old_door_state & DOOR_OPEN_1)
2514 CloseDoor(DOOR_CLOSE_1);
2516 /* save old door content */
2517 BlitBitmap(bitmap_db_door, bitmap_db_door,
2518 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2519 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2523 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2526 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2528 /* clear door drawing field */
2529 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2531 /* force DOOR font on preview level */
2532 game_status = GAME_MODE_PSEUDO_DOOR;
2534 /* write text for request */
2535 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2537 char text_line[max_request_line_len + 1];
2543 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2546 if (!tc || tc == ' ')
2557 strncpy(text_line, text, tl);
2560 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2561 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2562 text_line, font_nr);
2564 text += tl + (tc == ' ' ? 1 : 0);
2567 game_status = last_game_status; /* restore current game status */
2569 if (req_state & REQ_ASK)
2571 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2572 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2574 else if (req_state & REQ_CONFIRM)
2576 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2578 else if (req_state & REQ_PLAYER)
2580 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2581 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2582 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2583 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2586 /* copy request gadgets to door backbuffer */
2587 BlitBitmap(drawto, bitmap_db_door,
2588 DX, DY, DXSIZE, DYSIZE,
2589 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2591 OpenDoor(DOOR_OPEN_1);
2593 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2595 if (game_status == GAME_MODE_PLAYING)
2597 SetPanelBackground();
2598 SetDrawBackgroundMask(REDRAW_DOOR_1);
2602 SetDrawBackgroundMask(REDRAW_FIELD);
2608 if (game_status != GAME_MODE_MAIN)
2611 button_status = MB_RELEASED;
2613 request_gadget_id = -1;
2615 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2627 case EVENT_BUTTONPRESS:
2628 case EVENT_BUTTONRELEASE:
2629 case EVENT_MOTIONNOTIFY:
2631 if (event.type == EVENT_MOTIONNOTIFY)
2633 if (!PointerInWindow(window))
2634 continue; /* window and pointer are on different screens */
2639 motion_status = TRUE;
2640 mx = ((MotionEvent *) &event)->x;
2641 my = ((MotionEvent *) &event)->y;
2645 motion_status = FALSE;
2646 mx = ((ButtonEvent *) &event)->x;
2647 my = ((ButtonEvent *) &event)->y;
2648 if (event.type == EVENT_BUTTONPRESS)
2649 button_status = ((ButtonEvent *) &event)->button;
2651 button_status = MB_RELEASED;
2654 /* this sets 'request_gadget_id' */
2655 HandleGadgets(mx, my, button_status);
2657 switch (request_gadget_id)
2659 case TOOL_CTRL_ID_YES:
2662 case TOOL_CTRL_ID_NO:
2665 case TOOL_CTRL_ID_CONFIRM:
2666 result = TRUE | FALSE;
2669 case TOOL_CTRL_ID_PLAYER_1:
2672 case TOOL_CTRL_ID_PLAYER_2:
2675 case TOOL_CTRL_ID_PLAYER_3:
2678 case TOOL_CTRL_ID_PLAYER_4:
2689 case EVENT_KEYPRESS:
2690 switch (GetEventKey((KeyEvent *)&event, TRUE))
2703 if (req_state & REQ_PLAYER)
2707 case EVENT_KEYRELEASE:
2708 ClearPlayerAction();
2712 HandleOtherEvents(&event);
2716 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2718 int joy = AnyJoystick();
2720 if (joy & JOY_BUTTON_1)
2722 else if (joy & JOY_BUTTON_2)
2729 if (!PendingEvent()) /* delay only if no pending events */
2732 /* don't eat all CPU time */
2737 if (game_status != GAME_MODE_MAIN)
2742 if (!(req_state & REQ_STAY_OPEN))
2744 CloseDoor(DOOR_CLOSE_1);
2746 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2747 (req_state & REQ_REOPEN))
2748 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2753 if (game_status == GAME_MODE_PLAYING)
2755 SetPanelBackground();
2756 SetDrawBackgroundMask(REDRAW_DOOR_1);
2760 SetDrawBackgroundMask(REDRAW_FIELD);
2763 #if defined(NETWORK_AVALIABLE)
2764 /* continue network game after request */
2765 if (options.network &&
2766 game_status == GAME_MODE_PLAYING &&
2767 req_state & REQUEST_WAIT_FOR_INPUT)
2768 SendToServer_ContinuePlaying();
2771 /* restore deactivated drawing when quick-loading level tape recording */
2772 if (tape.playing && tape.deactivate_display)
2773 TapeDeactivateDisplayOn();
2778 unsigned int OpenDoor(unsigned int door_state)
2780 if (door_state & DOOR_COPY_BACK)
2782 if (door_state & DOOR_OPEN_1)
2783 BlitBitmap(bitmap_db_door, bitmap_db_door,
2784 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2785 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2787 if (door_state & DOOR_OPEN_2)
2788 BlitBitmap(bitmap_db_door, bitmap_db_door,
2789 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2790 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2792 door_state &= ~DOOR_COPY_BACK;
2795 return MoveDoor(door_state);
2798 unsigned int CloseDoor(unsigned int door_state)
2800 unsigned int old_door_state = GetDoorState();
2802 if (!(door_state & DOOR_NO_COPY_BACK))
2804 if (old_door_state & DOOR_OPEN_1)
2805 BlitBitmap(backbuffer, bitmap_db_door,
2806 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2808 if (old_door_state & DOOR_OPEN_2)
2809 BlitBitmap(backbuffer, bitmap_db_door,
2810 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2812 door_state &= ~DOOR_NO_COPY_BACK;
2815 return MoveDoor(door_state);
2818 unsigned int GetDoorState()
2820 return MoveDoor(DOOR_GET_STATE);
2823 unsigned int SetDoorState(unsigned int door_state)
2825 return MoveDoor(door_state | DOOR_SET_STATE);
2828 unsigned int MoveDoor(unsigned int door_state)
2830 static int door1 = DOOR_OPEN_1;
2831 static int door2 = DOOR_CLOSE_2;
2832 unsigned long door_delay = 0;
2833 unsigned long door_delay_value;
2836 if (door_1.width < 0 || door_1.width > DXSIZE)
2837 door_1.width = DXSIZE;
2838 if (door_1.height < 0 || door_1.height > DYSIZE)
2839 door_1.height = DYSIZE;
2840 if (door_2.width < 0 || door_2.width > VXSIZE)
2841 door_2.width = VXSIZE;
2842 if (door_2.height < 0 || door_2.height > VYSIZE)
2843 door_2.height = VYSIZE;
2845 if (door_state == DOOR_GET_STATE)
2846 return (door1 | door2);
2848 if (door_state & DOOR_SET_STATE)
2850 if (door_state & DOOR_ACTION_1)
2851 door1 = door_state & DOOR_ACTION_1;
2852 if (door_state & DOOR_ACTION_2)
2853 door2 = door_state & DOOR_ACTION_2;
2855 return (door1 | door2);
2858 if (!(door_state & DOOR_FORCE_REDRAW))
2860 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2861 door_state &= ~DOOR_OPEN_1;
2862 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2863 door_state &= ~DOOR_CLOSE_1;
2864 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2865 door_state &= ~DOOR_OPEN_2;
2866 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2867 door_state &= ~DOOR_CLOSE_2;
2870 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2873 if (setup.quick_doors)
2875 stepsize = 20; /* must be choosen to always draw last frame */
2876 door_delay_value = 0;
2879 if (global.autoplay_leveldir)
2881 door_state |= DOOR_NO_DELAY;
2882 door_state &= ~DOOR_CLOSE_ALL;
2885 if (door_state & DOOR_ACTION)
2887 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2888 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2889 boolean door_1_done = (!handle_door_1);
2890 boolean door_2_done = (!handle_door_2);
2891 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2892 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2893 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2894 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2895 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2896 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2897 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2898 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2899 int door_skip = max_door_size - door_size;
2900 int end = door_size;
2901 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2904 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2906 /* opening door sound has priority over simultaneously closing door */
2907 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2908 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2909 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2910 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2913 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2916 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2917 GC gc = bitmap->stored_clip_gc;
2919 if (door_state & DOOR_ACTION_1)
2921 int a = MIN(x * door_1.step_offset, end);
2922 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2923 int i = p + door_skip;
2925 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2927 BlitBitmap(bitmap_db_door, drawto,
2928 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2929 DXSIZE, DYSIZE, DX, DY);
2933 BlitBitmap(bitmap_db_door, drawto,
2934 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2935 DXSIZE, DYSIZE - p / 2, DX, DY);
2937 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2940 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2942 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2943 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2944 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2945 int dst2_x = DX, dst2_y = DY;
2946 int width = i, height = DYSIZE;
2948 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2949 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2952 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2953 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2956 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2958 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2959 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2960 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2961 int dst2_x = DX, dst2_y = DY;
2962 int width = DXSIZE, height = i;
2964 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2965 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2968 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2969 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2972 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2974 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2976 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2977 BlitBitmapMasked(bitmap, drawto,
2978 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2979 DX + DXSIZE - i, DY + j);
2980 BlitBitmapMasked(bitmap, drawto,
2981 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2982 DX + DXSIZE - i, DY + 140 + j);
2983 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2984 DY - (DOOR_GFX_PAGEY1 + j));
2985 BlitBitmapMasked(bitmap, drawto,
2986 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2988 BlitBitmapMasked(bitmap, drawto,
2989 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2992 BlitBitmapMasked(bitmap, drawto,
2993 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2995 BlitBitmapMasked(bitmap, drawto,
2996 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2998 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2999 BlitBitmapMasked(bitmap, drawto,
3000 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3001 DX + DXSIZE - i, DY + 77 + j);
3002 BlitBitmapMasked(bitmap, drawto,
3003 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3004 DX + DXSIZE - i, DY + 203 + j);
3007 redraw_mask |= REDRAW_DOOR_1;
3008 door_1_done = (a == end);
3011 if (door_state & DOOR_ACTION_2)
3013 int a = MIN(x * door_2.step_offset, door_size);
3014 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3015 int i = p + door_skip;
3017 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3019 BlitBitmap(bitmap_db_door, drawto,
3020 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3021 VXSIZE, VYSIZE, VX, VY);
3023 else if (x <= VYSIZE)
3025 BlitBitmap(bitmap_db_door, drawto,
3026 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3027 VXSIZE, VYSIZE - p / 2, VX, VY);
3029 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3032 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3034 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3035 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3036 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3037 int dst2_x = VX, dst2_y = VY;
3038 int width = i, height = VYSIZE;
3040 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3041 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3044 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3045 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3048 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3050 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3051 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3052 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3053 int dst2_x = VX, dst2_y = VY;
3054 int width = VXSIZE, height = i;
3056 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3057 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3060 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3061 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3064 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3066 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3068 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3069 BlitBitmapMasked(bitmap, drawto,
3070 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3071 VX + VXSIZE - i, VY + j);
3072 SetClipOrigin(bitmap, gc,
3073 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3074 BlitBitmapMasked(bitmap, drawto,
3075 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3078 BlitBitmapMasked(bitmap, drawto,
3079 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3080 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3081 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3082 BlitBitmapMasked(bitmap, drawto,
3083 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3085 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3088 redraw_mask |= REDRAW_DOOR_2;
3089 door_2_done = (a == VXSIZE);
3092 if (!(door_state & DOOR_NO_DELAY))
3096 if (game_status == GAME_MODE_MAIN)
3099 WaitUntilDelayReached(&door_delay, door_delay_value);
3104 if (door_state & DOOR_ACTION_1)
3105 door1 = door_state & DOOR_ACTION_1;
3106 if (door_state & DOOR_ACTION_2)
3107 door2 = door_state & DOOR_ACTION_2;
3109 return (door1 | door2);
3112 void DrawSpecialEditorDoor()
3114 /* draw bigger toolbox window */
3115 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3116 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3118 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3119 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3122 redraw_mask |= REDRAW_ALL;
3125 void UndrawSpecialEditorDoor()
3127 /* draw normal tape recorder window */
3128 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3129 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3132 redraw_mask |= REDRAW_ALL;
3136 /* ---------- new tool button stuff ---------------------------------------- */
3138 /* graphic position values for tool buttons */
3139 #define TOOL_BUTTON_YES_XPOS 2
3140 #define TOOL_BUTTON_YES_YPOS 250
3141 #define TOOL_BUTTON_YES_GFX_YPOS 0
3142 #define TOOL_BUTTON_YES_XSIZE 46
3143 #define TOOL_BUTTON_YES_YSIZE 28
3144 #define TOOL_BUTTON_NO_XPOS 52
3145 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3146 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3147 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3148 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3149 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3150 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3151 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3152 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3153 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3154 #define TOOL_BUTTON_PLAYER_XSIZE 30
3155 #define TOOL_BUTTON_PLAYER_YSIZE 30
3156 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3157 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3158 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3159 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3160 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3161 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3162 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3163 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3164 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3165 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3166 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3167 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3168 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3169 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3170 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3171 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3172 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3173 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3174 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3175 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3184 } toolbutton_info[NUM_TOOL_BUTTONS] =
3187 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3188 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3189 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3194 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3195 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3196 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3201 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3202 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3203 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3204 TOOL_CTRL_ID_CONFIRM,
3208 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3209 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3210 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3211 TOOL_CTRL_ID_PLAYER_1,
3215 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3216 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3217 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3218 TOOL_CTRL_ID_PLAYER_2,
3222 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3223 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3224 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3225 TOOL_CTRL_ID_PLAYER_3,
3229 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3230 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3231 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3232 TOOL_CTRL_ID_PLAYER_4,
3237 void CreateToolButtons()
3241 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3243 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3244 Bitmap *deco_bitmap = None;
3245 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3246 struct GadgetInfo *gi;
3247 unsigned long event_mask;
3248 int gd_xoffset, gd_yoffset;
3249 int gd_x1, gd_x2, gd_y;
3252 event_mask = GD_EVENT_RELEASED;
3254 gd_xoffset = toolbutton_info[i].xpos;
3255 gd_yoffset = toolbutton_info[i].ypos;
3256 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3257 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3258 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3260 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3262 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3264 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3265 &deco_bitmap, &deco_x, &deco_y);
3266 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3267 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3270 gi = CreateGadget(GDI_CUSTOM_ID, id,
3271 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3272 GDI_X, DX + toolbutton_info[i].x,
3273 GDI_Y, DY + toolbutton_info[i].y,
3274 GDI_WIDTH, toolbutton_info[i].width,
3275 GDI_HEIGHT, toolbutton_info[i].height,
3276 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3277 GDI_STATE, GD_BUTTON_UNPRESSED,
3278 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3279 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3280 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3281 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3282 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3283 GDI_DECORATION_SHIFTING, 1, 1,
3284 GDI_DIRECT_DRAW, FALSE,
3285 GDI_EVENT_MASK, event_mask,
3286 GDI_CALLBACK_ACTION, HandleToolButtons,
3290 Error(ERR_EXIT, "cannot create gadget");
3292 tool_gadget[id] = gi;
3296 void FreeToolButtons()
3300 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3301 FreeGadget(tool_gadget[i]);
3304 static void UnmapToolButtons()
3308 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3309 UnmapGadget(tool_gadget[i]);
3312 static void HandleToolButtons(struct GadgetInfo *gi)
3314 request_gadget_id = gi->custom_id;
3317 static struct Mapping_EM_to_RND_object
3320 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3321 boolean is_backside; /* backside of moving element */
3327 em_object_mapping_list[] =
3330 Xblank, TRUE, FALSE,
3334 Yacid_splash_eB, FALSE, FALSE,
3335 EL_ACID_SPLASH_RIGHT, -1, -1
3338 Yacid_splash_wB, FALSE, FALSE,
3339 EL_ACID_SPLASH_LEFT, -1, -1
3342 #ifdef EM_ENGINE_BAD_ROLL
3344 Xstone_force_e, FALSE, FALSE,
3345 EL_ROCK, -1, MV_BIT_RIGHT
3348 Xstone_force_w, FALSE, FALSE,
3349 EL_ROCK, -1, MV_BIT_LEFT
3352 Xnut_force_e, FALSE, FALSE,
3353 EL_NUT, -1, MV_BIT_RIGHT
3356 Xnut_force_w, FALSE, FALSE,
3357 EL_NUT, -1, MV_BIT_LEFT
3360 Xspring_force_e, FALSE, FALSE,
3361 EL_SPRING, -1, MV_BIT_RIGHT
3364 Xspring_force_w, FALSE, FALSE,
3365 EL_SPRING, -1, MV_BIT_LEFT
3368 Xemerald_force_e, FALSE, FALSE,
3369 EL_EMERALD, -1, MV_BIT_RIGHT
3372 Xemerald_force_w, FALSE, FALSE,
3373 EL_EMERALD, -1, MV_BIT_LEFT
3376 Xdiamond_force_e, FALSE, FALSE,
3377 EL_DIAMOND, -1, MV_BIT_RIGHT
3380 Xdiamond_force_w, FALSE, FALSE,
3381 EL_DIAMOND, -1, MV_BIT_LEFT
3384 Xbomb_force_e, FALSE, FALSE,
3385 EL_BOMB, -1, MV_BIT_RIGHT
3388 Xbomb_force_w, FALSE, FALSE,
3389 EL_BOMB, -1, MV_BIT_LEFT
3391 #endif /* EM_ENGINE_BAD_ROLL */
3394 Xstone, TRUE, FALSE,
3398 Xstone_pause, FALSE, FALSE,
3402 Xstone_fall, FALSE, FALSE,
3406 Ystone_s, FALSE, FALSE,
3407 EL_ROCK, ACTION_FALLING, -1
3410 Ystone_sB, FALSE, TRUE,
3411 EL_ROCK, ACTION_FALLING, -1
3414 Ystone_e, FALSE, FALSE,
3415 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3418 Ystone_eB, FALSE, TRUE,
3419 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3422 Ystone_w, FALSE, FALSE,
3423 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3426 Ystone_wB, FALSE, TRUE,
3427 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3434 Xnut_pause, FALSE, FALSE,
3438 Xnut_fall, FALSE, FALSE,
3442 Ynut_s, FALSE, FALSE,
3443 EL_NUT, ACTION_FALLING, -1
3446 Ynut_sB, FALSE, TRUE,
3447 EL_NUT, ACTION_FALLING, -1
3450 Ynut_e, FALSE, FALSE,
3451 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3454 Ynut_eB, FALSE, TRUE,
3455 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3458 Ynut_w, FALSE, FALSE,
3459 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3462 Ynut_wB, FALSE, TRUE,
3463 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3466 Xbug_n, TRUE, FALSE,
3470 Xbug_e, TRUE, FALSE,
3471 EL_BUG_RIGHT, -1, -1
3474 Xbug_s, TRUE, FALSE,
3478 Xbug_w, TRUE, FALSE,
3482 Xbug_gon, FALSE, FALSE,
3486 Xbug_goe, FALSE, FALSE,
3487 EL_BUG_RIGHT, -1, -1
3490 Xbug_gos, FALSE, FALSE,
3494 Xbug_gow, FALSE, FALSE,
3498 Ybug_n, FALSE, FALSE,
3499 EL_BUG, ACTION_MOVING, MV_BIT_UP
3502 Ybug_nB, FALSE, TRUE,
3503 EL_BUG, ACTION_MOVING, MV_BIT_UP
3506 Ybug_e, FALSE, FALSE,
3507 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3510 Ybug_eB, FALSE, TRUE,
3511 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3514 Ybug_s, FALSE, FALSE,
3515 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3518 Ybug_sB, FALSE, TRUE,
3519 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3522 Ybug_w, FALSE, FALSE,
3523 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3526 Ybug_wB, FALSE, TRUE,
3527 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3530 Ybug_w_n, FALSE, FALSE,
3531 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3534 Ybug_n_e, FALSE, FALSE,
3535 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3538 Ybug_e_s, FALSE, FALSE,
3539 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3542 Ybug_s_w, FALSE, FALSE,
3543 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3546 Ybug_e_n, FALSE, FALSE,
3547 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3550 Ybug_s_e, FALSE, FALSE,
3551 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3554 Ybug_w_s, FALSE, FALSE,
3555 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3558 Ybug_n_w, FALSE, FALSE,
3559 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3562 Ybug_stone, FALSE, FALSE,
3563 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3566 Ybug_spring, FALSE, FALSE,
3567 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3570 Xtank_n, TRUE, FALSE,
3571 EL_SPACESHIP_UP, -1, -1
3574 Xtank_e, TRUE, FALSE,
3575 EL_SPACESHIP_RIGHT, -1, -1
3578 Xtank_s, TRUE, FALSE,
3579 EL_SPACESHIP_DOWN, -1, -1
3582 Xtank_w, TRUE, FALSE,
3583 EL_SPACESHIP_LEFT, -1, -1
3586 Xtank_gon, FALSE, FALSE,
3587 EL_SPACESHIP_UP, -1, -1
3590 Xtank_goe, FALSE, FALSE,
3591 EL_SPACESHIP_RIGHT, -1, -1
3594 Xtank_gos, FALSE, FALSE,
3595 EL_SPACESHIP_DOWN, -1, -1
3598 Xtank_gow, FALSE, FALSE,
3599 EL_SPACESHIP_LEFT, -1, -1
3602 Ytank_n, FALSE, FALSE,
3603 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3606 Ytank_nB, FALSE, TRUE,
3607 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3610 Ytank_e, FALSE, FALSE,
3611 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3614 Ytank_eB, FALSE, TRUE,
3615 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3618 Ytank_s, FALSE, FALSE,
3619 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3622 Ytank_sB, FALSE, TRUE,
3623 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3626 Ytank_w, FALSE, FALSE,
3627 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3630 Ytank_wB, FALSE, TRUE,
3631 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3634 Ytank_w_n, FALSE, FALSE,
3635 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3638 Ytank_n_e, FALSE, FALSE,
3639 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3642 Ytank_e_s, FALSE, FALSE,
3643 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3646 Ytank_s_w, FALSE, FALSE,
3647 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3650 Ytank_e_n, FALSE, FALSE,
3651 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3654 Ytank_s_e, FALSE, FALSE,
3655 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3658 Ytank_w_s, FALSE, FALSE,
3659 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3662 Ytank_n_w, FALSE, FALSE,
3663 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3666 Ytank_stone, FALSE, FALSE,
3667 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3670 Ytank_spring, FALSE, FALSE,
3671 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3674 Xandroid, TRUE, FALSE,
3675 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3678 Xandroid_1_n, FALSE, FALSE,
3679 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3682 Xandroid_2_n, FALSE, FALSE,
3683 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3686 Xandroid_1_e, FALSE, FALSE,
3687 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3690 Xandroid_2_e, FALSE, FALSE,
3691 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3694 Xandroid_1_w, FALSE, FALSE,
3695 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3698 Xandroid_2_w, FALSE, FALSE,
3699 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3702 Xandroid_1_s, FALSE, FALSE,
3703 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3706 Xandroid_2_s, FALSE, FALSE,
3707 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3710 Yandroid_n, FALSE, FALSE,
3711 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3714 Yandroid_nB, FALSE, TRUE,
3715 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3718 Yandroid_ne, FALSE, FALSE,
3719 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3722 Yandroid_neB, FALSE, TRUE,
3723 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3726 Yandroid_e, FALSE, FALSE,
3727 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3730 Yandroid_eB, FALSE, TRUE,
3731 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3734 Yandroid_se, FALSE, FALSE,
3735 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3738 Yandroid_seB, FALSE, TRUE,
3739 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3742 Yandroid_s, FALSE, FALSE,
3743 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3746 Yandroid_sB, FALSE, TRUE,
3747 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3750 Yandroid_sw, FALSE, FALSE,
3751 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3754 Yandroid_swB, FALSE, TRUE,
3755 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3758 Yandroid_w, FALSE, FALSE,
3759 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3762 Yandroid_wB, FALSE, TRUE,
3763 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3766 Yandroid_nw, FALSE, FALSE,
3767 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3770 Yandroid_nwB, FALSE, TRUE,
3771 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3774 Xspring, TRUE, FALSE,
3778 Xspring_pause, FALSE, FALSE,
3782 Xspring_e, FALSE, FALSE,
3786 Xspring_w, FALSE, FALSE,
3790 Xspring_fall, FALSE, FALSE,
3794 Yspring_s, FALSE, FALSE,
3795 EL_SPRING, ACTION_FALLING, -1
3798 Yspring_sB, FALSE, TRUE,
3799 EL_SPRING, ACTION_FALLING, -1
3802 Yspring_e, FALSE, FALSE,
3803 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3806 Yspring_eB, FALSE, TRUE,
3807 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3810 Yspring_w, FALSE, FALSE,
3811 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3814 Yspring_wB, FALSE, TRUE,
3815 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3818 Yspring_kill_e, FALSE, FALSE,
3819 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3822 Yspring_kill_eB, FALSE, TRUE,
3823 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3826 Yspring_kill_w, FALSE, FALSE,
3827 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3830 Yspring_kill_wB, FALSE, TRUE,
3831 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3834 Xeater_n, TRUE, FALSE,
3835 EL_YAMYAM_UP, -1, -1
3838 Xeater_e, TRUE, FALSE,
3839 EL_YAMYAM_RIGHT, -1, -1
3842 Xeater_w, TRUE, FALSE,
3843 EL_YAMYAM_LEFT, -1, -1
3846 Xeater_s, TRUE, FALSE,
3847 EL_YAMYAM_DOWN, -1, -1
3850 Yeater_n, FALSE, FALSE,
3851 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3854 Yeater_nB, FALSE, TRUE,
3855 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3858 Yeater_e, FALSE, FALSE,
3859 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3862 Yeater_eB, FALSE, TRUE,
3863 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3866 Yeater_s, FALSE, FALSE,
3867 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3870 Yeater_sB, FALSE, TRUE,
3871 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3874 Yeater_w, FALSE, FALSE,
3875 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3878 Yeater_wB, FALSE, TRUE,
3879 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3882 Yeater_stone, FALSE, FALSE,
3883 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3886 Yeater_spring, FALSE, FALSE,
3887 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3890 Xalien, TRUE, FALSE,
3894 Xalien_pause, FALSE, FALSE,
3898 Yalien_n, FALSE, FALSE,
3899 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3902 Yalien_nB, FALSE, TRUE,
3903 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3906 Yalien_e, FALSE, FALSE,
3907 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3910 Yalien_eB, FALSE, TRUE,
3911 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3914 Yalien_s, FALSE, FALSE,
3915 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3918 Yalien_sB, FALSE, TRUE,
3919 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3922 Yalien_w, FALSE, FALSE,
3923 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3926 Yalien_wB, FALSE, TRUE,
3927 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3930 Yalien_stone, FALSE, FALSE,
3931 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3934 Yalien_spring, FALSE, FALSE,
3935 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3938 Xemerald, TRUE, FALSE,
3942 Xemerald_pause, FALSE, FALSE,
3946 Xemerald_fall, FALSE, FALSE,
3950 Xemerald_shine, FALSE, FALSE,
3951 EL_EMERALD, ACTION_TWINKLING, -1
3954 Yemerald_s, FALSE, FALSE,
3955 EL_EMERALD, ACTION_FALLING, -1
3958 Yemerald_sB, FALSE, TRUE,
3959 EL_EMERALD, ACTION_FALLING, -1
3962 Yemerald_e, FALSE, FALSE,
3963 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3966 Yemerald_eB, FALSE, TRUE,
3967 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3970 Yemerald_w, FALSE, FALSE,
3971 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3974 Yemerald_wB, FALSE, TRUE,
3975 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3978 Yemerald_eat, FALSE, FALSE,
3979 EL_EMERALD, ACTION_COLLECTING, -1
3982 Yemerald_stone, FALSE, FALSE,
3983 EL_NUT, ACTION_BREAKING, -1
3986 Xdiamond, TRUE, FALSE,
3990 Xdiamond_pause, FALSE, FALSE,
3994 Xdiamond_fall, FALSE, FALSE,
3998 Xdiamond_shine, FALSE, FALSE,
3999 EL_DIAMOND, ACTION_TWINKLING, -1
4002 Ydiamond_s, FALSE, FALSE,
4003 EL_DIAMOND, ACTION_FALLING, -1
4006 Ydiamond_sB, FALSE, TRUE,
4007 EL_DIAMOND, ACTION_FALLING, -1
4010 Ydiamond_e, FALSE, FALSE,
4011 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4014 Ydiamond_eB, FALSE, TRUE,
4015 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4018 Ydiamond_w, FALSE, FALSE,
4019 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4022 Ydiamond_wB, FALSE, TRUE,
4023 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4026 Ydiamond_eat, FALSE, FALSE,
4027 EL_DIAMOND, ACTION_COLLECTING, -1
4030 Ydiamond_stone, FALSE, FALSE,
4031 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4034 Xdrip_fall, TRUE, FALSE,
4035 EL_AMOEBA_DROP, -1, -1
4038 Xdrip_stretch, FALSE, FALSE,
4039 EL_AMOEBA_DROP, ACTION_FALLING, -1
4042 Xdrip_stretchB, FALSE, TRUE,
4043 EL_AMOEBA_DROP, ACTION_FALLING, -1
4046 Xdrip_eat, FALSE, FALSE,
4047 EL_AMOEBA_DROP, ACTION_GROWING, -1
4050 Ydrip_s1, FALSE, FALSE,
4051 EL_AMOEBA_DROP, ACTION_FALLING, -1
4054 Ydrip_s1B, FALSE, TRUE,
4055 EL_AMOEBA_DROP, ACTION_FALLING, -1
4058 Ydrip_s2, FALSE, FALSE,
4059 EL_AMOEBA_DROP, ACTION_FALLING, -1
4062 Ydrip_s2B, FALSE, TRUE,
4063 EL_AMOEBA_DROP, ACTION_FALLING, -1
4070 Xbomb_pause, FALSE, FALSE,
4074 Xbomb_fall, FALSE, FALSE,
4078 Ybomb_s, FALSE, FALSE,
4079 EL_BOMB, ACTION_FALLING, -1
4082 Ybomb_sB, FALSE, TRUE,
4083 EL_BOMB, ACTION_FALLING, -1
4086 Ybomb_e, FALSE, FALSE,
4087 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4090 Ybomb_eB, FALSE, TRUE,
4091 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4094 Ybomb_w, FALSE, FALSE,
4095 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4098 Ybomb_wB, FALSE, TRUE,
4099 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4102 Ybomb_eat, FALSE, FALSE,
4103 EL_BOMB, ACTION_ACTIVATING, -1
4106 Xballoon, TRUE, FALSE,
4110 Yballoon_n, FALSE, FALSE,
4111 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4114 Yballoon_nB, FALSE, TRUE,
4115 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4118 Yballoon_e, FALSE, FALSE,
4119 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4122 Yballoon_eB, FALSE, TRUE,
4123 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4126 Yballoon_s, FALSE, FALSE,
4127 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4130 Yballoon_sB, FALSE, TRUE,
4131 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4134 Yballoon_w, FALSE, FALSE,
4135 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4138 Yballoon_wB, FALSE, TRUE,
4139 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4142 Xgrass, TRUE, FALSE,
4143 EL_EMC_GRASS, -1, -1
4146 Ygrass_nB, FALSE, FALSE,
4147 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4150 Ygrass_eB, FALSE, FALSE,
4151 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4154 Ygrass_sB, FALSE, FALSE,
4155 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4158 Ygrass_wB, FALSE, FALSE,
4159 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4166 Ydirt_nB, FALSE, FALSE,
4167 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4170 Ydirt_eB, FALSE, FALSE,
4171 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4174 Ydirt_sB, FALSE, FALSE,
4175 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4178 Ydirt_wB, FALSE, FALSE,
4179 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4182 Xacid_ne, TRUE, FALSE,
4183 EL_ACID_POOL_TOPRIGHT, -1, -1
4186 Xacid_se, TRUE, FALSE,
4187 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4190 Xacid_s, TRUE, FALSE,
4191 EL_ACID_POOL_BOTTOM, -1, -1
4194 Xacid_sw, TRUE, FALSE,
4195 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4198 Xacid_nw, TRUE, FALSE,
4199 EL_ACID_POOL_TOPLEFT, -1, -1
4202 Xacid_1, TRUE, FALSE,
4206 Xacid_2, FALSE, FALSE,
4210 Xacid_3, FALSE, FALSE,
4214 Xacid_4, FALSE, FALSE,
4218 Xacid_5, FALSE, FALSE,
4222 Xacid_6, FALSE, FALSE,
4226 Xacid_7, FALSE, FALSE,
4230 Xacid_8, FALSE, FALSE,
4234 Xball_1, TRUE, FALSE,
4235 EL_EMC_MAGIC_BALL, -1, -1
4238 Xball_1B, FALSE, FALSE,
4239 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4242 Xball_2, FALSE, FALSE,
4243 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4246 Xball_2B, FALSE, FALSE,
4247 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4250 Yball_eat, FALSE, FALSE,
4251 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4254 Ykey_1_eat, FALSE, FALSE,
4255 EL_EM_KEY_1, ACTION_COLLECTING, -1
4258 Ykey_2_eat, FALSE, FALSE,
4259 EL_EM_KEY_2, ACTION_COLLECTING, -1
4262 Ykey_3_eat, FALSE, FALSE,
4263 EL_EM_KEY_3, ACTION_COLLECTING, -1
4266 Ykey_4_eat, FALSE, FALSE,
4267 EL_EM_KEY_4, ACTION_COLLECTING, -1
4270 Ykey_5_eat, FALSE, FALSE,
4271 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4274 Ykey_6_eat, FALSE, FALSE,
4275 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4278 Ykey_7_eat, FALSE, FALSE,
4279 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4282 Ykey_8_eat, FALSE, FALSE,
4283 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4286 Ylenses_eat, FALSE, FALSE,
4287 EL_EMC_LENSES, ACTION_COLLECTING, -1
4290 Ymagnify_eat, FALSE, FALSE,
4291 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4294 Ygrass_eat, FALSE, FALSE,
4295 EL_EMC_GRASS, ACTION_SNAPPING, -1
4298 Ydirt_eat, FALSE, FALSE,
4299 EL_SAND, ACTION_SNAPPING, -1
4302 Xgrow_ns, TRUE, FALSE,
4303 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4306 Ygrow_ns_eat, FALSE, FALSE,
4307 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4310 Xgrow_ew, TRUE, FALSE,
4311 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4314 Ygrow_ew_eat, FALSE, FALSE,
4315 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4318 Xwonderwall, TRUE, FALSE,
4319 EL_MAGIC_WALL, -1, -1
4322 XwonderwallB, FALSE, FALSE,
4323 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4326 Xamoeba_1, TRUE, FALSE,
4327 EL_AMOEBA_DRY, ACTION_OTHER, -1
4330 Xamoeba_2, FALSE, FALSE,
4331 EL_AMOEBA_DRY, ACTION_OTHER, -1
4334 Xamoeba_3, FALSE, FALSE,
4335 EL_AMOEBA_DRY, ACTION_OTHER, -1
4338 Xamoeba_4, FALSE, FALSE,
4339 EL_AMOEBA_DRY, ACTION_OTHER, -1
4342 Xamoeba_5, TRUE, FALSE,
4343 EL_AMOEBA_WET, ACTION_OTHER, -1
4346 Xamoeba_6, FALSE, FALSE,
4347 EL_AMOEBA_WET, ACTION_OTHER, -1
4350 Xamoeba_7, FALSE, FALSE,
4351 EL_AMOEBA_WET, ACTION_OTHER, -1
4354 Xamoeba_8, FALSE, FALSE,
4355 EL_AMOEBA_WET, ACTION_OTHER, -1
4358 Xdoor_1, TRUE, FALSE,
4359 EL_EM_GATE_1, -1, -1
4362 Xdoor_2, TRUE, FALSE,
4363 EL_EM_GATE_2, -1, -1
4366 Xdoor_3, TRUE, FALSE,
4367 EL_EM_GATE_3, -1, -1
4370 Xdoor_4, TRUE, FALSE,
4371 EL_EM_GATE_4, -1, -1
4374 Xdoor_5, TRUE, FALSE,
4375 EL_EMC_GATE_5, -1, -1
4378 Xdoor_6, TRUE, FALSE,
4379 EL_EMC_GATE_6, -1, -1
4382 Xdoor_7, TRUE, FALSE,
4383 EL_EMC_GATE_7, -1, -1
4386 Xdoor_8, TRUE, FALSE,
4387 EL_EMC_GATE_8, -1, -1
4390 Xkey_1, TRUE, FALSE,
4394 Xkey_2, TRUE, FALSE,
4398 Xkey_3, TRUE, FALSE,
4402 Xkey_4, TRUE, FALSE,
4406 Xkey_5, TRUE, FALSE,
4407 EL_EMC_KEY_5, -1, -1
4410 Xkey_6, TRUE, FALSE,
4411 EL_EMC_KEY_6, -1, -1
4414 Xkey_7, TRUE, FALSE,
4415 EL_EMC_KEY_7, -1, -1
4418 Xkey_8, TRUE, FALSE,
4419 EL_EMC_KEY_8, -1, -1
4422 Xwind_n, TRUE, FALSE,
4423 EL_BALLOON_SWITCH_UP, -1, -1
4426 Xwind_e, TRUE, FALSE,
4427 EL_BALLOON_SWITCH_RIGHT, -1, -1
4430 Xwind_s, TRUE, FALSE,
4431 EL_BALLOON_SWITCH_DOWN, -1, -1
4434 Xwind_w, TRUE, FALSE,
4435 EL_BALLOON_SWITCH_LEFT, -1, -1
4438 Xwind_nesw, TRUE, FALSE,
4439 EL_BALLOON_SWITCH_ANY, -1, -1
4442 Xwind_stop, TRUE, FALSE,
4443 EL_BALLOON_SWITCH_NONE, -1, -1
4447 EL_EXIT_CLOSED, -1, -1
4450 Xexit_1, TRUE, FALSE,
4451 EL_EXIT_OPEN, -1, -1
4454 Xexit_2, FALSE, FALSE,
4455 EL_EXIT_OPEN, -1, -1
4458 Xexit_3, FALSE, FALSE,
4459 EL_EXIT_OPEN, -1, -1
4462 Xdynamite, TRUE, FALSE,
4463 EL_EM_DYNAMITE, -1, -1
4466 Ydynamite_eat, FALSE, FALSE,
4467 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4470 Xdynamite_1, TRUE, FALSE,
4471 EL_EM_DYNAMITE_ACTIVE, -1, -1
4474 Xdynamite_2, FALSE, FALSE,
4475 EL_EM_DYNAMITE_ACTIVE, -1, -1
4478 Xdynamite_3, FALSE, FALSE,
4479 EL_EM_DYNAMITE_ACTIVE, -1, -1
4482 Xdynamite_4, FALSE, FALSE,
4483 EL_EM_DYNAMITE_ACTIVE, -1, -1
4486 Xbumper, TRUE, FALSE,
4487 EL_EMC_SPRING_BUMPER, -1, -1
4490 XbumperB, FALSE, FALSE,
4491 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4494 Xwheel, TRUE, FALSE,
4495 EL_ROBOT_WHEEL, -1, -1
4498 XwheelB, FALSE, FALSE,
4499 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4502 Xswitch, TRUE, FALSE,
4503 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4506 XswitchB, FALSE, FALSE,
4507 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4511 EL_QUICKSAND_EMPTY, -1, -1
4514 Xsand_stone, TRUE, FALSE,
4515 EL_QUICKSAND_FULL, -1, -1
4518 Xsand_stonein_1, FALSE, TRUE,
4519 EL_ROCK, ACTION_FILLING, -1
4522 Xsand_stonein_2, FALSE, TRUE,
4523 EL_ROCK, ACTION_FILLING, -1
4526 Xsand_stonein_3, FALSE, TRUE,
4527 EL_ROCK, ACTION_FILLING, -1
4530 Xsand_stonein_4, FALSE, TRUE,
4531 EL_ROCK, ACTION_FILLING, -1
4534 Xsand_stonesand_1, FALSE, FALSE,
4535 EL_QUICKSAND_FULL, -1, -1
4538 Xsand_stonesand_2, FALSE, FALSE,
4539 EL_QUICKSAND_FULL, -1, -1
4542 Xsand_stonesand_3, FALSE, FALSE,
4543 EL_QUICKSAND_FULL, -1, -1
4546 Xsand_stonesand_4, FALSE, FALSE,
4547 EL_QUICKSAND_FULL, -1, -1
4550 Xsand_stoneout_1, FALSE, FALSE,
4551 EL_ROCK, ACTION_EMPTYING, -1
4554 Xsand_stoneout_2, FALSE, FALSE,
4555 EL_ROCK, ACTION_EMPTYING, -1
4558 Xsand_sandstone_1, FALSE, FALSE,
4559 EL_QUICKSAND_FULL, -1, -1
4562 Xsand_sandstone_2, FALSE, FALSE,
4563 EL_QUICKSAND_FULL, -1, -1
4566 Xsand_sandstone_3, FALSE, FALSE,
4567 EL_QUICKSAND_FULL, -1, -1
4570 Xsand_sandstone_4, FALSE, FALSE,
4571 EL_QUICKSAND_FULL, -1, -1
4574 Xplant, TRUE, FALSE,
4575 EL_EMC_PLANT, -1, -1
4578 Yplant, FALSE, FALSE,
4579 EL_EMC_PLANT, -1, -1
4582 Xlenses, TRUE, FALSE,
4583 EL_EMC_LENSES, -1, -1
4586 Xmagnify, TRUE, FALSE,
4587 EL_EMC_MAGNIFIER, -1, -1
4590 Xdripper, TRUE, FALSE,
4591 EL_EMC_DRIPPER, -1, -1
4594 XdripperB, FALSE, FALSE,
4595 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4598 Xfake_blank, TRUE, FALSE,
4599 EL_INVISIBLE_WALL, -1, -1
4602 Xfake_blankB, FALSE, FALSE,
4603 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4606 Xfake_grass, TRUE, FALSE,
4607 EL_EMC_FAKE_GRASS, -1, -1
4610 Xfake_grassB, FALSE, FALSE,
4611 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4614 Xfake_door_1, TRUE, FALSE,
4615 EL_EM_GATE_1_GRAY, -1, -1
4618 Xfake_door_2, TRUE, FALSE,
4619 EL_EM_GATE_2_GRAY, -1, -1
4622 Xfake_door_3, TRUE, FALSE,
4623 EL_EM_GATE_3_GRAY, -1, -1
4626 Xfake_door_4, TRUE, FALSE,
4627 EL_EM_GATE_4_GRAY, -1, -1
4630 Xfake_door_5, TRUE, FALSE,
4631 EL_EMC_GATE_5_GRAY, -1, -1
4634 Xfake_door_6, TRUE, FALSE,
4635 EL_EMC_GATE_6_GRAY, -1, -1
4638 Xfake_door_7, TRUE, FALSE,
4639 EL_EMC_GATE_7_GRAY, -1, -1
4642 Xfake_door_8, TRUE, FALSE,
4643 EL_EMC_GATE_8_GRAY, -1, -1
4646 Xfake_acid_1, TRUE, FALSE,
4647 EL_EMC_FAKE_ACID, -1, -1
4650 Xfake_acid_2, FALSE, FALSE,
4651 EL_EMC_FAKE_ACID, -1, -1
4654 Xfake_acid_3, FALSE, FALSE,
4655 EL_EMC_FAKE_ACID, -1, -1
4658 Xfake_acid_4, FALSE, FALSE,
4659 EL_EMC_FAKE_ACID, -1, -1
4662 Xfake_acid_5, FALSE, FALSE,
4663 EL_EMC_FAKE_ACID, -1, -1
4666 Xfake_acid_6, FALSE, FALSE,
4667 EL_EMC_FAKE_ACID, -1, -1
4670 Xfake_acid_7, FALSE, FALSE,
4671 EL_EMC_FAKE_ACID, -1, -1
4674 Xfake_acid_8, FALSE, FALSE,
4675 EL_EMC_FAKE_ACID, -1, -1
4678 Xsteel_1, TRUE, FALSE,
4679 EL_STEELWALL, -1, -1
4682 Xsteel_2, TRUE, FALSE,
4683 EL_EMC_STEELWALL_2, -1, -1
4686 Xsteel_3, TRUE, FALSE,
4687 EL_EMC_STEELWALL_3, -1, -1
4690 Xsteel_4, TRUE, FALSE,
4691 EL_EMC_STEELWALL_4, -1, -1
4694 Xwall_1, TRUE, FALSE,
4698 Xwall_2, TRUE, FALSE,
4699 EL_EMC_WALL_14, -1, -1
4702 Xwall_3, TRUE, FALSE,
4703 EL_EMC_WALL_15, -1, -1
4706 Xwall_4, TRUE, FALSE,
4707 EL_EMC_WALL_16, -1, -1
4710 Xround_wall_1, TRUE, FALSE,
4711 EL_WALL_SLIPPERY, -1, -1
4714 Xround_wall_2, TRUE, FALSE,
4715 EL_EMC_WALL_SLIPPERY_2, -1, -1
4718 Xround_wall_3, TRUE, FALSE,
4719 EL_EMC_WALL_SLIPPERY_3, -1, -1
4722 Xround_wall_4, TRUE, FALSE,
4723 EL_EMC_WALL_SLIPPERY_4, -1, -1
4726 Xdecor_1, TRUE, FALSE,
4727 EL_EMC_WALL_8, -1, -1
4730 Xdecor_2, TRUE, FALSE,
4731 EL_EMC_WALL_6, -1, -1
4734 Xdecor_3, TRUE, FALSE,
4735 EL_EMC_WALL_4, -1, -1
4738 Xdecor_4, TRUE, FALSE,
4739 EL_EMC_WALL_7, -1, -1
4742 Xdecor_5, TRUE, FALSE,
4743 EL_EMC_WALL_5, -1, -1
4746 Xdecor_6, TRUE, FALSE,
4747 EL_EMC_WALL_9, -1, -1
4750 Xdecor_7, TRUE, FALSE,
4751 EL_EMC_WALL_10, -1, -1
4754 Xdecor_8, TRUE, FALSE,
4755 EL_EMC_WALL_1, -1, -1
4758 Xdecor_9, TRUE, FALSE,
4759 EL_EMC_WALL_2, -1, -1
4762 Xdecor_10, TRUE, FALSE,
4763 EL_EMC_WALL_3, -1, -1
4766 Xdecor_11, TRUE, FALSE,
4767 EL_EMC_WALL_11, -1, -1
4770 Xdecor_12, TRUE, FALSE,
4771 EL_EMC_WALL_12, -1, -1
4774 Xalpha_0, TRUE, FALSE,
4775 EL_CHAR('0'), -1, -1
4778 Xalpha_1, TRUE, FALSE,
4779 EL_CHAR('1'), -1, -1
4782 Xalpha_2, TRUE, FALSE,
4783 EL_CHAR('2'), -1, -1
4786 Xalpha_3, TRUE, FALSE,
4787 EL_CHAR('3'), -1, -1
4790 Xalpha_4, TRUE, FALSE,
4791 EL_CHAR('4'), -1, -1
4794 Xalpha_5, TRUE, FALSE,
4795 EL_CHAR('5'), -1, -1
4798 Xalpha_6, TRUE, FALSE,
4799 EL_CHAR('6'), -1, -1
4802 Xalpha_7, TRUE, FALSE,
4803 EL_CHAR('7'), -1, -1
4806 Xalpha_8, TRUE, FALSE,
4807 EL_CHAR('8'), -1, -1
4810 Xalpha_9, TRUE, FALSE,
4811 EL_CHAR('9'), -1, -1
4814 Xalpha_excla, TRUE, FALSE,
4815 EL_CHAR('!'), -1, -1
4818 Xalpha_quote, TRUE, FALSE,
4819 EL_CHAR('"'), -1, -1
4822 Xalpha_comma, TRUE, FALSE,
4823 EL_CHAR(','), -1, -1
4826 Xalpha_minus, TRUE, FALSE,
4827 EL_CHAR('-'), -1, -1
4830 Xalpha_perio, TRUE, FALSE,
4831 EL_CHAR('.'), -1, -1
4834 Xalpha_colon, TRUE, FALSE,
4835 EL_CHAR(':'), -1, -1
4838 Xalpha_quest, TRUE, FALSE,
4839 EL_CHAR('?'), -1, -1
4842 Xalpha_a, TRUE, FALSE,
4843 EL_CHAR('A'), -1, -1
4846 Xalpha_b, TRUE, FALSE,
4847 EL_CHAR('B'), -1, -1
4850 Xalpha_c, TRUE, FALSE,
4851 EL_CHAR('C'), -1, -1
4854 Xalpha_d, TRUE, FALSE,
4855 EL_CHAR('D'), -1, -1
4858 Xalpha_e, TRUE, FALSE,
4859 EL_CHAR('E'), -1, -1
4862 Xalpha_f, TRUE, FALSE,
4863 EL_CHAR('F'), -1, -1
4866 Xalpha_g, TRUE, FALSE,
4867 EL_CHAR('G'), -1, -1
4870 Xalpha_h, TRUE, FALSE,
4871 EL_CHAR('H'), -1, -1
4874 Xalpha_i, TRUE, FALSE,
4875 EL_CHAR('I'), -1, -1
4878 Xalpha_j, TRUE, FALSE,
4879 EL_CHAR('J'), -1, -1
4882 Xalpha_k, TRUE, FALSE,
4883 EL_CHAR('K'), -1, -1
4886 Xalpha_l, TRUE, FALSE,
4887 EL_CHAR('L'), -1, -1
4890 Xalpha_m, TRUE, FALSE,
4891 EL_CHAR('M'), -1, -1
4894 Xalpha_n, TRUE, FALSE,
4895 EL_CHAR('N'), -1, -1
4898 Xalpha_o, TRUE, FALSE,
4899 EL_CHAR('O'), -1, -1
4902 Xalpha_p, TRUE, FALSE,
4903 EL_CHAR('P'), -1, -1
4906 Xalpha_q, TRUE, FALSE,
4907 EL_CHAR('Q'), -1, -1
4910 Xalpha_r, TRUE, FALSE,
4911 EL_CHAR('R'), -1, -1
4914 Xalpha_s, TRUE, FALSE,
4915 EL_CHAR('S'), -1, -1
4918 Xalpha_t, TRUE, FALSE,
4919 EL_CHAR('T'), -1, -1
4922 Xalpha_u, TRUE, FALSE,
4923 EL_CHAR('U'), -1, -1
4926 Xalpha_v, TRUE, FALSE,
4927 EL_CHAR('V'), -1, -1
4930 Xalpha_w, TRUE, FALSE,
4931 EL_CHAR('W'), -1, -1
4934 Xalpha_x, TRUE, FALSE,
4935 EL_CHAR('X'), -1, -1
4938 Xalpha_y, TRUE, FALSE,
4939 EL_CHAR('Y'), -1, -1
4942 Xalpha_z, TRUE, FALSE,
4943 EL_CHAR('Z'), -1, -1
4946 Xalpha_arrow_e, TRUE, FALSE,
4947 EL_CHAR('>'), -1, -1
4950 Xalpha_arrow_w, TRUE, FALSE,
4951 EL_CHAR('<'), -1, -1
4954 Xalpha_copyr, TRUE, FALSE,
4955 EL_CHAR('©'), -1, -1
4959 Xboom_bug, FALSE, FALSE,
4960 EL_BUG, ACTION_EXPLODING, -1
4963 Xboom_bomb, FALSE, FALSE,
4964 EL_BOMB, ACTION_EXPLODING, -1
4967 Xboom_android, FALSE, FALSE,
4968 EL_EMC_ANDROID, ACTION_OTHER, -1
4971 Xboom_1, FALSE, FALSE,
4972 EL_DEFAULT, ACTION_EXPLODING, -1
4975 Xboom_2, FALSE, FALSE,
4976 EL_DEFAULT, ACTION_EXPLODING, -1
4979 Znormal, FALSE, FALSE,
4983 Zdynamite, FALSE, FALSE,
4987 Zplayer, FALSE, FALSE,
4991 ZBORDER, FALSE, FALSE,
5001 static struct Mapping_EM_to_RND_player
5010 em_player_mapping_list[] =
5014 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5018 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5022 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5026 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5030 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5034 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5038 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5042 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5046 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5050 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5054 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5058 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5062 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5066 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5070 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5074 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5078 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5082 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5086 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5090 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5094 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5098 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5102 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5106 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5110 EL_PLAYER_1, ACTION_DEFAULT, -1,
5114 EL_PLAYER_2, ACTION_DEFAULT, -1,
5118 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5122 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5126 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5130 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5134 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5138 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5142 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5146 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5150 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5154 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5158 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5162 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5166 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5170 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5174 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5178 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5182 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5186 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5190 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5194 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5198 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5202 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5206 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5210 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5214 EL_PLAYER_3, ACTION_DEFAULT, -1,
5218 EL_PLAYER_4, ACTION_DEFAULT, -1,
5227 int map_element_RND_to_EM(int element_rnd)
5229 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5230 static boolean mapping_initialized = FALSE;
5232 if (!mapping_initialized)
5236 /* return "Xalpha_quest" for all undefined elements in mapping array */
5237 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5238 mapping_RND_to_EM[i] = Xalpha_quest;
5240 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5241 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5242 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5243 em_object_mapping_list[i].element_em;
5245 mapping_initialized = TRUE;
5248 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5249 return mapping_RND_to_EM[element_rnd];
5251 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5256 int map_element_EM_to_RND(int element_em)
5258 static unsigned short mapping_EM_to_RND[TILE_MAX];
5259 static boolean mapping_initialized = FALSE;
5261 if (!mapping_initialized)
5265 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5266 for (i = 0; i < TILE_MAX; i++)
5267 mapping_EM_to_RND[i] = EL_UNKNOWN;
5269 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5270 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5271 em_object_mapping_list[i].element_rnd;
5273 mapping_initialized = TRUE;
5276 if (element_em >= 0 && element_em < TILE_MAX)
5277 return mapping_EM_to_RND[element_em];
5279 Error(ERR_WARN, "invalid EM level element %d", element_em);
5284 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5286 struct LevelInfo_EM *level_em = level->native_em_level;
5287 struct LEVEL *lev = level_em->lev;
5290 for (i = 0; i < TILE_MAX; i++)
5291 lev->android_array[i] = Xblank;
5293 for (i = 0; i < level->num_android_clone_elements; i++)
5295 int element_rnd = level->android_clone_element[i];
5296 int element_em = map_element_RND_to_EM(element_rnd);
5298 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5299 if (em_object_mapping_list[j].element_rnd == element_rnd)
5300 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5304 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5306 struct LevelInfo_EM *level_em = level->native_em_level;
5307 struct LEVEL *lev = level_em->lev;
5310 level->num_android_clone_elements = 0;
5312 for (i = 0; i < TILE_MAX; i++)
5314 int element_em = lev->android_array[i];
5316 boolean element_found = FALSE;
5318 if (element_em == Xblank)
5321 element_rnd = map_element_EM_to_RND(element_em);
5323 for (j = 0; j < level->num_android_clone_elements; j++)
5324 if (level->android_clone_element[j] == element_rnd)
5325 element_found = TRUE;
5329 level->android_clone_element[level->num_android_clone_elements++] =
5332 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5337 if (level->num_android_clone_elements == 0)
5339 level->num_android_clone_elements = 1;
5340 level->android_clone_element[0] = EL_EMPTY;
5344 int map_direction_RND_to_EM(int direction)
5346 return (direction == MV_UP ? 0 :
5347 direction == MV_RIGHT ? 1 :
5348 direction == MV_DOWN ? 2 :
5349 direction == MV_LEFT ? 3 :
5353 int map_direction_EM_to_RND(int direction)
5355 return (direction == 0 ? MV_UP :
5356 direction == 1 ? MV_RIGHT :
5357 direction == 2 ? MV_DOWN :
5358 direction == 3 ? MV_LEFT :
5362 int get_next_element(int element)
5366 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5367 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5368 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5369 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5370 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5371 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5372 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5374 default: return element;
5379 int el_act_dir2img(int element, int action, int direction)
5381 element = GFX_ELEMENT(element);
5383 if (direction == MV_NONE)
5384 return element_info[element].graphic[action];
5386 direction = MV_DIR_TO_BIT(direction);
5388 return element_info[element].direction_graphic[action][direction];
5391 int el_act_dir2img(int element, int action, int direction)
5393 element = GFX_ELEMENT(element);
5394 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5396 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5397 return element_info[element].direction_graphic[action][direction];
5402 static int el_act_dir2crm(int element, int action, int direction)
5404 element = GFX_ELEMENT(element);
5406 if (direction == MV_NONE)
5407 return element_info[element].crumbled[action];
5409 direction = MV_DIR_TO_BIT(direction);
5411 return element_info[element].direction_crumbled[action][direction];
5414 static int el_act_dir2crm(int element, int action, int direction)
5416 element = GFX_ELEMENT(element);
5417 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5419 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5420 return element_info[element].direction_crumbled[action][direction];
5424 int el_act2img(int element, int action)
5426 element = GFX_ELEMENT(element);
5428 return element_info[element].graphic[action];
5431 int el_act2crm(int element, int action)
5433 element = GFX_ELEMENT(element);
5435 return element_info[element].crumbled[action];
5438 int el_dir2img(int element, int direction)
5440 element = GFX_ELEMENT(element);
5442 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5445 int el2baseimg(int element)
5447 return element_info[element].graphic[ACTION_DEFAULT];
5450 int el2img(int element)
5452 element = GFX_ELEMENT(element);
5454 return element_info[element].graphic[ACTION_DEFAULT];
5457 int el2edimg(int element)
5459 element = GFX_ELEMENT(element);
5461 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5464 int el2preimg(int element)
5466 element = GFX_ELEMENT(element);
5468 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5471 int font2baseimg(int font_nr)
5473 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5476 int getNumActivePlayers_EM()
5478 int num_players = 0;
5484 for (i = 0; i < MAX_PLAYERS; i++)
5485 if (tape.player_participates[i])
5491 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5493 int game_frame_delay_value;
5495 game_frame_delay_value =
5496 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5497 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5500 if (tape.playing && tape.warp_forward && !tape.pausing)
5501 game_frame_delay_value = 0;
5503 return game_frame_delay_value;
5506 unsigned int InitRND(long seed)
5508 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5509 return InitEngineRandom_EM(seed);
5511 return InitEngineRandom_RND(seed);
5514 void InitGraphicInfo_EM(void)
5516 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5517 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5521 int num_em_gfx_errors = 0;
5523 if (graphic_info_em_object[0][0].bitmap == NULL)
5525 /* EM graphics not yet initialized in em_open_all() */
5530 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5533 /* always start with reliable default values */
5534 for (i = 0; i < TILE_MAX; i++)
5536 object_mapping[i].element_rnd = EL_UNKNOWN;
5537 object_mapping[i].is_backside = FALSE;
5538 object_mapping[i].action = ACTION_DEFAULT;
5539 object_mapping[i].direction = MV_NONE;
5542 /* always start with reliable default values */
5543 for (p = 0; p < MAX_PLAYERS; p++)
5545 for (i = 0; i < SPR_MAX; i++)
5547 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5548 player_mapping[p][i].action = ACTION_DEFAULT;
5549 player_mapping[p][i].direction = MV_NONE;
5553 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5555 int e = em_object_mapping_list[i].element_em;
5557 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5558 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5560 if (em_object_mapping_list[i].action != -1)
5561 object_mapping[e].action = em_object_mapping_list[i].action;
5563 if (em_object_mapping_list[i].direction != -1)
5564 object_mapping[e].direction =
5565 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5568 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5570 int a = em_player_mapping_list[i].action_em;
5571 int p = em_player_mapping_list[i].player_nr;
5573 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5575 if (em_player_mapping_list[i].action != -1)
5576 player_mapping[p][a].action = em_player_mapping_list[i].action;
5578 if (em_player_mapping_list[i].direction != -1)
5579 player_mapping[p][a].direction =
5580 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5583 for (i = 0; i < TILE_MAX; i++)
5585 int element = object_mapping[i].element_rnd;
5586 int action = object_mapping[i].action;
5587 int direction = object_mapping[i].direction;
5588 boolean is_backside = object_mapping[i].is_backside;
5589 boolean action_removing = (action == ACTION_DIGGING ||
5590 action == ACTION_SNAPPING ||
5591 action == ACTION_COLLECTING);
5592 boolean action_exploding = ((action == ACTION_EXPLODING ||
5593 action == ACTION_SMASHED_BY_ROCK ||
5594 action == ACTION_SMASHED_BY_SPRING) &&
5595 element != EL_DIAMOND);
5596 boolean action_active = (action == ACTION_ACTIVE);
5597 boolean action_other = (action == ACTION_OTHER);
5599 for (j = 0; j < 8; j++)
5601 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5602 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5604 i == Xdrip_stretch ? element :
5605 i == Xdrip_stretchB ? element :
5606 i == Ydrip_s1 ? element :
5607 i == Ydrip_s1B ? element :
5608 i == Xball_1B ? element :
5609 i == Xball_2 ? element :
5610 i == Xball_2B ? element :
5611 i == Yball_eat ? element :
5612 i == Ykey_1_eat ? element :
5613 i == Ykey_2_eat ? element :
5614 i == Ykey_3_eat ? element :
5615 i == Ykey_4_eat ? element :
5616 i == Ykey_5_eat ? element :
5617 i == Ykey_6_eat ? element :
5618 i == Ykey_7_eat ? element :
5619 i == Ykey_8_eat ? element :
5620 i == Ylenses_eat ? element :
5621 i == Ymagnify_eat ? element :
5622 i == Ygrass_eat ? element :
5623 i == Ydirt_eat ? element :
5624 i == Yemerald_stone ? EL_EMERALD :
5625 i == Ydiamond_stone ? EL_ROCK :
5626 i == Xsand_stonein_1 ? element :
5627 i == Xsand_stonein_2 ? element :
5628 i == Xsand_stonein_3 ? element :
5629 i == Xsand_stonein_4 ? element :
5630 is_backside ? EL_EMPTY :
5631 action_removing ? EL_EMPTY :
5633 int effective_action = (j < 7 ? action :
5634 i == Xdrip_stretch ? action :
5635 i == Xdrip_stretchB ? action :
5636 i == Ydrip_s1 ? action :
5637 i == Ydrip_s1B ? action :
5638 i == Xball_1B ? action :
5639 i == Xball_2 ? action :
5640 i == Xball_2B ? action :
5641 i == Yball_eat ? action :
5642 i == Ykey_1_eat ? action :
5643 i == Ykey_2_eat ? action :
5644 i == Ykey_3_eat ? action :
5645 i == Ykey_4_eat ? action :
5646 i == Ykey_5_eat ? action :
5647 i == Ykey_6_eat ? action :
5648 i == Ykey_7_eat ? action :
5649 i == Ykey_8_eat ? action :
5650 i == Ylenses_eat ? action :
5651 i == Ymagnify_eat ? action :
5652 i == Ygrass_eat ? action :
5653 i == Ydirt_eat ? action :
5654 i == Xsand_stonein_1 ? action :
5655 i == Xsand_stonein_2 ? action :
5656 i == Xsand_stonein_3 ? action :
5657 i == Xsand_stonein_4 ? action :
5658 i == Xsand_stoneout_1 ? action :
5659 i == Xsand_stoneout_2 ? action :
5660 i == Xboom_android ? ACTION_EXPLODING :
5661 action_exploding ? ACTION_EXPLODING :
5662 action_active ? action :
5663 action_other ? action :
5665 int graphic = (el_act_dir2img(effective_element, effective_action,
5667 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5669 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5670 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5671 boolean has_action_graphics = (graphic != base_graphic);
5672 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5673 struct GraphicInfo *g = &graphic_info[graphic];
5674 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5677 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5678 boolean special_animation = (action != ACTION_DEFAULT &&
5679 g->anim_frames == 3 &&
5680 g->anim_delay == 2 &&
5681 g->anim_mode & ANIM_LINEAR);
5682 int sync_frame = (i == Xdrip_stretch ? 7 :
5683 i == Xdrip_stretchB ? 7 :
5684 i == Ydrip_s2 ? j + 8 :
5685 i == Ydrip_s2B ? j + 8 :
5694 i == Xfake_acid_1 ? 0 :
5695 i == Xfake_acid_2 ? 10 :
5696 i == Xfake_acid_3 ? 20 :
5697 i == Xfake_acid_4 ? 30 :
5698 i == Xfake_acid_5 ? 40 :
5699 i == Xfake_acid_6 ? 50 :
5700 i == Xfake_acid_7 ? 60 :
5701 i == Xfake_acid_8 ? 70 :
5703 i == Xball_2B ? j + 8 :
5704 i == Yball_eat ? j + 1 :
5705 i == Ykey_1_eat ? j + 1 :
5706 i == Ykey_2_eat ? j + 1 :
5707 i == Ykey_3_eat ? j + 1 :
5708 i == Ykey_4_eat ? j + 1 :
5709 i == Ykey_5_eat ? j + 1 :
5710 i == Ykey_6_eat ? j + 1 :
5711 i == Ykey_7_eat ? j + 1 :
5712 i == Ykey_8_eat ? j + 1 :
5713 i == Ylenses_eat ? j + 1 :
5714 i == Ymagnify_eat ? j + 1 :
5715 i == Ygrass_eat ? j + 1 :
5716 i == Ydirt_eat ? j + 1 :
5717 i == Xamoeba_1 ? 0 :
5718 i == Xamoeba_2 ? 1 :
5719 i == Xamoeba_3 ? 2 :
5720 i == Xamoeba_4 ? 3 :
5721 i == Xamoeba_5 ? 0 :
5722 i == Xamoeba_6 ? 1 :
5723 i == Xamoeba_7 ? 2 :
5724 i == Xamoeba_8 ? 3 :
5725 i == Xexit_2 ? j + 8 :
5726 i == Xexit_3 ? j + 16 :
5727 i == Xdynamite_1 ? 0 :
5728 i == Xdynamite_2 ? 8 :
5729 i == Xdynamite_3 ? 16 :
5730 i == Xdynamite_4 ? 24 :
5731 i == Xsand_stonein_1 ? j + 1 :
5732 i == Xsand_stonein_2 ? j + 9 :
5733 i == Xsand_stonein_3 ? j + 17 :
5734 i == Xsand_stonein_4 ? j + 25 :
5735 i == Xsand_stoneout_1 && j == 0 ? 0 :
5736 i == Xsand_stoneout_1 && j == 1 ? 0 :
5737 i == Xsand_stoneout_1 && j == 2 ? 1 :
5738 i == Xsand_stoneout_1 && j == 3 ? 2 :
5739 i == Xsand_stoneout_1 && j == 4 ? 2 :
5740 i == Xsand_stoneout_1 && j == 5 ? 3 :
5741 i == Xsand_stoneout_1 && j == 6 ? 4 :
5742 i == Xsand_stoneout_1 && j == 7 ? 4 :
5743 i == Xsand_stoneout_2 && j == 0 ? 5 :
5744 i == Xsand_stoneout_2 && j == 1 ? 6 :
5745 i == Xsand_stoneout_2 && j == 2 ? 7 :
5746 i == Xsand_stoneout_2 && j == 3 ? 8 :
5747 i == Xsand_stoneout_2 && j == 4 ? 9 :
5748 i == Xsand_stoneout_2 && j == 5 ? 11 :
5749 i == Xsand_stoneout_2 && j == 6 ? 13 :
5750 i == Xsand_stoneout_2 && j == 7 ? 15 :
5751 i == Xboom_bug && j == 1 ? 2 :
5752 i == Xboom_bug && j == 2 ? 2 :
5753 i == Xboom_bug && j == 3 ? 4 :
5754 i == Xboom_bug && j == 4 ? 4 :
5755 i == Xboom_bug && j == 5 ? 2 :
5756 i == Xboom_bug && j == 6 ? 2 :
5757 i == Xboom_bug && j == 7 ? 0 :
5758 i == Xboom_bomb && j == 1 ? 2 :
5759 i == Xboom_bomb && j == 2 ? 2 :
5760 i == Xboom_bomb && j == 3 ? 4 :
5761 i == Xboom_bomb && j == 4 ? 4 :
5762 i == Xboom_bomb && j == 5 ? 2 :
5763 i == Xboom_bomb && j == 6 ? 2 :
5764 i == Xboom_bomb && j == 7 ? 0 :
5765 i == Xboom_android && j == 7 ? 6 :
5766 i == Xboom_1 && j == 1 ? 2 :
5767 i == Xboom_1 && j == 2 ? 2 :
5768 i == Xboom_1 && j == 3 ? 4 :
5769 i == Xboom_1 && j == 4 ? 4 :
5770 i == Xboom_1 && j == 5 ? 6 :
5771 i == Xboom_1 && j == 6 ? 6 :
5772 i == Xboom_1 && j == 7 ? 8 :
5773 i == Xboom_2 && j == 0 ? 8 :
5774 i == Xboom_2 && j == 1 ? 8 :
5775 i == Xboom_2 && j == 2 ? 10 :
5776 i == Xboom_2 && j == 3 ? 10 :
5777 i == Xboom_2 && j == 4 ? 10 :
5778 i == Xboom_2 && j == 5 ? 12 :
5779 i == Xboom_2 && j == 6 ? 12 :
5780 i == Xboom_2 && j == 7 ? 12 :
5781 special_animation && j == 4 ? 3 :
5782 effective_action != action ? 0 :
5786 Bitmap *debug_bitmap = g_em->bitmap;
5787 int debug_src_x = g_em->src_x;
5788 int debug_src_y = g_em->src_y;
5791 int frame = getAnimationFrame(g->anim_frames,
5794 g->anim_start_frame,
5797 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5798 g->double_movement && is_backside);
5800 g_em->bitmap = src_bitmap;
5801 g_em->src_x = src_x;
5802 g_em->src_y = src_y;
5803 g_em->src_offset_x = 0;
5804 g_em->src_offset_y = 0;
5805 g_em->dst_offset_x = 0;
5806 g_em->dst_offset_y = 0;
5807 g_em->width = TILEX;
5808 g_em->height = TILEY;
5810 g_em->crumbled_bitmap = NULL;
5811 g_em->crumbled_src_x = 0;
5812 g_em->crumbled_src_y = 0;
5813 g_em->crumbled_border_size = 0;
5815 g_em->has_crumbled_graphics = FALSE;
5816 g_em->preserve_background = FALSE;
5819 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5820 printf("::: empty crumbled: %d [%s], %d, %d\n",
5821 effective_element, element_info[effective_element].token_name,
5822 effective_action, direction);
5825 /* if element can be crumbled, but certain action graphics are just empty
5826 space (like snapping sand with the original R'n'D graphics), do not
5827 treat these empty space graphics as crumbled graphics in EMC engine */
5828 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5830 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5832 g_em->has_crumbled_graphics = TRUE;
5833 g_em->crumbled_bitmap = src_bitmap;
5834 g_em->crumbled_src_x = src_x;
5835 g_em->crumbled_src_y = src_y;
5836 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5840 if (element == EL_ROCK &&
5841 effective_action == ACTION_FILLING)
5842 printf("::: has_action_graphics == %d\n", has_action_graphics);
5845 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5846 effective_action == ACTION_MOVING ||
5847 effective_action == ACTION_PUSHING ||
5848 effective_action == ACTION_EATING)) ||
5849 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5850 effective_action == ACTION_EMPTYING)))
5853 (effective_action == ACTION_FALLING ||
5854 effective_action == ACTION_FILLING ||
5855 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5856 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5857 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5858 int num_steps = (i == Ydrip_s1 ? 16 :
5859 i == Ydrip_s1B ? 16 :
5860 i == Ydrip_s2 ? 16 :
5861 i == Ydrip_s2B ? 16 :
5862 i == Xsand_stonein_1 ? 32 :
5863 i == Xsand_stonein_2 ? 32 :
5864 i == Xsand_stonein_3 ? 32 :
5865 i == Xsand_stonein_4 ? 32 :
5866 i == Xsand_stoneout_1 ? 16 :
5867 i == Xsand_stoneout_2 ? 16 : 8);
5868 int cx = ABS(dx) * (TILEX / num_steps);
5869 int cy = ABS(dy) * (TILEY / num_steps);
5870 int step_frame = (i == Ydrip_s2 ? j + 8 :
5871 i == Ydrip_s2B ? j + 8 :
5872 i == Xsand_stonein_2 ? j + 8 :
5873 i == Xsand_stonein_3 ? j + 16 :
5874 i == Xsand_stonein_4 ? j + 24 :
5875 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5876 int step = (is_backside ? step_frame : num_steps - step_frame);
5878 if (is_backside) /* tile where movement starts */
5880 if (dx < 0 || dy < 0)
5882 g_em->src_offset_x = cx * step;
5883 g_em->src_offset_y = cy * step;
5887 g_em->dst_offset_x = cx * step;
5888 g_em->dst_offset_y = cy * step;
5891 else /* tile where movement ends */
5893 if (dx < 0 || dy < 0)
5895 g_em->dst_offset_x = cx * step;
5896 g_em->dst_offset_y = cy * step;
5900 g_em->src_offset_x = cx * step;
5901 g_em->src_offset_y = cy * step;
5905 g_em->width = TILEX - cx * step;
5906 g_em->height = TILEY - cy * step;
5909 /* create unique graphic identifier to decide if tile must be redrawn */
5910 /* bit 31 - 16 (16 bit): EM style graphic
5911 bit 15 - 12 ( 4 bit): EM style frame
5912 bit 11 - 6 ( 6 bit): graphic width
5913 bit 5 - 0 ( 6 bit): graphic height */
5914 g_em->unique_identifier =
5915 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5919 /* skip check for EMC elements not contained in original EMC artwork */
5920 if (element == EL_EMC_FAKE_ACID)
5923 if (g_em->bitmap != debug_bitmap ||
5924 g_em->src_x != debug_src_x ||
5925 g_em->src_y != debug_src_y ||
5926 g_em->src_offset_x != 0 ||
5927 g_em->src_offset_y != 0 ||
5928 g_em->dst_offset_x != 0 ||
5929 g_em->dst_offset_y != 0 ||
5930 g_em->width != TILEX ||
5931 g_em->height != TILEY)
5933 static int last_i = -1;
5941 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5942 i, element, element_info[element].token_name,
5943 element_action_info[effective_action].suffix, direction);
5945 if (element != effective_element)
5946 printf(" [%d ('%s')]",
5948 element_info[effective_element].token_name);
5952 if (g_em->bitmap != debug_bitmap)
5953 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5954 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5956 if (g_em->src_x != debug_src_x ||
5957 g_em->src_y != debug_src_y)
5958 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5959 j, (is_backside ? 'B' : 'F'),
5960 g_em->src_x, g_em->src_y,
5961 g_em->src_x / 32, g_em->src_y / 32,
5962 debug_src_x, debug_src_y,
5963 debug_src_x / 32, debug_src_y / 32);
5965 if (g_em->src_offset_x != 0 ||
5966 g_em->src_offset_y != 0 ||
5967 g_em->dst_offset_x != 0 ||
5968 g_em->dst_offset_y != 0)
5969 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5971 g_em->src_offset_x, g_em->src_offset_y,
5972 g_em->dst_offset_x, g_em->dst_offset_y);
5974 if (g_em->width != TILEX ||
5975 g_em->height != TILEY)
5976 printf(" %d (%d): size %d,%d should be %d,%d\n",
5978 g_em->width, g_em->height, TILEX, TILEY);
5980 num_em_gfx_errors++;
5987 for (i = 0; i < TILE_MAX; i++)
5989 for (j = 0; j < 8; j++)
5991 int element = object_mapping[i].element_rnd;
5992 int action = object_mapping[i].action;
5993 int direction = object_mapping[i].direction;
5994 boolean is_backside = object_mapping[i].is_backside;
5995 int graphic_action = el_act_dir2img(element, action, direction);
5996 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5998 if ((action == ACTION_SMASHED_BY_ROCK ||
5999 action == ACTION_SMASHED_BY_SPRING ||
6000 action == ACTION_EATING) &&
6001 graphic_action == graphic_default)
6003 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6004 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6005 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6006 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6009 /* no separate animation for "smashed by rock" -- use rock instead */
6010 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6011 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6013 g_em->bitmap = g_xx->bitmap;
6014 g_em->src_x = g_xx->src_x;
6015 g_em->src_y = g_xx->src_y;
6016 g_em->src_offset_x = g_xx->src_offset_x;
6017 g_em->src_offset_y = g_xx->src_offset_y;
6018 g_em->dst_offset_x = g_xx->dst_offset_x;
6019 g_em->dst_offset_y = g_xx->dst_offset_y;
6020 g_em->width = g_xx->width;
6021 g_em->height = g_xx->height;
6022 g_em->unique_identifier = g_xx->unique_identifier;
6025 g_em->preserve_background = TRUE;
6030 for (p = 0; p < MAX_PLAYERS; p++)
6032 for (i = 0; i < SPR_MAX; i++)
6034 int element = player_mapping[p][i].element_rnd;
6035 int action = player_mapping[p][i].action;
6036 int direction = player_mapping[p][i].direction;
6038 for (j = 0; j < 8; j++)
6040 int effective_element = element;
6041 int effective_action = action;
6042 int graphic = (direction == MV_NONE ?
6043 el_act2img(effective_element, effective_action) :
6044 el_act_dir2img(effective_element, effective_action,
6046 struct GraphicInfo *g = &graphic_info[graphic];
6047 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6053 Bitmap *debug_bitmap = g_em->bitmap;
6054 int debug_src_x = g_em->src_x;
6055 int debug_src_y = g_em->src_y;
6058 int frame = getAnimationFrame(g->anim_frames,
6061 g->anim_start_frame,
6064 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6066 g_em->bitmap = src_bitmap;
6067 g_em->src_x = src_x;
6068 g_em->src_y = src_y;
6069 g_em->src_offset_x = 0;
6070 g_em->src_offset_y = 0;
6071 g_em->dst_offset_x = 0;
6072 g_em->dst_offset_y = 0;
6073 g_em->width = TILEX;
6074 g_em->height = TILEY;
6078 /* skip check for EMC elements not contained in original EMC artwork */
6079 if (element == EL_PLAYER_3 ||
6080 element == EL_PLAYER_4)
6083 if (g_em->bitmap != debug_bitmap ||
6084 g_em->src_x != debug_src_x ||
6085 g_em->src_y != debug_src_y)
6087 static int last_i = -1;
6095 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6096 p, i, element, element_info[element].token_name,
6097 element_action_info[effective_action].suffix, direction);
6099 if (element != effective_element)
6100 printf(" [%d ('%s')]",
6102 element_info[effective_element].token_name);
6106 if (g_em->bitmap != debug_bitmap)
6107 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6108 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6110 if (g_em->src_x != debug_src_x ||
6111 g_em->src_y != debug_src_y)
6112 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6114 g_em->src_x, g_em->src_y,
6115 g_em->src_x / 32, g_em->src_y / 32,
6116 debug_src_x, debug_src_y,
6117 debug_src_x / 32, debug_src_y / 32);
6119 num_em_gfx_errors++;
6129 printf("::: [%d errors found]\n", num_em_gfx_errors);
6135 void PlayMenuSound()
6137 int sound = menu.sound[game_status];
6139 if (sound == SND_UNDEFINED)
6142 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6143 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6146 if (IS_LOOP_SOUND(sound))
6147 PlaySoundLoop(sound);
6152 void PlayMenuSoundStereo(int sound, int stereo_position)
6154 if (sound == SND_UNDEFINED)
6157 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6158 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6161 if (IS_LOOP_SOUND(sound))
6162 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6164 PlaySoundStereo(sound, stereo_position);
6167 void PlayMenuSoundIfLoop()
6169 int sound = menu.sound[game_status];
6171 if (sound == SND_UNDEFINED)
6174 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6175 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6178 if (IS_LOOP_SOUND(sound))
6179 PlaySoundLoop(sound);
6182 void PlayMenuMusic()
6184 int music = menu.music[game_status];
6186 if (music == MUS_UNDEFINED)
6189 if (!setup.sound_music)
6195 void PlaySoundActivating()
6197 PlaySound(SND_MENU_ITEM_ACTIVATING);
6200 void PlaySoundSelecting()
6202 PlaySound(SND_MENU_ITEM_SELECTING);
6205 void ToggleFullscreenIfNeeded()
6207 boolean change_fullscreen = (setup.fullscreen !=
6208 video.fullscreen_enabled);
6209 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6210 !strEqual(setup.fullscreen_mode,
6211 video.fullscreen_mode_current));
6213 if (!video.fullscreen_available)
6217 if (change_fullscreen || change_fullscreen_mode)
6219 if (setup.fullscreen != video.fullscreen_enabled ||
6220 setup.fullscreen_mode != video.fullscreen_mode_current)
6223 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6225 /* save backbuffer content which gets lost when toggling fullscreen mode */
6226 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6229 if (change_fullscreen_mode)
6231 if (setup.fullscreen && video.fullscreen_enabled)
6234 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6236 /* (this is now set in sdl.c) */
6238 video.fullscreen_mode_current = setup.fullscreen_mode;
6240 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6243 /* toggle fullscreen */
6244 ChangeVideoModeIfNeeded(setup.fullscreen);
6246 setup.fullscreen = video.fullscreen_enabled;
6248 /* restore backbuffer content from temporary backbuffer backup bitmap */
6249 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6251 FreeBitmap(tmp_backbuffer);
6254 /* update visible window/screen */
6255 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6257 redraw_mask = REDRAW_ALL;