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 = fading.fade_delay;
537 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
539 draw_border_function = DrawMaskedBorder_FIELD;
541 else /* REDRAW_ALL */
548 fade_delay = fading.fade_delay;
549 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
552 redraw_mask |= fade_mask;
555 if (fading.anim_mode == ANIM_NONE)
560 if (!setup.fade_screens || fade_delay == 0)
562 if (!setup.fade_screens || fade_delay == 0 || fading.anim_mode == ANIM_NONE)
565 if (fade_mode == FADE_MODE_FADE_OUT)
566 ClearRectangle(backbuffer, x, y, width, height);
573 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
574 draw_border_function);
576 redraw_mask &= ~fade_mask;
579 void FadeIn(int fade_mask)
581 FadeExt(fade_mask, FADE_MODE_FADE_IN);
584 void FadeOut(int fade_mask)
586 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
589 void FadeCross(int fade_mask)
591 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
594 void FadeCrossSaveBackbuffer()
596 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
599 void SetWindowBackgroundImageIfDefined(int graphic)
601 if (graphic_info[graphic].bitmap)
602 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
605 void SetMainBackgroundImageIfDefined(int graphic)
607 if (graphic_info[graphic].bitmap)
608 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
611 void SetDoorBackgroundImageIfDefined(int graphic)
613 if (graphic_info[graphic].bitmap)
614 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
617 void SetWindowBackgroundImage(int graphic)
619 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
620 graphic_info[graphic].bitmap ?
621 graphic_info[graphic].bitmap :
622 graphic_info[IMG_BACKGROUND].bitmap);
625 void SetMainBackgroundImage(int graphic)
627 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
628 graphic_info[graphic].bitmap ?
629 graphic_info[graphic].bitmap :
630 graphic_info[IMG_BACKGROUND].bitmap);
633 void SetDoorBackgroundImage(int graphic)
635 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
636 graphic_info[graphic].bitmap ?
637 graphic_info[graphic].bitmap :
638 graphic_info[IMG_BACKGROUND].bitmap);
641 void SetPanelBackground()
643 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
644 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
646 SetDoorBackgroundBitmap(bitmap_db_panel);
649 void DrawBackground(int x, int y, int width, int height)
651 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
652 /* (when entering hall of fame after playing) */
654 ClearRectangleOnBackground(drawto, x, y, width, height);
656 ClearRectangleOnBackground(backbuffer, x, y, width, height);
659 redraw_mask |= REDRAW_FIELD;
662 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
664 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
666 if (font->bitmap == NULL)
669 DrawBackground(x, y, width, height);
672 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
674 struct GraphicInfo *g = &graphic_info[graphic];
676 if (g->bitmap == NULL)
679 DrawBackground(x, y, width, height);
684 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
685 /* (when entering hall of fame after playing) */
686 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
688 /* !!! maybe this should be done before clearing the background !!! */
689 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
691 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
692 SetDrawtoField(DRAW_BUFFERED);
695 SetDrawtoField(DRAW_BACKBUFFER);
697 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
699 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
700 SetDrawtoField(DRAW_DIRECT);
704 void MarkTileDirty(int x, int y)
706 int xx = redraw_x1 + x;
707 int yy = redraw_y1 + y;
712 redraw[xx][yy] = TRUE;
713 redraw_mask |= REDRAW_TILES;
716 void SetBorderElement()
720 BorderElement = EL_EMPTY;
722 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
724 for (x = 0; x < lev_fieldx; x++)
726 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
727 BorderElement = EL_STEELWALL;
729 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
735 void FloodFillLevel(int from_x, int from_y, int fill_element,
736 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
737 int max_fieldx, int max_fieldy)
741 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
742 static int safety = 0;
744 /* check if starting field still has the desired content */
745 if (field[from_x][from_y] == fill_element)
750 if (safety > max_fieldx * max_fieldy)
751 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
753 old_element = field[from_x][from_y];
754 field[from_x][from_y] = fill_element;
756 for (i = 0; i < 4; i++)
758 x = from_x + check[i][0];
759 y = from_y + check[i][1];
761 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
762 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
768 void SetRandomAnimationValue(int x, int y)
770 gfx.anim_random_frame = GfxRandom[x][y];
773 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
775 /* animation synchronized with global frame counter, not move position */
776 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
777 sync_frame = FrameCounter;
779 return getAnimationFrame(graphic_info[graphic].anim_frames,
780 graphic_info[graphic].anim_delay,
781 graphic_info[graphic].anim_mode,
782 graphic_info[graphic].anim_start_frame,
786 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
787 int *x, int *y, boolean get_backside)
789 struct GraphicInfo *g = &graphic_info[graphic];
790 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
791 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
795 if (g->offset_y == 0) /* frames are ordered horizontally */
797 int max_width = g->anim_frames_per_line * g->width;
798 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
800 *x = pos % max_width;
801 *y = src_y % g->height + pos / max_width * g->height;
803 else if (g->offset_x == 0) /* frames are ordered vertically */
805 int max_height = g->anim_frames_per_line * g->height;
806 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
808 *x = src_x % g->width + pos / max_height * g->width;
809 *y = pos % max_height;
811 else /* frames are ordered diagonally */
813 *x = src_x + frame * g->offset_x;
814 *y = src_y + frame * g->offset_y;
818 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
820 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
823 void DrawGraphic(int x, int y, int graphic, int frame)
826 if (!IN_SCR_FIELD(x, y))
828 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
829 printf("DrawGraphic(): This should never happen!\n");
834 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
838 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
844 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
845 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
848 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
851 if (!IN_SCR_FIELD(x, y))
853 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
854 printf("DrawGraphicThruMask(): This should never happen!\n");
859 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
864 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
870 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
872 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
873 dst_x - src_x, dst_y - src_y);
874 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
877 void DrawMiniGraphic(int x, int y, int graphic)
879 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
880 MarkTileDirty(x / 2, y / 2);
883 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
885 struct GraphicInfo *g = &graphic_info[graphic];
887 int mini_starty = g->bitmap->height * 2 / 3;
890 *x = mini_startx + g->src_x / 2;
891 *y = mini_starty + g->src_y / 2;
894 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
899 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
900 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
903 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
904 int graphic, int frame,
905 int cut_mode, int mask_mode)
910 int width = TILEX, height = TILEY;
913 if (dx || dy) /* shifted graphic */
915 if (x < BX1) /* object enters playfield from the left */
922 else if (x > BX2) /* object enters playfield from the right */
928 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
934 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
936 else if (dx) /* general horizontal movement */
937 MarkTileDirty(x + SIGN(dx), y);
939 if (y < BY1) /* object enters playfield from the top */
941 if (cut_mode==CUT_BELOW) /* object completely above top border */
949 else if (y > BY2) /* object enters playfield from the bottom */
955 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
961 else if (dy > 0 && cut_mode == CUT_ABOVE)
963 if (y == BY2) /* object completely above bottom border */
969 MarkTileDirty(x, y + 1);
970 } /* object leaves playfield to the bottom */
971 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
973 else if (dy) /* general vertical movement */
974 MarkTileDirty(x, y + SIGN(dy));
978 if (!IN_SCR_FIELD(x, y))
980 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
981 printf("DrawGraphicShifted(): This should never happen!\n");
986 if (width > 0 && height > 0)
988 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
993 dst_x = FX + x * TILEX + dx;
994 dst_y = FY + y * TILEY + dy;
996 if (mask_mode == USE_MASKING)
998 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
999 dst_x - src_x, dst_y - src_y);
1000 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1004 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1007 MarkTileDirty(x, y);
1011 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1012 int graphic, int frame,
1013 int cut_mode, int mask_mode)
1018 int width = TILEX, height = TILEY;
1021 int x2 = x + SIGN(dx);
1022 int y2 = y + SIGN(dy);
1023 int anim_frames = graphic_info[graphic].anim_frames;
1024 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1025 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1026 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1028 /* re-calculate animation frame for two-tile movement animation */
1029 frame = getGraphicAnimationFrame(graphic, sync_frame);
1031 /* check if movement start graphic inside screen area and should be drawn */
1032 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1034 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1036 dst_x = FX + x1 * TILEX;
1037 dst_y = FY + y1 * TILEY;
1039 if (mask_mode == USE_MASKING)
1041 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1042 dst_x - src_x, dst_y - src_y);
1043 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1047 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1050 MarkTileDirty(x1, y1);
1053 /* check if movement end graphic inside screen area and should be drawn */
1054 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1056 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1058 dst_x = FX + x2 * TILEX;
1059 dst_y = FY + y2 * TILEY;
1061 if (mask_mode == USE_MASKING)
1063 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1064 dst_x - src_x, dst_y - src_y);
1065 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1069 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1072 MarkTileDirty(x2, y2);
1076 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1077 int graphic, int frame,
1078 int cut_mode, int mask_mode)
1082 DrawGraphic(x, y, graphic, frame);
1087 if (graphic_info[graphic].double_movement) /* EM style movement images */
1088 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1090 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1093 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1094 int frame, int cut_mode)
1096 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1099 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1100 int cut_mode, int mask_mode)
1102 int lx = LEVELX(x), ly = LEVELY(y);
1106 if (IN_LEV_FIELD(lx, ly))
1108 SetRandomAnimationValue(lx, ly);
1110 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1111 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1113 /* do not use double (EM style) movement graphic when not moving */
1114 if (graphic_info[graphic].double_movement && !dx && !dy)
1116 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1117 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1120 else /* border element */
1122 graphic = el2img(element);
1123 frame = getGraphicAnimationFrame(graphic, -1);
1126 if (element == EL_EXPANDABLE_WALL)
1128 boolean left_stopped = FALSE, right_stopped = FALSE;
1130 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1131 left_stopped = TRUE;
1132 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1133 right_stopped = TRUE;
1135 if (left_stopped && right_stopped)
1137 else if (left_stopped)
1139 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1140 frame = graphic_info[graphic].anim_frames - 1;
1142 else if (right_stopped)
1144 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1145 frame = graphic_info[graphic].anim_frames - 1;
1150 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1151 else if (mask_mode == USE_MASKING)
1152 DrawGraphicThruMask(x, y, graphic, frame);
1154 DrawGraphic(x, y, graphic, frame);
1157 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1158 int cut_mode, int mask_mode)
1160 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1161 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1162 cut_mode, mask_mode);
1165 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1168 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1171 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1174 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1177 void DrawLevelElementThruMask(int x, int y, int element)
1179 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1182 void DrawLevelFieldThruMask(int x, int y)
1184 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1187 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1191 int sx = SCREENX(x), sy = SCREENY(y);
1193 int width, height, cx, cy, i;
1194 int crumbled_border_size = graphic_info[graphic].border_size;
1195 static int xy[4][2] =
1203 if (!IN_LEV_FIELD(x, y))
1206 element = TILE_GFX_ELEMENT(x, y);
1208 /* crumble field itself */
1209 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1211 if (!IN_SCR_FIELD(sx, sy))
1214 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1216 for (i = 0; i < 4; i++)
1218 int xx = x + xy[i][0];
1219 int yy = y + xy[i][1];
1221 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1224 /* check if neighbour field is of same type */
1225 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1228 if (i == 1 || i == 2)
1230 width = crumbled_border_size;
1232 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1238 height = crumbled_border_size;
1240 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1243 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1244 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1247 MarkTileDirty(sx, sy);
1249 else /* crumble neighbour fields */
1251 for (i = 0; i < 4; i++)
1253 int xx = x + xy[i][0];
1254 int yy = y + xy[i][1];
1255 int sxx = sx + xy[i][0];
1256 int syy = sy + xy[i][1];
1258 if (!IN_LEV_FIELD(xx, yy) ||
1259 !IN_SCR_FIELD(sxx, syy) ||
1263 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1266 element = TILE_GFX_ELEMENT(xx, yy);
1268 if (!GFX_CRUMBLED(element))
1271 graphic = el_act2crm(element, ACTION_DEFAULT);
1272 crumbled_border_size = graphic_info[graphic].border_size;
1274 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1276 if (i == 1 || i == 2)
1278 width = crumbled_border_size;
1280 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1286 height = crumbled_border_size;
1288 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1291 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1292 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1294 MarkTileDirty(sxx, syy);
1299 void DrawLevelFieldCrumbledSand(int x, int y)
1303 if (!IN_LEV_FIELD(x, y))
1307 /* !!! CHECK THIS !!! */
1310 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1311 GFX_CRUMBLED(GfxElement[x][y]))
1314 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1315 GfxElement[x][y] != EL_UNDEFINED &&
1316 GFX_CRUMBLED(GfxElement[x][y]))
1318 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1325 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1327 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1330 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1333 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1336 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1337 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1338 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1339 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1340 int sx = SCREENX(x), sy = SCREENY(y);
1342 DrawGraphic(sx, sy, graphic1, frame1);
1343 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1346 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1348 int sx = SCREENX(x), sy = SCREENY(y);
1349 static int xy[4][2] =
1358 for (i = 0; i < 4; i++)
1360 int xx = x + xy[i][0];
1361 int yy = y + xy[i][1];
1362 int sxx = sx + xy[i][0];
1363 int syy = sy + xy[i][1];
1365 if (!IN_LEV_FIELD(xx, yy) ||
1366 !IN_SCR_FIELD(sxx, syy) ||
1367 !GFX_CRUMBLED(Feld[xx][yy]) ||
1371 DrawLevelField(xx, yy);
1375 static int getBorderElement(int x, int y)
1379 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1380 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1381 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1382 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1383 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1384 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1385 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1387 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1388 int steel_position = (x == -1 && y == -1 ? 0 :
1389 x == lev_fieldx && y == -1 ? 1 :
1390 x == -1 && y == lev_fieldy ? 2 :
1391 x == lev_fieldx && y == lev_fieldy ? 3 :
1392 x == -1 || x == lev_fieldx ? 4 :
1393 y == -1 || y == lev_fieldy ? 5 : 6);
1395 return border[steel_position][steel_type];
1398 void DrawScreenElement(int x, int y, int element)
1400 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1401 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1404 void DrawLevelElement(int x, int y, int element)
1406 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1407 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1410 void DrawScreenField(int x, int y)
1412 int lx = LEVELX(x), ly = LEVELY(y);
1413 int element, content;
1415 if (!IN_LEV_FIELD(lx, ly))
1417 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1420 element = getBorderElement(lx, ly);
1422 DrawScreenElement(x, y, element);
1426 element = Feld[lx][ly];
1427 content = Store[lx][ly];
1429 if (IS_MOVING(lx, ly))
1431 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1432 boolean cut_mode = NO_CUTTING;
1434 if (element == EL_QUICKSAND_EMPTYING ||
1435 element == EL_QUICKSAND_FAST_EMPTYING ||
1436 element == EL_MAGIC_WALL_EMPTYING ||
1437 element == EL_BD_MAGIC_WALL_EMPTYING ||
1438 element == EL_DC_MAGIC_WALL_EMPTYING ||
1439 element == EL_AMOEBA_DROPPING)
1440 cut_mode = CUT_ABOVE;
1441 else if (element == EL_QUICKSAND_FILLING ||
1442 element == EL_QUICKSAND_FAST_FILLING ||
1443 element == EL_MAGIC_WALL_FILLING ||
1444 element == EL_BD_MAGIC_WALL_FILLING ||
1445 element == EL_DC_MAGIC_WALL_FILLING)
1446 cut_mode = CUT_BELOW;
1448 if (cut_mode == CUT_ABOVE)
1449 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1451 DrawScreenElement(x, y, EL_EMPTY);
1454 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1455 else if (cut_mode == NO_CUTTING)
1456 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1458 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1460 if (content == EL_ACID)
1462 int dir = MovDir[lx][ly];
1463 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1464 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1466 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1469 else if (IS_BLOCKED(lx, ly))
1474 boolean cut_mode = NO_CUTTING;
1475 int element_old, content_old;
1477 Blocked2Moving(lx, ly, &oldx, &oldy);
1480 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1481 MovDir[oldx][oldy] == MV_RIGHT);
1483 element_old = Feld[oldx][oldy];
1484 content_old = Store[oldx][oldy];
1486 if (element_old == EL_QUICKSAND_EMPTYING ||
1487 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1488 element_old == EL_MAGIC_WALL_EMPTYING ||
1489 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1490 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1491 element_old == EL_AMOEBA_DROPPING)
1492 cut_mode = CUT_ABOVE;
1494 DrawScreenElement(x, y, EL_EMPTY);
1497 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1499 else if (cut_mode == NO_CUTTING)
1500 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1503 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1506 else if (IS_DRAWABLE(element))
1507 DrawScreenElement(x, y, element);
1509 DrawScreenElement(x, y, EL_EMPTY);
1512 void DrawLevelField(int x, int y)
1514 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1515 DrawScreenField(SCREENX(x), SCREENY(y));
1516 else if (IS_MOVING(x, y))
1520 Moving2Blocked(x, y, &newx, &newy);
1521 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1522 DrawScreenField(SCREENX(newx), SCREENY(newy));
1524 else if (IS_BLOCKED(x, y))
1528 Blocked2Moving(x, y, &oldx, &oldy);
1529 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1530 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1534 void DrawMiniElement(int x, int y, int element)
1538 graphic = el2edimg(element);
1539 DrawMiniGraphic(x, y, graphic);
1542 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1544 int x = sx + scroll_x, y = sy + scroll_y;
1546 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1547 DrawMiniElement(sx, sy, EL_EMPTY);
1548 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1549 DrawMiniElement(sx, sy, Feld[x][y]);
1551 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1554 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1555 int x, int y, int xsize, int ysize, int font_nr)
1557 int font_width = getFontWidth(font_nr);
1558 int font_height = getFontHeight(font_nr);
1559 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1562 int dst_x = SX + startx + x * font_width;
1563 int dst_y = SY + starty + y * font_height;
1564 int width = graphic_info[graphic].width;
1565 int height = graphic_info[graphic].height;
1566 int inner_width = MAX(width - 2 * font_width, font_width);
1567 int inner_height = MAX(height - 2 * font_height, font_height);
1568 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1569 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1570 boolean draw_masked = graphic_info[graphic].draw_masked;
1572 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1574 if (src_bitmap == NULL || width < font_width || height < font_height)
1576 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1580 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1581 inner_sx + (x - 1) * font_width % inner_width);
1582 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1583 inner_sy + (y - 1) * font_height % inner_height);
1587 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1588 dst_x - src_x, dst_y - src_y);
1589 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1593 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1597 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1599 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1600 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1601 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1602 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1603 boolean no_delay = (tape.warp_forward);
1604 unsigned long anim_delay = 0;
1605 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1606 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1607 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1608 int font_width = getFontWidth(font_nr);
1609 int font_height = getFontHeight(font_nr);
1610 int max_xsize = level.envelope[envelope_nr].xsize;
1611 int max_ysize = level.envelope[envelope_nr].ysize;
1612 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1613 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1614 int xend = max_xsize;
1615 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1616 int xstep = (xstart < xend ? 1 : 0);
1617 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1620 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1622 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1623 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1624 int sx = (SXSIZE - xsize * font_width) / 2;
1625 int sy = (SYSIZE - ysize * font_height) / 2;
1628 SetDrawtoField(DRAW_BUFFERED);
1630 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1632 SetDrawtoField(DRAW_BACKBUFFER);
1634 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1635 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1638 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1639 level.envelope[envelope_nr].text, font_nr, max_xsize,
1640 xsize - 2, ysize - 2, mask_mode,
1641 level.envelope[envelope_nr].autowrap,
1642 level.envelope[envelope_nr].centered, FALSE);
1644 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1645 level.envelope[envelope_nr].text, font_nr, max_xsize,
1646 xsize - 2, ysize - 2, mask_mode);
1649 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1652 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1656 void ShowEnvelope(int envelope_nr)
1658 int element = EL_ENVELOPE_1 + envelope_nr;
1659 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1660 int sound_opening = element_info[element].sound[ACTION_OPENING];
1661 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1662 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1663 boolean no_delay = (tape.warp_forward);
1664 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1665 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1666 int anim_mode = graphic_info[graphic].anim_mode;
1667 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1668 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1670 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1672 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1674 if (anim_mode == ANIM_DEFAULT)
1675 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1677 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1680 Delay(wait_delay_value);
1682 WaitForEventToContinue();
1684 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1686 if (anim_mode != ANIM_NONE)
1687 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1689 if (anim_mode == ANIM_DEFAULT)
1690 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1692 game.envelope_active = FALSE;
1694 SetDrawtoField(DRAW_BUFFERED);
1696 redraw_mask |= REDRAW_FIELD;
1700 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1705 int width_mult, width_div;
1706 int height_mult, height_div;
1714 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1715 5 - log_2(tilesize));
1716 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1717 int width_mult = offset_calc[offset_calc_pos].width_mult;
1718 int width_div = offset_calc[offset_calc_pos].width_div;
1719 int height_mult = offset_calc[offset_calc_pos].height_mult;
1720 int height_div = offset_calc[offset_calc_pos].height_div;
1721 int mini_startx = src_bitmap->width * width_mult / width_div;
1722 int mini_starty = src_bitmap->height * height_mult / height_div;
1723 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1724 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1726 *bitmap = src_bitmap;
1731 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1735 int graphic = el2preimg(element);
1737 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1738 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1745 SetDrawBackgroundMask(REDRAW_NONE);
1748 for (x = BX1; x <= BX2; x++)
1749 for (y = BY1; y <= BY2; y++)
1750 DrawScreenField(x, y);
1752 redraw_mask |= REDRAW_FIELD;
1755 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1759 for (x = 0; x < size_x; x++)
1760 for (y = 0; y < size_y; y++)
1761 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1763 redraw_mask |= REDRAW_FIELD;
1766 static void DrawPreviewLevelExt(int from_x, int from_y)
1768 boolean show_level_border = (BorderElement != EL_EMPTY);
1769 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1770 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1771 int tile_size = preview.tile_size;
1772 int preview_width = preview.xsize * tile_size;
1773 int preview_height = preview.ysize * tile_size;
1774 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1775 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1776 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1777 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1780 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1782 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1783 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1785 for (x = 0; x < real_preview_xsize; x++)
1787 for (y = 0; y < real_preview_ysize; y++)
1789 int lx = from_x + x + (show_level_border ? -1 : 0);
1790 int ly = from_y + y + (show_level_border ? -1 : 0);
1791 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1792 getBorderElement(lx, ly));
1794 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1795 element, tile_size);
1799 redraw_mask |= REDRAW_MICROLEVEL;
1802 #define MICROLABEL_EMPTY 0
1803 #define MICROLABEL_LEVEL_NAME 1
1804 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1805 #define MICROLABEL_LEVEL_AUTHOR 3
1806 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1807 #define MICROLABEL_IMPORTED_FROM 5
1808 #define MICROLABEL_IMPORTED_BY_HEAD 6
1809 #define MICROLABEL_IMPORTED_BY 7
1811 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
1813 int max_text_width = SXSIZE;
1814 int font_width = getFontWidth(font_nr);
1816 if (pos->align == ALIGN_CENTER)
1817 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1818 else if (pos->align == ALIGN_RIGHT)
1819 max_text_width = pos->x;
1821 max_text_width = SXSIZE - pos->x;
1823 return max_text_width / font_width;
1826 static void DrawPreviewLevelLabelExt(int mode)
1828 struct TextPosInfo *pos = &menu.main.text.level_info_2;
1829 char label_text[MAX_OUTPUT_LINESIZE + 1];
1830 int max_len_label_text;
1832 int font_nr = pos->font;
1835 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1836 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1837 mode == MICROLABEL_IMPORTED_BY_HEAD)
1838 font_nr = pos->font_alt;
1840 int font_nr = FONT_TEXT_2;
1843 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1844 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1845 mode == MICROLABEL_IMPORTED_BY_HEAD)
1846 font_nr = FONT_TEXT_3;
1850 max_len_label_text = getMaxTextLength(pos, font_nr);
1852 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1856 if (pos->chars != -1)
1857 max_len_label_text = pos->chars;
1860 for (i = 0; i < max_len_label_text; i++)
1861 label_text[i] = ' ';
1862 label_text[max_len_label_text] = '\0';
1864 if (strlen(label_text) > 0)
1867 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1869 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1870 int lypos = MICROLABEL2_YPOS;
1872 DrawText(lxpos, lypos, label_text, font_nr);
1877 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1878 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1879 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1880 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1881 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1882 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1883 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1884 max_len_label_text);
1885 label_text[max_len_label_text] = '\0';
1887 if (strlen(label_text) > 0)
1890 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1892 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1893 int lypos = MICROLABEL2_YPOS;
1895 DrawText(lxpos, lypos, label_text, font_nr);
1899 redraw_mask |= REDRAW_MICROLEVEL;
1902 void DrawPreviewLevel(boolean restart)
1904 static unsigned long scroll_delay = 0;
1905 static unsigned long label_delay = 0;
1906 static int from_x, from_y, scroll_direction;
1907 static int label_state, label_counter;
1908 unsigned long scroll_delay_value = preview.step_delay;
1909 boolean show_level_border = (BorderElement != EL_EMPTY);
1910 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1911 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1912 int last_game_status = game_status; /* save current game status */
1915 /* force PREVIEW font on preview level */
1916 game_status = GAME_MODE_PSEUDO_PREVIEW;
1924 if (preview.anim_mode == ANIM_CENTERED)
1926 if (level_xsize > preview.xsize)
1927 from_x = (level_xsize - preview.xsize) / 2;
1928 if (level_ysize > preview.ysize)
1929 from_y = (level_ysize - preview.ysize) / 2;
1932 from_x += preview.xoffset;
1933 from_y += preview.yoffset;
1935 scroll_direction = MV_RIGHT;
1939 DrawPreviewLevelExt(from_x, from_y);
1940 DrawPreviewLevelLabelExt(label_state);
1942 /* initialize delay counters */
1943 DelayReached(&scroll_delay, 0);
1944 DelayReached(&label_delay, 0);
1946 if (leveldir_current->name)
1948 struct TextPosInfo *pos = &menu.main.text.level_info_1;
1949 char label_text[MAX_OUTPUT_LINESIZE + 1];
1951 int font_nr = pos->font;
1953 int font_nr = FONT_TEXT_1;
1956 int max_len_label_text = getMaxTextLength(pos, font_nr);
1958 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1966 if (pos->chars != -1)
1967 max_len_label_text = pos->chars;
1970 strncpy(label_text, leveldir_current->name, max_len_label_text);
1971 label_text[max_len_label_text] = '\0';
1974 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1976 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1977 lypos = SY + MICROLABEL1_YPOS;
1979 DrawText(lxpos, lypos, label_text, font_nr);
1983 game_status = last_game_status; /* restore current game status */
1988 /* scroll preview level, if needed */
1989 if (preview.anim_mode != ANIM_NONE &&
1990 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1991 DelayReached(&scroll_delay, scroll_delay_value))
1993 switch (scroll_direction)
1998 from_x -= preview.step_offset;
1999 from_x = (from_x < 0 ? 0 : from_x);
2002 scroll_direction = MV_UP;
2006 if (from_x < level_xsize - preview.xsize)
2008 from_x += preview.step_offset;
2009 from_x = (from_x > level_xsize - preview.xsize ?
2010 level_xsize - preview.xsize : from_x);
2013 scroll_direction = MV_DOWN;
2019 from_y -= preview.step_offset;
2020 from_y = (from_y < 0 ? 0 : from_y);
2023 scroll_direction = MV_RIGHT;
2027 if (from_y < level_ysize - preview.ysize)
2029 from_y += preview.step_offset;
2030 from_y = (from_y > level_ysize - preview.ysize ?
2031 level_ysize - preview.ysize : from_y);
2034 scroll_direction = MV_LEFT;
2041 DrawPreviewLevelExt(from_x, from_y);
2044 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2045 /* redraw micro level label, if needed */
2046 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2047 !strEqual(level.author, ANONYMOUS_NAME) &&
2048 !strEqual(level.author, leveldir_current->name) &&
2049 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2051 int max_label_counter = 23;
2053 if (leveldir_current->imported_from != NULL &&
2054 strlen(leveldir_current->imported_from) > 0)
2055 max_label_counter += 14;
2056 if (leveldir_current->imported_by != NULL &&
2057 strlen(leveldir_current->imported_by) > 0)
2058 max_label_counter += 14;
2060 label_counter = (label_counter + 1) % max_label_counter;
2061 label_state = (label_counter >= 0 && label_counter <= 7 ?
2062 MICROLABEL_LEVEL_NAME :
2063 label_counter >= 9 && label_counter <= 12 ?
2064 MICROLABEL_LEVEL_AUTHOR_HEAD :
2065 label_counter >= 14 && label_counter <= 21 ?
2066 MICROLABEL_LEVEL_AUTHOR :
2067 label_counter >= 23 && label_counter <= 26 ?
2068 MICROLABEL_IMPORTED_FROM_HEAD :
2069 label_counter >= 28 && label_counter <= 35 ?
2070 MICROLABEL_IMPORTED_FROM :
2071 label_counter >= 37 && label_counter <= 40 ?
2072 MICROLABEL_IMPORTED_BY_HEAD :
2073 label_counter >= 42 && label_counter <= 49 ?
2074 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2076 if (leveldir_current->imported_from == NULL &&
2077 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2078 label_state == MICROLABEL_IMPORTED_FROM))
2079 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2080 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2082 DrawPreviewLevelLabelExt(label_state);
2085 game_status = last_game_status; /* restore current game status */
2088 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2089 int graphic, int sync_frame, int mask_mode)
2091 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2093 if (mask_mode == USE_MASKING)
2094 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2096 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2099 inline void DrawGraphicAnimation(int x, int y, int graphic)
2101 int lx = LEVELX(x), ly = LEVELY(y);
2103 if (!IN_SCR_FIELD(x, y))
2106 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2107 graphic, GfxFrame[lx][ly], NO_MASKING);
2108 MarkTileDirty(x, y);
2111 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2113 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2116 void DrawLevelElementAnimation(int x, int y, int element)
2118 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2120 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2123 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2125 int sx = SCREENX(x), sy = SCREENY(y);
2127 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2130 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2133 DrawGraphicAnimation(sx, sy, graphic);
2136 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2137 DrawLevelFieldCrumbledSand(x, y);
2139 if (GFX_CRUMBLED(Feld[x][y]))
2140 DrawLevelFieldCrumbledSand(x, y);
2144 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2146 int sx = SCREENX(x), sy = SCREENY(y);
2149 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2152 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2154 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2157 DrawGraphicAnimation(sx, sy, graphic);
2159 if (GFX_CRUMBLED(element))
2160 DrawLevelFieldCrumbledSand(x, y);
2163 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2165 if (player->use_murphy)
2167 /* this works only because currently only one player can be "murphy" ... */
2168 static int last_horizontal_dir = MV_LEFT;
2169 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2171 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2172 last_horizontal_dir = move_dir;
2174 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2176 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2178 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2184 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2187 static boolean equalGraphics(int graphic1, int graphic2)
2189 struct GraphicInfo *g1 = &graphic_info[graphic1];
2190 struct GraphicInfo *g2 = &graphic_info[graphic2];
2192 return (g1->bitmap == g2->bitmap &&
2193 g1->src_x == g2->src_x &&
2194 g1->src_y == g2->src_y &&
2195 g1->anim_frames == g2->anim_frames &&
2196 g1->anim_delay == g2->anim_delay &&
2197 g1->anim_mode == g2->anim_mode);
2200 void DrawAllPlayers()
2204 for (i = 0; i < MAX_PLAYERS; i++)
2205 if (stored_player[i].active)
2206 DrawPlayer(&stored_player[i]);
2209 void DrawPlayerField(int x, int y)
2211 if (!IS_PLAYER(x, y))
2214 DrawPlayer(PLAYERINFO(x, y));
2217 void DrawPlayer(struct PlayerInfo *player)
2219 int jx = player->jx;
2220 int jy = player->jy;
2221 int move_dir = player->MovDir;
2222 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2223 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2224 int last_jx = (player->is_moving ? jx - dx : jx);
2225 int last_jy = (player->is_moving ? jy - dy : jy);
2226 int next_jx = jx + dx;
2227 int next_jy = jy + dy;
2228 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2229 boolean player_is_opaque = FALSE;
2230 int sx = SCREENX(jx), sy = SCREENY(jy);
2231 int sxx = 0, syy = 0;
2232 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2234 int action = ACTION_DEFAULT;
2235 int last_player_graphic = getPlayerGraphic(player, move_dir);
2236 int last_player_frame = player->Frame;
2239 /* GfxElement[][] is set to the element the player is digging or collecting;
2240 remove also for off-screen player if the player is not moving anymore */
2241 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2242 GfxElement[jx][jy] = EL_UNDEFINED;
2244 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2248 if (!IN_LEV_FIELD(jx, jy))
2250 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2251 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2252 printf("DrawPlayerField(): This should never happen!\n");
2257 if (element == EL_EXPLOSION)
2260 action = (player->is_pushing ? ACTION_PUSHING :
2261 player->is_digging ? ACTION_DIGGING :
2262 player->is_collecting ? ACTION_COLLECTING :
2263 player->is_moving ? ACTION_MOVING :
2264 player->is_snapping ? ACTION_SNAPPING :
2265 player->is_dropping ? ACTION_DROPPING :
2266 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2268 if (player->is_waiting)
2269 move_dir = player->dir_waiting;
2271 InitPlayerGfxAnimation(player, action, move_dir);
2273 /* ----------------------------------------------------------------------- */
2274 /* draw things in the field the player is leaving, if needed */
2275 /* ----------------------------------------------------------------------- */
2277 if (player->is_moving)
2279 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2281 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2283 if (last_element == EL_DYNAMITE_ACTIVE ||
2284 last_element == EL_EM_DYNAMITE_ACTIVE ||
2285 last_element == EL_SP_DISK_RED_ACTIVE)
2286 DrawDynamite(last_jx, last_jy);
2288 DrawLevelFieldThruMask(last_jx, last_jy);
2290 else if (last_element == EL_DYNAMITE_ACTIVE ||
2291 last_element == EL_EM_DYNAMITE_ACTIVE ||
2292 last_element == EL_SP_DISK_RED_ACTIVE)
2293 DrawDynamite(last_jx, last_jy);
2295 /* !!! this is not enough to prevent flickering of players which are
2296 moving next to each others without a free tile between them -- this
2297 can only be solved by drawing all players layer by layer (first the
2298 background, then the foreground etc.) !!! => TODO */
2299 else if (!IS_PLAYER(last_jx, last_jy))
2300 DrawLevelField(last_jx, last_jy);
2303 DrawLevelField(last_jx, last_jy);
2306 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2307 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2310 if (!IN_SCR_FIELD(sx, sy))
2313 if (setup.direct_draw)
2314 SetDrawtoField(DRAW_BUFFERED);
2316 /* ----------------------------------------------------------------------- */
2317 /* draw things behind the player, if needed */
2318 /* ----------------------------------------------------------------------- */
2321 DrawLevelElement(jx, jy, Back[jx][jy]);
2322 else if (IS_ACTIVE_BOMB(element))
2323 DrawLevelElement(jx, jy, EL_EMPTY);
2326 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2328 int old_element = GfxElement[jx][jy];
2329 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2330 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2332 if (GFX_CRUMBLED(old_element))
2333 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2335 DrawGraphic(sx, sy, old_graphic, frame);
2337 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2338 player_is_opaque = TRUE;
2342 GfxElement[jx][jy] = EL_UNDEFINED;
2344 /* make sure that pushed elements are drawn with correct frame rate */
2346 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2348 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2349 GfxFrame[jx][jy] = player->StepFrame;
2351 if (player->is_pushing && player->is_moving)
2352 GfxFrame[jx][jy] = player->StepFrame;
2355 DrawLevelField(jx, jy);
2359 /* ----------------------------------------------------------------------- */
2360 /* draw player himself */
2361 /* ----------------------------------------------------------------------- */
2363 graphic = getPlayerGraphic(player, move_dir);
2365 /* in the case of changed player action or direction, prevent the current
2366 animation frame from being restarted for identical animations */
2367 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2368 player->Frame = last_player_frame;
2370 frame = getGraphicAnimationFrame(graphic, player->Frame);
2374 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2375 sxx = player->GfxPos;
2377 syy = player->GfxPos;
2380 if (!setup.soft_scrolling && ScreenMovPos)
2383 if (player_is_opaque)
2384 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2386 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2388 if (SHIELD_ON(player))
2390 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2391 IMG_SHIELD_NORMAL_ACTIVE);
2392 int frame = getGraphicAnimationFrame(graphic, -1);
2394 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2397 /* ----------------------------------------------------------------------- */
2398 /* draw things the player is pushing, if needed */
2399 /* ----------------------------------------------------------------------- */
2402 printf("::: %d, %d [%d, %d] [%d]\n",
2403 player->is_pushing, player_is_moving, player->GfxAction,
2404 player->is_moving, player_is_moving);
2408 if (player->is_pushing && player->is_moving)
2410 int px = SCREENX(jx), py = SCREENY(jy);
2411 int pxx = (TILEX - ABS(sxx)) * dx;
2412 int pyy = (TILEY - ABS(syy)) * dy;
2413 int gfx_frame = GfxFrame[jx][jy];
2419 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2421 element = Feld[next_jx][next_jy];
2422 gfx_frame = GfxFrame[next_jx][next_jy];
2425 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2428 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2429 frame = getGraphicAnimationFrame(graphic, sync_frame);
2431 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2434 /* draw background element under pushed element (like the Sokoban field) */
2435 if (Back[next_jx][next_jy])
2436 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2438 /* masked drawing is needed for EMC style (double) movement graphics */
2439 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2443 /* ----------------------------------------------------------------------- */
2444 /* draw things in front of player (active dynamite or dynabombs) */
2445 /* ----------------------------------------------------------------------- */
2447 if (IS_ACTIVE_BOMB(element))
2449 graphic = el2img(element);
2450 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2452 if (game.emulation == EMU_SUPAPLEX)
2453 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2455 DrawGraphicThruMask(sx, sy, graphic, frame);
2458 if (player_is_moving && last_element == EL_EXPLOSION)
2460 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2461 GfxElement[last_jx][last_jy] : EL_EMPTY);
2462 int graphic = el_act2img(element, ACTION_EXPLODING);
2463 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2464 int phase = ExplodePhase[last_jx][last_jy] - 1;
2465 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2468 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2471 /* ----------------------------------------------------------------------- */
2472 /* draw elements the player is just walking/passing through/under */
2473 /* ----------------------------------------------------------------------- */
2475 if (player_is_moving)
2477 /* handle the field the player is leaving ... */
2478 if (IS_ACCESSIBLE_INSIDE(last_element))
2479 DrawLevelField(last_jx, last_jy);
2480 else if (IS_ACCESSIBLE_UNDER(last_element))
2481 DrawLevelFieldThruMask(last_jx, last_jy);
2484 /* do not redraw accessible elements if the player is just pushing them */
2485 if (!player_is_moving || !player->is_pushing)
2487 /* ... and the field the player is entering */
2488 if (IS_ACCESSIBLE_INSIDE(element))
2489 DrawLevelField(jx, jy);
2490 else if (IS_ACCESSIBLE_UNDER(element))
2491 DrawLevelFieldThruMask(jx, jy);
2494 if (setup.direct_draw)
2496 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2497 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2498 int x_size = TILEX * (1 + ABS(jx - last_jx));
2499 int y_size = TILEY * (1 + ABS(jy - last_jy));
2501 BlitBitmap(drawto_field, window,
2502 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2503 SetDrawtoField(DRAW_DIRECT);
2506 MarkTileDirty(sx, sy);
2509 /* ------------------------------------------------------------------------- */
2511 void WaitForEventToContinue()
2513 boolean still_wait = TRUE;
2515 /* simulate releasing mouse button over last gadget, if still pressed */
2517 HandleGadgets(-1, -1, 0);
2519 button_status = MB_RELEASED;
2535 case EVENT_BUTTONPRESS:
2536 case EVENT_KEYPRESS:
2540 case EVENT_KEYRELEASE:
2541 ClearPlayerAction();
2545 HandleOtherEvents(&event);
2549 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2556 /* don't eat all CPU time */
2561 #define MAX_REQUEST_LINES 13
2562 #define MAX_REQUEST_LINE_FONT1_LEN 7
2563 #define MAX_REQUEST_LINE_FONT2_LEN 10
2565 boolean Request(char *text, unsigned int req_state)
2567 int mx, my, ty, result = -1;
2568 unsigned int old_door_state;
2569 int last_game_status = game_status; /* save current game status */
2570 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2571 int font_nr = FONT_TEXT_2;
2572 int max_word_len = 0;
2575 for (text_ptr = text; *text_ptr; text_ptr++)
2577 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2579 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2581 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2583 font_nr = FONT_TEXT_1;
2585 font_nr = FONT_LEVEL_NUMBER;
2592 if (game_status == GAME_MODE_PLAYING &&
2593 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2594 BlitScreenToBitmap_EM(backbuffer);
2596 /* disable deactivated drawing when quick-loading level tape recording */
2597 if (tape.playing && tape.deactivate_display)
2598 TapeDeactivateDisplayOff(TRUE);
2600 SetMouseCursor(CURSOR_DEFAULT);
2602 #if defined(NETWORK_AVALIABLE)
2603 /* pause network game while waiting for request to answer */
2604 if (options.network &&
2605 game_status == GAME_MODE_PLAYING &&
2606 req_state & REQUEST_WAIT_FOR_INPUT)
2607 SendToServer_PausePlaying();
2610 old_door_state = GetDoorState();
2612 /* simulate releasing mouse button over last gadget, if still pressed */
2614 HandleGadgets(-1, -1, 0);
2618 if (old_door_state & DOOR_OPEN_1)
2620 CloseDoor(DOOR_CLOSE_1);
2622 /* save old door content */
2623 BlitBitmap(bitmap_db_door, bitmap_db_door,
2624 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2625 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2629 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2632 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2634 /* clear door drawing field */
2635 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2637 /* force DOOR font inside door area */
2638 game_status = GAME_MODE_PSEUDO_DOOR;
2640 /* write text for request */
2641 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2643 char text_line[max_request_line_len + 1];
2649 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2652 if (!tc || tc == ' ')
2663 strncpy(text_line, text, tl);
2666 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2667 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2668 text_line, font_nr);
2670 text += tl + (tc == ' ' ? 1 : 0);
2673 game_status = last_game_status; /* restore current game status */
2675 if (req_state & REQ_ASK)
2677 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2678 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2680 else if (req_state & REQ_CONFIRM)
2682 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2684 else if (req_state & REQ_PLAYER)
2686 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2687 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2688 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2689 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2692 /* copy request gadgets to door backbuffer */
2693 BlitBitmap(drawto, bitmap_db_door,
2694 DX, DY, DXSIZE, DYSIZE,
2695 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2697 OpenDoor(DOOR_OPEN_1);
2699 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2701 if (game_status == GAME_MODE_PLAYING)
2703 SetPanelBackground();
2704 SetDrawBackgroundMask(REDRAW_DOOR_1);
2708 SetDrawBackgroundMask(REDRAW_FIELD);
2714 if (game_status != GAME_MODE_MAIN)
2717 button_status = MB_RELEASED;
2719 request_gadget_id = -1;
2721 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2733 case EVENT_BUTTONPRESS:
2734 case EVENT_BUTTONRELEASE:
2735 case EVENT_MOTIONNOTIFY:
2737 if (event.type == EVENT_MOTIONNOTIFY)
2739 if (!PointerInWindow(window))
2740 continue; /* window and pointer are on different screens */
2745 motion_status = TRUE;
2746 mx = ((MotionEvent *) &event)->x;
2747 my = ((MotionEvent *) &event)->y;
2751 motion_status = FALSE;
2752 mx = ((ButtonEvent *) &event)->x;
2753 my = ((ButtonEvent *) &event)->y;
2754 if (event.type == EVENT_BUTTONPRESS)
2755 button_status = ((ButtonEvent *) &event)->button;
2757 button_status = MB_RELEASED;
2760 /* this sets 'request_gadget_id' */
2761 HandleGadgets(mx, my, button_status);
2763 switch (request_gadget_id)
2765 case TOOL_CTRL_ID_YES:
2768 case TOOL_CTRL_ID_NO:
2771 case TOOL_CTRL_ID_CONFIRM:
2772 result = TRUE | FALSE;
2775 case TOOL_CTRL_ID_PLAYER_1:
2778 case TOOL_CTRL_ID_PLAYER_2:
2781 case TOOL_CTRL_ID_PLAYER_3:
2784 case TOOL_CTRL_ID_PLAYER_4:
2795 case EVENT_KEYPRESS:
2796 switch (GetEventKey((KeyEvent *)&event, TRUE))
2809 if (req_state & REQ_PLAYER)
2813 case EVENT_KEYRELEASE:
2814 ClearPlayerAction();
2818 HandleOtherEvents(&event);
2822 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2824 int joy = AnyJoystick();
2826 if (joy & JOY_BUTTON_1)
2828 else if (joy & JOY_BUTTON_2)
2834 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2836 HandleGameActions();
2843 if (!PendingEvent()) /* delay only if no pending events */
2852 if (!PendingEvent()) /* delay only if no pending events */
2855 /* don't eat all CPU time */
2862 if (game_status != GAME_MODE_MAIN)
2867 if (!(req_state & REQ_STAY_OPEN))
2869 CloseDoor(DOOR_CLOSE_1);
2871 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2872 (req_state & REQ_REOPEN))
2873 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2878 if (game_status == GAME_MODE_PLAYING)
2880 SetPanelBackground();
2881 SetDrawBackgroundMask(REDRAW_DOOR_1);
2885 SetDrawBackgroundMask(REDRAW_FIELD);
2888 #if defined(NETWORK_AVALIABLE)
2889 /* continue network game after request */
2890 if (options.network &&
2891 game_status == GAME_MODE_PLAYING &&
2892 req_state & REQUEST_WAIT_FOR_INPUT)
2893 SendToServer_ContinuePlaying();
2896 /* restore deactivated drawing when quick-loading level tape recording */
2897 if (tape.playing && tape.deactivate_display)
2898 TapeDeactivateDisplayOn();
2903 unsigned int OpenDoor(unsigned int door_state)
2905 if (door_state & DOOR_COPY_BACK)
2907 if (door_state & DOOR_OPEN_1)
2908 BlitBitmap(bitmap_db_door, bitmap_db_door,
2909 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2910 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2912 if (door_state & DOOR_OPEN_2)
2913 BlitBitmap(bitmap_db_door, bitmap_db_door,
2914 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2915 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2917 door_state &= ~DOOR_COPY_BACK;
2920 return MoveDoor(door_state);
2923 unsigned int CloseDoor(unsigned int door_state)
2925 unsigned int old_door_state = GetDoorState();
2927 if (!(door_state & DOOR_NO_COPY_BACK))
2929 if (old_door_state & DOOR_OPEN_1)
2930 BlitBitmap(backbuffer, bitmap_db_door,
2931 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2933 if (old_door_state & DOOR_OPEN_2)
2934 BlitBitmap(backbuffer, bitmap_db_door,
2935 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2937 door_state &= ~DOOR_NO_COPY_BACK;
2940 return MoveDoor(door_state);
2943 unsigned int GetDoorState()
2945 return MoveDoor(DOOR_GET_STATE);
2948 unsigned int SetDoorState(unsigned int door_state)
2950 return MoveDoor(door_state | DOOR_SET_STATE);
2953 unsigned int MoveDoor(unsigned int door_state)
2955 static int door1 = DOOR_OPEN_1;
2956 static int door2 = DOOR_CLOSE_2;
2957 unsigned long door_delay = 0;
2958 unsigned long door_delay_value;
2961 if (door_1.width < 0 || door_1.width > DXSIZE)
2962 door_1.width = DXSIZE;
2963 if (door_1.height < 0 || door_1.height > DYSIZE)
2964 door_1.height = DYSIZE;
2965 if (door_2.width < 0 || door_2.width > VXSIZE)
2966 door_2.width = VXSIZE;
2967 if (door_2.height < 0 || door_2.height > VYSIZE)
2968 door_2.height = VYSIZE;
2970 if (door_state == DOOR_GET_STATE)
2971 return (door1 | door2);
2973 if (door_state & DOOR_SET_STATE)
2975 if (door_state & DOOR_ACTION_1)
2976 door1 = door_state & DOOR_ACTION_1;
2977 if (door_state & DOOR_ACTION_2)
2978 door2 = door_state & DOOR_ACTION_2;
2980 return (door1 | door2);
2983 if (!(door_state & DOOR_FORCE_REDRAW))
2985 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2986 door_state &= ~DOOR_OPEN_1;
2987 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2988 door_state &= ~DOOR_CLOSE_1;
2989 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2990 door_state &= ~DOOR_OPEN_2;
2991 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2992 door_state &= ~DOOR_CLOSE_2;
2995 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2998 if (setup.quick_doors)
3000 stepsize = 20; /* must be chosen to always draw last frame */
3001 door_delay_value = 0;
3004 if (global.autoplay_leveldir)
3006 door_state |= DOOR_NO_DELAY;
3007 door_state &= ~DOOR_CLOSE_ALL;
3010 if (door_state & DOOR_ACTION)
3012 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3013 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3014 boolean door_1_done = (!handle_door_1);
3015 boolean door_2_done = (!handle_door_2);
3016 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3017 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3018 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3019 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3020 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3021 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3022 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3023 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3024 int door_skip = max_door_size - door_size;
3025 int end = door_size;
3026 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3029 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3031 /* opening door sound has priority over simultaneously closing door */
3032 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3033 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3034 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3035 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3038 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3041 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3042 GC gc = bitmap->stored_clip_gc;
3044 if (door_state & DOOR_ACTION_1)
3046 int a = MIN(x * door_1.step_offset, end);
3047 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3048 int i = p + door_skip;
3050 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3052 BlitBitmap(bitmap_db_door, drawto,
3053 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3054 DXSIZE, DYSIZE, DX, DY);
3058 BlitBitmap(bitmap_db_door, drawto,
3059 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3060 DXSIZE, DYSIZE - p / 2, DX, DY);
3062 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3065 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3067 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3068 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3069 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3070 int dst2_x = DX, dst2_y = DY;
3071 int width = i, height = DYSIZE;
3073 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3074 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3077 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3078 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3081 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3083 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3084 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3085 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3086 int dst2_x = DX, dst2_y = DY;
3087 int width = DXSIZE, height = i;
3089 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3090 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3093 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3094 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3097 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3099 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3101 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3102 BlitBitmapMasked(bitmap, drawto,
3103 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3104 DX + DXSIZE - i, DY + j);
3105 BlitBitmapMasked(bitmap, drawto,
3106 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3107 DX + DXSIZE - i, DY + 140 + j);
3108 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3109 DY - (DOOR_GFX_PAGEY1 + j));
3110 BlitBitmapMasked(bitmap, drawto,
3111 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3113 BlitBitmapMasked(bitmap, drawto,
3114 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3117 BlitBitmapMasked(bitmap, drawto,
3118 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3120 BlitBitmapMasked(bitmap, drawto,
3121 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3123 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3124 BlitBitmapMasked(bitmap, drawto,
3125 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3126 DX + DXSIZE - i, DY + 77 + j);
3127 BlitBitmapMasked(bitmap, drawto,
3128 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3129 DX + DXSIZE - i, DY + 203 + j);
3132 redraw_mask |= REDRAW_DOOR_1;
3133 door_1_done = (a == end);
3136 if (door_state & DOOR_ACTION_2)
3138 int a = MIN(x * door_2.step_offset, door_size);
3139 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3140 int i = p + door_skip;
3142 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3144 BlitBitmap(bitmap_db_door, drawto,
3145 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3146 VXSIZE, VYSIZE, VX, VY);
3148 else if (x <= VYSIZE)
3150 BlitBitmap(bitmap_db_door, drawto,
3151 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3152 VXSIZE, VYSIZE - p / 2, VX, VY);
3154 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3157 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3159 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3160 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3161 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3162 int dst2_x = VX, dst2_y = VY;
3163 int width = i, height = VYSIZE;
3165 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3166 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3169 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3170 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3173 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3175 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3176 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3177 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3178 int dst2_x = VX, dst2_y = VY;
3179 int width = VXSIZE, height = i;
3181 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3182 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3185 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3186 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3189 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3191 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3193 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3194 BlitBitmapMasked(bitmap, drawto,
3195 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3196 VX + VXSIZE - i, VY + j);
3197 SetClipOrigin(bitmap, gc,
3198 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3199 BlitBitmapMasked(bitmap, drawto,
3200 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3203 BlitBitmapMasked(bitmap, drawto,
3204 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3205 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3206 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3207 BlitBitmapMasked(bitmap, drawto,
3208 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3210 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3213 redraw_mask |= REDRAW_DOOR_2;
3214 door_2_done = (a == VXSIZE);
3217 if (!(door_state & DOOR_NO_DELAY))
3221 if (game_status == GAME_MODE_MAIN)
3224 WaitUntilDelayReached(&door_delay, door_delay_value);
3229 if (door_state & DOOR_ACTION_1)
3230 door1 = door_state & DOOR_ACTION_1;
3231 if (door_state & DOOR_ACTION_2)
3232 door2 = door_state & DOOR_ACTION_2;
3234 return (door1 | door2);
3237 void DrawSpecialEditorDoor()
3239 /* draw bigger toolbox window */
3240 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3241 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3243 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3244 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3247 redraw_mask |= REDRAW_ALL;
3250 void UndrawSpecialEditorDoor()
3252 /* draw normal tape recorder window */
3253 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3254 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3257 redraw_mask |= REDRAW_ALL;
3261 /* ---------- new tool button stuff ---------------------------------------- */
3263 /* graphic position values for tool buttons */
3264 #define TOOL_BUTTON_YES_XPOS 2
3265 #define TOOL_BUTTON_YES_YPOS 250
3266 #define TOOL_BUTTON_YES_GFX_YPOS 0
3267 #define TOOL_BUTTON_YES_XSIZE 46
3268 #define TOOL_BUTTON_YES_YSIZE 28
3269 #define TOOL_BUTTON_NO_XPOS 52
3270 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3271 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3272 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3273 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3274 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3275 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3276 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3277 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3278 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3279 #define TOOL_BUTTON_PLAYER_XSIZE 30
3280 #define TOOL_BUTTON_PLAYER_YSIZE 30
3281 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3282 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3283 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3284 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3285 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3286 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3287 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3288 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3289 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3290 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3291 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3292 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3293 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3294 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3295 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3296 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3297 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3298 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3299 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3300 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3309 } toolbutton_info[NUM_TOOL_BUTTONS] =
3312 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3313 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3314 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3319 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3320 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3321 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3326 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3327 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3328 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3329 TOOL_CTRL_ID_CONFIRM,
3333 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3334 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3335 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3336 TOOL_CTRL_ID_PLAYER_1,
3340 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3341 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3342 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3343 TOOL_CTRL_ID_PLAYER_2,
3347 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3348 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3349 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3350 TOOL_CTRL_ID_PLAYER_3,
3354 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3355 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3356 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3357 TOOL_CTRL_ID_PLAYER_4,
3362 void CreateToolButtons()
3366 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3368 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3369 Bitmap *deco_bitmap = None;
3370 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3371 struct GadgetInfo *gi;
3372 unsigned long event_mask;
3373 int gd_xoffset, gd_yoffset;
3374 int gd_x1, gd_x2, gd_y;
3377 event_mask = GD_EVENT_RELEASED;
3379 gd_xoffset = toolbutton_info[i].xpos;
3380 gd_yoffset = toolbutton_info[i].ypos;
3381 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3382 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3383 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3385 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3387 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3389 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3390 &deco_bitmap, &deco_x, &deco_y);
3391 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3392 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3395 gi = CreateGadget(GDI_CUSTOM_ID, id,
3396 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3397 GDI_X, DX + toolbutton_info[i].x,
3398 GDI_Y, DY + toolbutton_info[i].y,
3399 GDI_WIDTH, toolbutton_info[i].width,
3400 GDI_HEIGHT, toolbutton_info[i].height,
3401 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3402 GDI_STATE, GD_BUTTON_UNPRESSED,
3403 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3404 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3405 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3406 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3407 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3408 GDI_DECORATION_SHIFTING, 1, 1,
3409 GDI_DIRECT_DRAW, FALSE,
3410 GDI_EVENT_MASK, event_mask,
3411 GDI_CALLBACK_ACTION, HandleToolButtons,
3415 Error(ERR_EXIT, "cannot create gadget");
3417 tool_gadget[id] = gi;
3421 void FreeToolButtons()
3425 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3426 FreeGadget(tool_gadget[i]);
3429 static void UnmapToolButtons()
3433 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3434 UnmapGadget(tool_gadget[i]);
3437 static void HandleToolButtons(struct GadgetInfo *gi)
3439 request_gadget_id = gi->custom_id;
3442 static struct Mapping_EM_to_RND_object
3445 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3446 boolean is_backside; /* backside of moving element */
3452 em_object_mapping_list[] =
3455 Xblank, TRUE, FALSE,
3459 Yacid_splash_eB, FALSE, FALSE,
3460 EL_ACID_SPLASH_RIGHT, -1, -1
3463 Yacid_splash_wB, FALSE, FALSE,
3464 EL_ACID_SPLASH_LEFT, -1, -1
3467 #ifdef EM_ENGINE_BAD_ROLL
3469 Xstone_force_e, FALSE, FALSE,
3470 EL_ROCK, -1, MV_BIT_RIGHT
3473 Xstone_force_w, FALSE, FALSE,
3474 EL_ROCK, -1, MV_BIT_LEFT
3477 Xnut_force_e, FALSE, FALSE,
3478 EL_NUT, -1, MV_BIT_RIGHT
3481 Xnut_force_w, FALSE, FALSE,
3482 EL_NUT, -1, MV_BIT_LEFT
3485 Xspring_force_e, FALSE, FALSE,
3486 EL_SPRING, -1, MV_BIT_RIGHT
3489 Xspring_force_w, FALSE, FALSE,
3490 EL_SPRING, -1, MV_BIT_LEFT
3493 Xemerald_force_e, FALSE, FALSE,
3494 EL_EMERALD, -1, MV_BIT_RIGHT
3497 Xemerald_force_w, FALSE, FALSE,
3498 EL_EMERALD, -1, MV_BIT_LEFT
3501 Xdiamond_force_e, FALSE, FALSE,
3502 EL_DIAMOND, -1, MV_BIT_RIGHT
3505 Xdiamond_force_w, FALSE, FALSE,
3506 EL_DIAMOND, -1, MV_BIT_LEFT
3509 Xbomb_force_e, FALSE, FALSE,
3510 EL_BOMB, -1, MV_BIT_RIGHT
3513 Xbomb_force_w, FALSE, FALSE,
3514 EL_BOMB, -1, MV_BIT_LEFT
3516 #endif /* EM_ENGINE_BAD_ROLL */
3519 Xstone, TRUE, FALSE,
3523 Xstone_pause, FALSE, FALSE,
3527 Xstone_fall, FALSE, FALSE,
3531 Ystone_s, FALSE, FALSE,
3532 EL_ROCK, ACTION_FALLING, -1
3535 Ystone_sB, FALSE, TRUE,
3536 EL_ROCK, ACTION_FALLING, -1
3539 Ystone_e, FALSE, FALSE,
3540 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3543 Ystone_eB, FALSE, TRUE,
3544 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3547 Ystone_w, FALSE, FALSE,
3548 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3551 Ystone_wB, FALSE, TRUE,
3552 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3559 Xnut_pause, FALSE, FALSE,
3563 Xnut_fall, FALSE, FALSE,
3567 Ynut_s, FALSE, FALSE,
3568 EL_NUT, ACTION_FALLING, -1
3571 Ynut_sB, FALSE, TRUE,
3572 EL_NUT, ACTION_FALLING, -1
3575 Ynut_e, FALSE, FALSE,
3576 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3579 Ynut_eB, FALSE, TRUE,
3580 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3583 Ynut_w, FALSE, FALSE,
3584 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3587 Ynut_wB, FALSE, TRUE,
3588 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3591 Xbug_n, TRUE, FALSE,
3595 Xbug_e, TRUE, FALSE,
3596 EL_BUG_RIGHT, -1, -1
3599 Xbug_s, TRUE, FALSE,
3603 Xbug_w, TRUE, FALSE,
3607 Xbug_gon, FALSE, FALSE,
3611 Xbug_goe, FALSE, FALSE,
3612 EL_BUG_RIGHT, -1, -1
3615 Xbug_gos, FALSE, FALSE,
3619 Xbug_gow, FALSE, FALSE,
3623 Ybug_n, FALSE, FALSE,
3624 EL_BUG, ACTION_MOVING, MV_BIT_UP
3627 Ybug_nB, FALSE, TRUE,
3628 EL_BUG, ACTION_MOVING, MV_BIT_UP
3631 Ybug_e, FALSE, FALSE,
3632 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3635 Ybug_eB, FALSE, TRUE,
3636 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3639 Ybug_s, FALSE, FALSE,
3640 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3643 Ybug_sB, FALSE, TRUE,
3644 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3647 Ybug_w, FALSE, FALSE,
3648 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3651 Ybug_wB, FALSE, TRUE,
3652 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3655 Ybug_w_n, FALSE, FALSE,
3656 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3659 Ybug_n_e, FALSE, FALSE,
3660 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3663 Ybug_e_s, FALSE, FALSE,
3664 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3667 Ybug_s_w, FALSE, FALSE,
3668 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3671 Ybug_e_n, FALSE, FALSE,
3672 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3675 Ybug_s_e, FALSE, FALSE,
3676 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3679 Ybug_w_s, FALSE, FALSE,
3680 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3683 Ybug_n_w, FALSE, FALSE,
3684 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3687 Ybug_stone, FALSE, FALSE,
3688 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3691 Ybug_spring, FALSE, FALSE,
3692 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3695 Xtank_n, TRUE, FALSE,
3696 EL_SPACESHIP_UP, -1, -1
3699 Xtank_e, TRUE, FALSE,
3700 EL_SPACESHIP_RIGHT, -1, -1
3703 Xtank_s, TRUE, FALSE,
3704 EL_SPACESHIP_DOWN, -1, -1
3707 Xtank_w, TRUE, FALSE,
3708 EL_SPACESHIP_LEFT, -1, -1
3711 Xtank_gon, FALSE, FALSE,
3712 EL_SPACESHIP_UP, -1, -1
3715 Xtank_goe, FALSE, FALSE,
3716 EL_SPACESHIP_RIGHT, -1, -1
3719 Xtank_gos, FALSE, FALSE,
3720 EL_SPACESHIP_DOWN, -1, -1
3723 Xtank_gow, FALSE, FALSE,
3724 EL_SPACESHIP_LEFT, -1, -1
3727 Ytank_n, FALSE, FALSE,
3728 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3731 Ytank_nB, FALSE, TRUE,
3732 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3735 Ytank_e, FALSE, FALSE,
3736 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3739 Ytank_eB, FALSE, TRUE,
3740 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3743 Ytank_s, FALSE, FALSE,
3744 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3747 Ytank_sB, FALSE, TRUE,
3748 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3751 Ytank_w, FALSE, FALSE,
3752 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3755 Ytank_wB, FALSE, TRUE,
3756 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3759 Ytank_w_n, FALSE, FALSE,
3760 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3763 Ytank_n_e, FALSE, FALSE,
3764 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3767 Ytank_e_s, FALSE, FALSE,
3768 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3771 Ytank_s_w, FALSE, FALSE,
3772 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3775 Ytank_e_n, FALSE, FALSE,
3776 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3779 Ytank_s_e, FALSE, FALSE,
3780 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3783 Ytank_w_s, FALSE, FALSE,
3784 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3787 Ytank_n_w, FALSE, FALSE,
3788 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3791 Ytank_stone, FALSE, FALSE,
3792 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3795 Ytank_spring, FALSE, FALSE,
3796 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3799 Xandroid, TRUE, FALSE,
3800 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3803 Xandroid_1_n, FALSE, FALSE,
3804 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3807 Xandroid_2_n, FALSE, FALSE,
3808 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3811 Xandroid_1_e, FALSE, FALSE,
3812 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3815 Xandroid_2_e, FALSE, FALSE,
3816 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3819 Xandroid_1_w, FALSE, FALSE,
3820 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3823 Xandroid_2_w, FALSE, FALSE,
3824 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3827 Xandroid_1_s, FALSE, FALSE,
3828 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3831 Xandroid_2_s, FALSE, FALSE,
3832 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3835 Yandroid_n, FALSE, FALSE,
3836 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3839 Yandroid_nB, FALSE, TRUE,
3840 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3843 Yandroid_ne, FALSE, FALSE,
3844 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3847 Yandroid_neB, FALSE, TRUE,
3848 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3851 Yandroid_e, FALSE, FALSE,
3852 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3855 Yandroid_eB, FALSE, TRUE,
3856 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3859 Yandroid_se, FALSE, FALSE,
3860 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3863 Yandroid_seB, FALSE, TRUE,
3864 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3867 Yandroid_s, FALSE, FALSE,
3868 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3871 Yandroid_sB, FALSE, TRUE,
3872 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3875 Yandroid_sw, FALSE, FALSE,
3876 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3879 Yandroid_swB, FALSE, TRUE,
3880 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3883 Yandroid_w, FALSE, FALSE,
3884 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3887 Yandroid_wB, FALSE, TRUE,
3888 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3891 Yandroid_nw, FALSE, FALSE,
3892 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3895 Yandroid_nwB, FALSE, TRUE,
3896 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3899 Xspring, TRUE, FALSE,
3903 Xspring_pause, FALSE, FALSE,
3907 Xspring_e, FALSE, FALSE,
3911 Xspring_w, FALSE, FALSE,
3915 Xspring_fall, FALSE, FALSE,
3919 Yspring_s, FALSE, FALSE,
3920 EL_SPRING, ACTION_FALLING, -1
3923 Yspring_sB, FALSE, TRUE,
3924 EL_SPRING, ACTION_FALLING, -1
3927 Yspring_e, FALSE, FALSE,
3928 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3931 Yspring_eB, FALSE, TRUE,
3932 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3935 Yspring_w, FALSE, FALSE,
3936 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3939 Yspring_wB, FALSE, TRUE,
3940 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3943 Yspring_kill_e, FALSE, FALSE,
3944 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3947 Yspring_kill_eB, FALSE, TRUE,
3948 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3951 Yspring_kill_w, FALSE, FALSE,
3952 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3955 Yspring_kill_wB, FALSE, TRUE,
3956 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3959 Xeater_n, TRUE, FALSE,
3960 EL_YAMYAM_UP, -1, -1
3963 Xeater_e, TRUE, FALSE,
3964 EL_YAMYAM_RIGHT, -1, -1
3967 Xeater_w, TRUE, FALSE,
3968 EL_YAMYAM_LEFT, -1, -1
3971 Xeater_s, TRUE, FALSE,
3972 EL_YAMYAM_DOWN, -1, -1
3975 Yeater_n, FALSE, FALSE,
3976 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3979 Yeater_nB, FALSE, TRUE,
3980 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3983 Yeater_e, FALSE, FALSE,
3984 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3987 Yeater_eB, FALSE, TRUE,
3988 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3991 Yeater_s, FALSE, FALSE,
3992 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3995 Yeater_sB, FALSE, TRUE,
3996 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3999 Yeater_w, FALSE, FALSE,
4000 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4003 Yeater_wB, FALSE, TRUE,
4004 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4007 Yeater_stone, FALSE, FALSE,
4008 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4011 Yeater_spring, FALSE, FALSE,
4012 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4015 Xalien, TRUE, FALSE,
4019 Xalien_pause, FALSE, FALSE,
4023 Yalien_n, FALSE, FALSE,
4024 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4027 Yalien_nB, FALSE, TRUE,
4028 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4031 Yalien_e, FALSE, FALSE,
4032 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4035 Yalien_eB, FALSE, TRUE,
4036 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4039 Yalien_s, FALSE, FALSE,
4040 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4043 Yalien_sB, FALSE, TRUE,
4044 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4047 Yalien_w, FALSE, FALSE,
4048 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4051 Yalien_wB, FALSE, TRUE,
4052 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4055 Yalien_stone, FALSE, FALSE,
4056 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4059 Yalien_spring, FALSE, FALSE,
4060 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4063 Xemerald, TRUE, FALSE,
4067 Xemerald_pause, FALSE, FALSE,
4071 Xemerald_fall, FALSE, FALSE,
4075 Xemerald_shine, FALSE, FALSE,
4076 EL_EMERALD, ACTION_TWINKLING, -1
4079 Yemerald_s, FALSE, FALSE,
4080 EL_EMERALD, ACTION_FALLING, -1
4083 Yemerald_sB, FALSE, TRUE,
4084 EL_EMERALD, ACTION_FALLING, -1
4087 Yemerald_e, FALSE, FALSE,
4088 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4091 Yemerald_eB, FALSE, TRUE,
4092 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4095 Yemerald_w, FALSE, FALSE,
4096 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4099 Yemerald_wB, FALSE, TRUE,
4100 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4103 Yemerald_eat, FALSE, FALSE,
4104 EL_EMERALD, ACTION_COLLECTING, -1
4107 Yemerald_stone, FALSE, FALSE,
4108 EL_NUT, ACTION_BREAKING, -1
4111 Xdiamond, TRUE, FALSE,
4115 Xdiamond_pause, FALSE, FALSE,
4119 Xdiamond_fall, FALSE, FALSE,
4123 Xdiamond_shine, FALSE, FALSE,
4124 EL_DIAMOND, ACTION_TWINKLING, -1
4127 Ydiamond_s, FALSE, FALSE,
4128 EL_DIAMOND, ACTION_FALLING, -1
4131 Ydiamond_sB, FALSE, TRUE,
4132 EL_DIAMOND, ACTION_FALLING, -1
4135 Ydiamond_e, FALSE, FALSE,
4136 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4139 Ydiamond_eB, FALSE, TRUE,
4140 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4143 Ydiamond_w, FALSE, FALSE,
4144 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4147 Ydiamond_wB, FALSE, TRUE,
4148 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4151 Ydiamond_eat, FALSE, FALSE,
4152 EL_DIAMOND, ACTION_COLLECTING, -1
4155 Ydiamond_stone, FALSE, FALSE,
4156 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4159 Xdrip_fall, TRUE, FALSE,
4160 EL_AMOEBA_DROP, -1, -1
4163 Xdrip_stretch, FALSE, FALSE,
4164 EL_AMOEBA_DROP, ACTION_FALLING, -1
4167 Xdrip_stretchB, FALSE, TRUE,
4168 EL_AMOEBA_DROP, ACTION_FALLING, -1
4171 Xdrip_eat, FALSE, FALSE,
4172 EL_AMOEBA_DROP, ACTION_GROWING, -1
4175 Ydrip_s1, FALSE, FALSE,
4176 EL_AMOEBA_DROP, ACTION_FALLING, -1
4179 Ydrip_s1B, FALSE, TRUE,
4180 EL_AMOEBA_DROP, ACTION_FALLING, -1
4183 Ydrip_s2, FALSE, FALSE,
4184 EL_AMOEBA_DROP, ACTION_FALLING, -1
4187 Ydrip_s2B, FALSE, TRUE,
4188 EL_AMOEBA_DROP, ACTION_FALLING, -1
4195 Xbomb_pause, FALSE, FALSE,
4199 Xbomb_fall, FALSE, FALSE,
4203 Ybomb_s, FALSE, FALSE,
4204 EL_BOMB, ACTION_FALLING, -1
4207 Ybomb_sB, FALSE, TRUE,
4208 EL_BOMB, ACTION_FALLING, -1
4211 Ybomb_e, FALSE, FALSE,
4212 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4215 Ybomb_eB, FALSE, TRUE,
4216 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4219 Ybomb_w, FALSE, FALSE,
4220 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4223 Ybomb_wB, FALSE, TRUE,
4224 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4227 Ybomb_eat, FALSE, FALSE,
4228 EL_BOMB, ACTION_ACTIVATING, -1
4231 Xballoon, TRUE, FALSE,
4235 Yballoon_n, FALSE, FALSE,
4236 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4239 Yballoon_nB, FALSE, TRUE,
4240 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4243 Yballoon_e, FALSE, FALSE,
4244 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4247 Yballoon_eB, FALSE, TRUE,
4248 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4251 Yballoon_s, FALSE, FALSE,
4252 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4255 Yballoon_sB, FALSE, TRUE,
4256 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4259 Yballoon_w, FALSE, FALSE,
4260 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4263 Yballoon_wB, FALSE, TRUE,
4264 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4267 Xgrass, TRUE, FALSE,
4268 EL_EMC_GRASS, -1, -1
4271 Ygrass_nB, FALSE, FALSE,
4272 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4275 Ygrass_eB, FALSE, FALSE,
4276 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4279 Ygrass_sB, FALSE, FALSE,
4280 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4283 Ygrass_wB, FALSE, FALSE,
4284 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4291 Ydirt_nB, FALSE, FALSE,
4292 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4295 Ydirt_eB, FALSE, FALSE,
4296 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4299 Ydirt_sB, FALSE, FALSE,
4300 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4303 Ydirt_wB, FALSE, FALSE,
4304 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4307 Xacid_ne, TRUE, FALSE,
4308 EL_ACID_POOL_TOPRIGHT, -1, -1
4311 Xacid_se, TRUE, FALSE,
4312 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4315 Xacid_s, TRUE, FALSE,
4316 EL_ACID_POOL_BOTTOM, -1, -1
4319 Xacid_sw, TRUE, FALSE,
4320 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4323 Xacid_nw, TRUE, FALSE,
4324 EL_ACID_POOL_TOPLEFT, -1, -1
4327 Xacid_1, TRUE, FALSE,
4331 Xacid_2, FALSE, FALSE,
4335 Xacid_3, FALSE, FALSE,
4339 Xacid_4, FALSE, FALSE,
4343 Xacid_5, FALSE, FALSE,
4347 Xacid_6, FALSE, FALSE,
4351 Xacid_7, FALSE, FALSE,
4355 Xacid_8, FALSE, FALSE,
4359 Xball_1, TRUE, FALSE,
4360 EL_EMC_MAGIC_BALL, -1, -1
4363 Xball_1B, FALSE, FALSE,
4364 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4367 Xball_2, FALSE, FALSE,
4368 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4371 Xball_2B, FALSE, FALSE,
4372 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4375 Yball_eat, FALSE, FALSE,
4376 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4379 Ykey_1_eat, FALSE, FALSE,
4380 EL_EM_KEY_1, ACTION_COLLECTING, -1
4383 Ykey_2_eat, FALSE, FALSE,
4384 EL_EM_KEY_2, ACTION_COLLECTING, -1
4387 Ykey_3_eat, FALSE, FALSE,
4388 EL_EM_KEY_3, ACTION_COLLECTING, -1
4391 Ykey_4_eat, FALSE, FALSE,
4392 EL_EM_KEY_4, ACTION_COLLECTING, -1
4395 Ykey_5_eat, FALSE, FALSE,
4396 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4399 Ykey_6_eat, FALSE, FALSE,
4400 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4403 Ykey_7_eat, FALSE, FALSE,
4404 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4407 Ykey_8_eat, FALSE, FALSE,
4408 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4411 Ylenses_eat, FALSE, FALSE,
4412 EL_EMC_LENSES, ACTION_COLLECTING, -1
4415 Ymagnify_eat, FALSE, FALSE,
4416 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4419 Ygrass_eat, FALSE, FALSE,
4420 EL_EMC_GRASS, ACTION_SNAPPING, -1
4423 Ydirt_eat, FALSE, FALSE,
4424 EL_SAND, ACTION_SNAPPING, -1
4427 Xgrow_ns, TRUE, FALSE,
4428 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4431 Ygrow_ns_eat, FALSE, FALSE,
4432 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4435 Xgrow_ew, TRUE, FALSE,
4436 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4439 Ygrow_ew_eat, FALSE, FALSE,
4440 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4443 Xwonderwall, TRUE, FALSE,
4444 EL_MAGIC_WALL, -1, -1
4447 XwonderwallB, FALSE, FALSE,
4448 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4451 Xamoeba_1, TRUE, FALSE,
4452 EL_AMOEBA_DRY, ACTION_OTHER, -1
4455 Xamoeba_2, FALSE, FALSE,
4456 EL_AMOEBA_DRY, ACTION_OTHER, -1
4459 Xamoeba_3, FALSE, FALSE,
4460 EL_AMOEBA_DRY, ACTION_OTHER, -1
4463 Xamoeba_4, FALSE, FALSE,
4464 EL_AMOEBA_DRY, ACTION_OTHER, -1
4467 Xamoeba_5, TRUE, FALSE,
4468 EL_AMOEBA_WET, ACTION_OTHER, -1
4471 Xamoeba_6, FALSE, FALSE,
4472 EL_AMOEBA_WET, ACTION_OTHER, -1
4475 Xamoeba_7, FALSE, FALSE,
4476 EL_AMOEBA_WET, ACTION_OTHER, -1
4479 Xamoeba_8, FALSE, FALSE,
4480 EL_AMOEBA_WET, ACTION_OTHER, -1
4483 Xdoor_1, TRUE, FALSE,
4484 EL_EM_GATE_1, -1, -1
4487 Xdoor_2, TRUE, FALSE,
4488 EL_EM_GATE_2, -1, -1
4491 Xdoor_3, TRUE, FALSE,
4492 EL_EM_GATE_3, -1, -1
4495 Xdoor_4, TRUE, FALSE,
4496 EL_EM_GATE_4, -1, -1
4499 Xdoor_5, TRUE, FALSE,
4500 EL_EMC_GATE_5, -1, -1
4503 Xdoor_6, TRUE, FALSE,
4504 EL_EMC_GATE_6, -1, -1
4507 Xdoor_7, TRUE, FALSE,
4508 EL_EMC_GATE_7, -1, -1
4511 Xdoor_8, TRUE, FALSE,
4512 EL_EMC_GATE_8, -1, -1
4515 Xkey_1, TRUE, FALSE,
4519 Xkey_2, TRUE, FALSE,
4523 Xkey_3, TRUE, FALSE,
4527 Xkey_4, TRUE, FALSE,
4531 Xkey_5, TRUE, FALSE,
4532 EL_EMC_KEY_5, -1, -1
4535 Xkey_6, TRUE, FALSE,
4536 EL_EMC_KEY_6, -1, -1
4539 Xkey_7, TRUE, FALSE,
4540 EL_EMC_KEY_7, -1, -1
4543 Xkey_8, TRUE, FALSE,
4544 EL_EMC_KEY_8, -1, -1
4547 Xwind_n, TRUE, FALSE,
4548 EL_BALLOON_SWITCH_UP, -1, -1
4551 Xwind_e, TRUE, FALSE,
4552 EL_BALLOON_SWITCH_RIGHT, -1, -1
4555 Xwind_s, TRUE, FALSE,
4556 EL_BALLOON_SWITCH_DOWN, -1, -1
4559 Xwind_w, TRUE, FALSE,
4560 EL_BALLOON_SWITCH_LEFT, -1, -1
4563 Xwind_nesw, TRUE, FALSE,
4564 EL_BALLOON_SWITCH_ANY, -1, -1
4567 Xwind_stop, TRUE, FALSE,
4568 EL_BALLOON_SWITCH_NONE, -1, -1
4572 EL_EM_EXIT_CLOSED, -1, -1
4575 Xexit_1, TRUE, FALSE,
4576 EL_EM_EXIT_OPEN, -1, -1
4579 Xexit_2, FALSE, FALSE,
4580 EL_EM_EXIT_OPEN, -1, -1
4583 Xexit_3, FALSE, FALSE,
4584 EL_EM_EXIT_OPEN, -1, -1
4587 Xdynamite, TRUE, FALSE,
4588 EL_EM_DYNAMITE, -1, -1
4591 Ydynamite_eat, FALSE, FALSE,
4592 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4595 Xdynamite_1, TRUE, FALSE,
4596 EL_EM_DYNAMITE_ACTIVE, -1, -1
4599 Xdynamite_2, FALSE, FALSE,
4600 EL_EM_DYNAMITE_ACTIVE, -1, -1
4603 Xdynamite_3, FALSE, FALSE,
4604 EL_EM_DYNAMITE_ACTIVE, -1, -1
4607 Xdynamite_4, FALSE, FALSE,
4608 EL_EM_DYNAMITE_ACTIVE, -1, -1
4611 Xbumper, TRUE, FALSE,
4612 EL_EMC_SPRING_BUMPER, -1, -1
4615 XbumperB, FALSE, FALSE,
4616 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4619 Xwheel, TRUE, FALSE,
4620 EL_ROBOT_WHEEL, -1, -1
4623 XwheelB, FALSE, FALSE,
4624 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4627 Xswitch, TRUE, FALSE,
4628 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4631 XswitchB, FALSE, FALSE,
4632 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4636 EL_QUICKSAND_EMPTY, -1, -1
4639 Xsand_stone, TRUE, FALSE,
4640 EL_QUICKSAND_FULL, -1, -1
4643 Xsand_stonein_1, FALSE, TRUE,
4644 EL_ROCK, ACTION_FILLING, -1
4647 Xsand_stonein_2, FALSE, TRUE,
4648 EL_ROCK, ACTION_FILLING, -1
4651 Xsand_stonein_3, FALSE, TRUE,
4652 EL_ROCK, ACTION_FILLING, -1
4655 Xsand_stonein_4, FALSE, TRUE,
4656 EL_ROCK, ACTION_FILLING, -1
4659 Xsand_stonesand_1, FALSE, FALSE,
4660 EL_QUICKSAND_FULL, -1, -1
4663 Xsand_stonesand_2, FALSE, FALSE,
4664 EL_QUICKSAND_FULL, -1, -1
4667 Xsand_stonesand_3, FALSE, FALSE,
4668 EL_QUICKSAND_FULL, -1, -1
4671 Xsand_stonesand_4, FALSE, FALSE,
4672 EL_QUICKSAND_FULL, -1, -1
4675 Xsand_stoneout_1, FALSE, FALSE,
4676 EL_ROCK, ACTION_EMPTYING, -1
4679 Xsand_stoneout_2, FALSE, FALSE,
4680 EL_ROCK, ACTION_EMPTYING, -1
4683 Xsand_sandstone_1, FALSE, FALSE,
4684 EL_QUICKSAND_FULL, -1, -1
4687 Xsand_sandstone_2, FALSE, FALSE,
4688 EL_QUICKSAND_FULL, -1, -1
4691 Xsand_sandstone_3, FALSE, FALSE,
4692 EL_QUICKSAND_FULL, -1, -1
4695 Xsand_sandstone_4, FALSE, FALSE,
4696 EL_QUICKSAND_FULL, -1, -1
4699 Xplant, TRUE, FALSE,
4700 EL_EMC_PLANT, -1, -1
4703 Yplant, FALSE, FALSE,
4704 EL_EMC_PLANT, -1, -1
4707 Xlenses, TRUE, FALSE,
4708 EL_EMC_LENSES, -1, -1
4711 Xmagnify, TRUE, FALSE,
4712 EL_EMC_MAGNIFIER, -1, -1
4715 Xdripper, TRUE, FALSE,
4716 EL_EMC_DRIPPER, -1, -1
4719 XdripperB, FALSE, FALSE,
4720 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4723 Xfake_blank, TRUE, FALSE,
4724 EL_INVISIBLE_WALL, -1, -1
4727 Xfake_blankB, FALSE, FALSE,
4728 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4731 Xfake_grass, TRUE, FALSE,
4732 EL_EMC_FAKE_GRASS, -1, -1
4735 Xfake_grassB, FALSE, FALSE,
4736 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4739 Xfake_door_1, TRUE, FALSE,
4740 EL_EM_GATE_1_GRAY, -1, -1
4743 Xfake_door_2, TRUE, FALSE,
4744 EL_EM_GATE_2_GRAY, -1, -1
4747 Xfake_door_3, TRUE, FALSE,
4748 EL_EM_GATE_3_GRAY, -1, -1
4751 Xfake_door_4, TRUE, FALSE,
4752 EL_EM_GATE_4_GRAY, -1, -1
4755 Xfake_door_5, TRUE, FALSE,
4756 EL_EMC_GATE_5_GRAY, -1, -1
4759 Xfake_door_6, TRUE, FALSE,
4760 EL_EMC_GATE_6_GRAY, -1, -1
4763 Xfake_door_7, TRUE, FALSE,
4764 EL_EMC_GATE_7_GRAY, -1, -1
4767 Xfake_door_8, TRUE, FALSE,
4768 EL_EMC_GATE_8_GRAY, -1, -1
4771 Xfake_acid_1, TRUE, FALSE,
4772 EL_EMC_FAKE_ACID, -1, -1
4775 Xfake_acid_2, FALSE, FALSE,
4776 EL_EMC_FAKE_ACID, -1, -1
4779 Xfake_acid_3, FALSE, FALSE,
4780 EL_EMC_FAKE_ACID, -1, -1
4783 Xfake_acid_4, FALSE, FALSE,
4784 EL_EMC_FAKE_ACID, -1, -1
4787 Xfake_acid_5, FALSE, FALSE,
4788 EL_EMC_FAKE_ACID, -1, -1
4791 Xfake_acid_6, FALSE, FALSE,
4792 EL_EMC_FAKE_ACID, -1, -1
4795 Xfake_acid_7, FALSE, FALSE,
4796 EL_EMC_FAKE_ACID, -1, -1
4799 Xfake_acid_8, FALSE, FALSE,
4800 EL_EMC_FAKE_ACID, -1, -1
4803 Xsteel_1, TRUE, FALSE,
4804 EL_STEELWALL, -1, -1
4807 Xsteel_2, TRUE, FALSE,
4808 EL_EMC_STEELWALL_2, -1, -1
4811 Xsteel_3, TRUE, FALSE,
4812 EL_EMC_STEELWALL_3, -1, -1
4815 Xsteel_4, TRUE, FALSE,
4816 EL_EMC_STEELWALL_4, -1, -1
4819 Xwall_1, TRUE, FALSE,
4823 Xwall_2, TRUE, FALSE,
4824 EL_EMC_WALL_14, -1, -1
4827 Xwall_3, TRUE, FALSE,
4828 EL_EMC_WALL_15, -1, -1
4831 Xwall_4, TRUE, FALSE,
4832 EL_EMC_WALL_16, -1, -1
4835 Xround_wall_1, TRUE, FALSE,
4836 EL_WALL_SLIPPERY, -1, -1
4839 Xround_wall_2, TRUE, FALSE,
4840 EL_EMC_WALL_SLIPPERY_2, -1, -1
4843 Xround_wall_3, TRUE, FALSE,
4844 EL_EMC_WALL_SLIPPERY_3, -1, -1
4847 Xround_wall_4, TRUE, FALSE,
4848 EL_EMC_WALL_SLIPPERY_4, -1, -1
4851 Xdecor_1, TRUE, FALSE,
4852 EL_EMC_WALL_8, -1, -1
4855 Xdecor_2, TRUE, FALSE,
4856 EL_EMC_WALL_6, -1, -1
4859 Xdecor_3, TRUE, FALSE,
4860 EL_EMC_WALL_4, -1, -1
4863 Xdecor_4, TRUE, FALSE,
4864 EL_EMC_WALL_7, -1, -1
4867 Xdecor_5, TRUE, FALSE,
4868 EL_EMC_WALL_5, -1, -1
4871 Xdecor_6, TRUE, FALSE,
4872 EL_EMC_WALL_9, -1, -1
4875 Xdecor_7, TRUE, FALSE,
4876 EL_EMC_WALL_10, -1, -1
4879 Xdecor_8, TRUE, FALSE,
4880 EL_EMC_WALL_1, -1, -1
4883 Xdecor_9, TRUE, FALSE,
4884 EL_EMC_WALL_2, -1, -1
4887 Xdecor_10, TRUE, FALSE,
4888 EL_EMC_WALL_3, -1, -1
4891 Xdecor_11, TRUE, FALSE,
4892 EL_EMC_WALL_11, -1, -1
4895 Xdecor_12, TRUE, FALSE,
4896 EL_EMC_WALL_12, -1, -1
4899 Xalpha_0, TRUE, FALSE,
4900 EL_CHAR('0'), -1, -1
4903 Xalpha_1, TRUE, FALSE,
4904 EL_CHAR('1'), -1, -1
4907 Xalpha_2, TRUE, FALSE,
4908 EL_CHAR('2'), -1, -1
4911 Xalpha_3, TRUE, FALSE,
4912 EL_CHAR('3'), -1, -1
4915 Xalpha_4, TRUE, FALSE,
4916 EL_CHAR('4'), -1, -1
4919 Xalpha_5, TRUE, FALSE,
4920 EL_CHAR('5'), -1, -1
4923 Xalpha_6, TRUE, FALSE,
4924 EL_CHAR('6'), -1, -1
4927 Xalpha_7, TRUE, FALSE,
4928 EL_CHAR('7'), -1, -1
4931 Xalpha_8, TRUE, FALSE,
4932 EL_CHAR('8'), -1, -1
4935 Xalpha_9, TRUE, FALSE,
4936 EL_CHAR('9'), -1, -1
4939 Xalpha_excla, TRUE, FALSE,
4940 EL_CHAR('!'), -1, -1
4943 Xalpha_quote, TRUE, FALSE,
4944 EL_CHAR('"'), -1, -1
4947 Xalpha_comma, TRUE, FALSE,
4948 EL_CHAR(','), -1, -1
4951 Xalpha_minus, TRUE, FALSE,
4952 EL_CHAR('-'), -1, -1
4955 Xalpha_perio, TRUE, FALSE,
4956 EL_CHAR('.'), -1, -1
4959 Xalpha_colon, TRUE, FALSE,
4960 EL_CHAR(':'), -1, -1
4963 Xalpha_quest, TRUE, FALSE,
4964 EL_CHAR('?'), -1, -1
4967 Xalpha_a, TRUE, FALSE,
4968 EL_CHAR('A'), -1, -1
4971 Xalpha_b, TRUE, FALSE,
4972 EL_CHAR('B'), -1, -1
4975 Xalpha_c, TRUE, FALSE,
4976 EL_CHAR('C'), -1, -1
4979 Xalpha_d, TRUE, FALSE,
4980 EL_CHAR('D'), -1, -1
4983 Xalpha_e, TRUE, FALSE,
4984 EL_CHAR('E'), -1, -1
4987 Xalpha_f, TRUE, FALSE,
4988 EL_CHAR('F'), -1, -1
4991 Xalpha_g, TRUE, FALSE,
4992 EL_CHAR('G'), -1, -1
4995 Xalpha_h, TRUE, FALSE,
4996 EL_CHAR('H'), -1, -1
4999 Xalpha_i, TRUE, FALSE,
5000 EL_CHAR('I'), -1, -1
5003 Xalpha_j, TRUE, FALSE,
5004 EL_CHAR('J'), -1, -1
5007 Xalpha_k, TRUE, FALSE,
5008 EL_CHAR('K'), -1, -1
5011 Xalpha_l, TRUE, FALSE,
5012 EL_CHAR('L'), -1, -1
5015 Xalpha_m, TRUE, FALSE,
5016 EL_CHAR('M'), -1, -1
5019 Xalpha_n, TRUE, FALSE,
5020 EL_CHAR('N'), -1, -1
5023 Xalpha_o, TRUE, FALSE,
5024 EL_CHAR('O'), -1, -1
5027 Xalpha_p, TRUE, FALSE,
5028 EL_CHAR('P'), -1, -1
5031 Xalpha_q, TRUE, FALSE,
5032 EL_CHAR('Q'), -1, -1
5035 Xalpha_r, TRUE, FALSE,
5036 EL_CHAR('R'), -1, -1
5039 Xalpha_s, TRUE, FALSE,
5040 EL_CHAR('S'), -1, -1
5043 Xalpha_t, TRUE, FALSE,
5044 EL_CHAR('T'), -1, -1
5047 Xalpha_u, TRUE, FALSE,
5048 EL_CHAR('U'), -1, -1
5051 Xalpha_v, TRUE, FALSE,
5052 EL_CHAR('V'), -1, -1
5055 Xalpha_w, TRUE, FALSE,
5056 EL_CHAR('W'), -1, -1
5059 Xalpha_x, TRUE, FALSE,
5060 EL_CHAR('X'), -1, -1
5063 Xalpha_y, TRUE, FALSE,
5064 EL_CHAR('Y'), -1, -1
5067 Xalpha_z, TRUE, FALSE,
5068 EL_CHAR('Z'), -1, -1
5071 Xalpha_arrow_e, TRUE, FALSE,
5072 EL_CHAR('>'), -1, -1
5075 Xalpha_arrow_w, TRUE, FALSE,
5076 EL_CHAR('<'), -1, -1
5079 Xalpha_copyr, TRUE, FALSE,
5080 EL_CHAR('©'), -1, -1
5084 Xboom_bug, FALSE, FALSE,
5085 EL_BUG, ACTION_EXPLODING, -1
5088 Xboom_bomb, FALSE, FALSE,
5089 EL_BOMB, ACTION_EXPLODING, -1
5092 Xboom_android, FALSE, FALSE,
5093 EL_EMC_ANDROID, ACTION_OTHER, -1
5096 Xboom_1, FALSE, FALSE,
5097 EL_DEFAULT, ACTION_EXPLODING, -1
5100 Xboom_2, FALSE, FALSE,
5101 EL_DEFAULT, ACTION_EXPLODING, -1
5104 Znormal, FALSE, FALSE,
5108 Zdynamite, FALSE, FALSE,
5112 Zplayer, FALSE, FALSE,
5116 ZBORDER, FALSE, FALSE,
5126 static struct Mapping_EM_to_RND_player
5135 em_player_mapping_list[] =
5139 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5143 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5147 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5151 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5155 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5159 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5163 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5167 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5171 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5175 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5179 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5183 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5187 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5191 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5195 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5199 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5203 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5207 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5211 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5215 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5219 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5223 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5227 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5231 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5235 EL_PLAYER_1, ACTION_DEFAULT, -1,
5239 EL_PLAYER_2, ACTION_DEFAULT, -1,
5243 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5247 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5251 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5255 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5259 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5263 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5267 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5271 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5275 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5279 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5283 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5287 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5291 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5295 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5299 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5303 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5307 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5311 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5315 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5319 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5323 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5327 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5331 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5335 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5339 EL_PLAYER_3, ACTION_DEFAULT, -1,
5343 EL_PLAYER_4, ACTION_DEFAULT, -1,
5352 int map_element_RND_to_EM(int element_rnd)
5354 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5355 static boolean mapping_initialized = FALSE;
5357 if (!mapping_initialized)
5361 /* return "Xalpha_quest" for all undefined elements in mapping array */
5362 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5363 mapping_RND_to_EM[i] = Xalpha_quest;
5365 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5366 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5367 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5368 em_object_mapping_list[i].element_em;
5370 mapping_initialized = TRUE;
5373 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5374 return mapping_RND_to_EM[element_rnd];
5376 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5381 int map_element_EM_to_RND(int element_em)
5383 static unsigned short mapping_EM_to_RND[TILE_MAX];
5384 static boolean mapping_initialized = FALSE;
5386 if (!mapping_initialized)
5390 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5391 for (i = 0; i < TILE_MAX; i++)
5392 mapping_EM_to_RND[i] = EL_UNKNOWN;
5394 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5395 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5396 em_object_mapping_list[i].element_rnd;
5398 mapping_initialized = TRUE;
5401 if (element_em >= 0 && element_em < TILE_MAX)
5402 return mapping_EM_to_RND[element_em];
5404 Error(ERR_WARN, "invalid EM level element %d", element_em);
5409 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5411 struct LevelInfo_EM *level_em = level->native_em_level;
5412 struct LEVEL *lev = level_em->lev;
5415 for (i = 0; i < TILE_MAX; i++)
5416 lev->android_array[i] = Xblank;
5418 for (i = 0; i < level->num_android_clone_elements; i++)
5420 int element_rnd = level->android_clone_element[i];
5421 int element_em = map_element_RND_to_EM(element_rnd);
5423 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5424 if (em_object_mapping_list[j].element_rnd == element_rnd)
5425 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5429 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5431 struct LevelInfo_EM *level_em = level->native_em_level;
5432 struct LEVEL *lev = level_em->lev;
5435 level->num_android_clone_elements = 0;
5437 for (i = 0; i < TILE_MAX; i++)
5439 int element_em = lev->android_array[i];
5441 boolean element_found = FALSE;
5443 if (element_em == Xblank)
5446 element_rnd = map_element_EM_to_RND(element_em);
5448 for (j = 0; j < level->num_android_clone_elements; j++)
5449 if (level->android_clone_element[j] == element_rnd)
5450 element_found = TRUE;
5454 level->android_clone_element[level->num_android_clone_elements++] =
5457 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5462 if (level->num_android_clone_elements == 0)
5464 level->num_android_clone_elements = 1;
5465 level->android_clone_element[0] = EL_EMPTY;
5469 int map_direction_RND_to_EM(int direction)
5471 return (direction == MV_UP ? 0 :
5472 direction == MV_RIGHT ? 1 :
5473 direction == MV_DOWN ? 2 :
5474 direction == MV_LEFT ? 3 :
5478 int map_direction_EM_to_RND(int direction)
5480 return (direction == 0 ? MV_UP :
5481 direction == 1 ? MV_RIGHT :
5482 direction == 2 ? MV_DOWN :
5483 direction == 3 ? MV_LEFT :
5487 int get_next_element(int element)
5491 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5492 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5493 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5494 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5495 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5496 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5497 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5498 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5499 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5500 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5501 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5503 default: return element;
5508 int el_act_dir2img(int element, int action, int direction)
5510 element = GFX_ELEMENT(element);
5512 if (direction == MV_NONE)
5513 return element_info[element].graphic[action];
5515 direction = MV_DIR_TO_BIT(direction);
5517 return element_info[element].direction_graphic[action][direction];
5520 int el_act_dir2img(int element, int action, int direction)
5522 element = GFX_ELEMENT(element);
5523 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5525 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5526 return element_info[element].direction_graphic[action][direction];
5531 static int el_act_dir2crm(int element, int action, int direction)
5533 element = GFX_ELEMENT(element);
5535 if (direction == MV_NONE)
5536 return element_info[element].crumbled[action];
5538 direction = MV_DIR_TO_BIT(direction);
5540 return element_info[element].direction_crumbled[action][direction];
5543 static int el_act_dir2crm(int element, int action, int direction)
5545 element = GFX_ELEMENT(element);
5546 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5548 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5549 return element_info[element].direction_crumbled[action][direction];
5553 int el_act2img(int element, int action)
5555 element = GFX_ELEMENT(element);
5557 return element_info[element].graphic[action];
5560 int el_act2crm(int element, int action)
5562 element = GFX_ELEMENT(element);
5564 return element_info[element].crumbled[action];
5567 int el_dir2img(int element, int direction)
5569 element = GFX_ELEMENT(element);
5571 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5574 int el2baseimg(int element)
5576 return element_info[element].graphic[ACTION_DEFAULT];
5579 int el2img(int element)
5581 element = GFX_ELEMENT(element);
5583 return element_info[element].graphic[ACTION_DEFAULT];
5586 int el2edimg(int element)
5588 element = GFX_ELEMENT(element);
5590 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5593 int el2preimg(int element)
5595 element = GFX_ELEMENT(element);
5597 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5600 int font2baseimg(int font_nr)
5602 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5605 int getBeltNrFromBeltElement(int element)
5607 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5608 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5609 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5612 int getBeltNrFromBeltActiveElement(int element)
5614 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5615 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5616 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5619 int getBeltNrFromBeltSwitchElement(int element)
5621 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5622 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5623 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5626 int getBeltDirNrFromBeltElement(int element)
5628 static int belt_base_element[4] =
5630 EL_CONVEYOR_BELT_1_LEFT,
5631 EL_CONVEYOR_BELT_2_LEFT,
5632 EL_CONVEYOR_BELT_3_LEFT,
5633 EL_CONVEYOR_BELT_4_LEFT
5636 int belt_nr = getBeltNrFromBeltElement(element);
5637 int belt_dir_nr = element - belt_base_element[belt_nr];
5639 return (belt_dir_nr % 3);
5642 int getBeltDirNrFromBeltSwitchElement(int element)
5644 static int belt_base_element[4] =
5646 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5647 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5648 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5649 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5652 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5653 int belt_dir_nr = element - belt_base_element[belt_nr];
5655 return (belt_dir_nr % 3);
5658 int getBeltDirFromBeltElement(int element)
5660 static int belt_move_dir[3] =
5667 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5669 return belt_move_dir[belt_dir_nr];
5672 int getBeltDirFromBeltSwitchElement(int element)
5674 static int belt_move_dir[3] =
5681 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5683 return belt_move_dir[belt_dir_nr];
5686 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5688 static int belt_base_element[4] =
5690 EL_CONVEYOR_BELT_1_LEFT,
5691 EL_CONVEYOR_BELT_2_LEFT,
5692 EL_CONVEYOR_BELT_3_LEFT,
5693 EL_CONVEYOR_BELT_4_LEFT
5695 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5697 return belt_base_element[belt_nr] + belt_dir_nr;
5700 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5702 static int belt_base_element[4] =
5704 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5705 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5706 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5707 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5709 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5711 return belt_base_element[belt_nr] + belt_dir_nr;
5714 int getNumActivePlayers_EM()
5716 int num_players = 0;
5722 for (i = 0; i < MAX_PLAYERS; i++)
5723 if (tape.player_participates[i])
5729 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5731 int game_frame_delay_value;
5733 game_frame_delay_value =
5734 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5735 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5738 if (tape.playing && tape.warp_forward && !tape.pausing)
5739 game_frame_delay_value = 0;
5741 return game_frame_delay_value;
5744 unsigned int InitRND(long seed)
5746 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5747 return InitEngineRandom_EM(seed);
5749 return InitEngineRandom_RND(seed);
5753 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5754 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5757 void ResetGfxAnimation_EM(int x, int y, int tile)
5762 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5763 Bitmap **src_bitmap, int *src_x, int *src_y,
5766 int element = object_mapping[tile].element_rnd;
5767 int action = object_mapping[tile].action;
5768 int direction = object_mapping[tile].direction;
5769 boolean is_backside = object_mapping[tile].is_backside;
5770 boolean action_removing = (action == ACTION_DIGGING ||
5771 action == ACTION_SNAPPING ||
5772 action == ACTION_COLLECTING);
5773 int effective_element = (frame_em > 0 ? element :
5774 is_backside ? EL_EMPTY :
5775 action_removing ? EL_EMPTY :
5777 int graphic = (direction == MV_NONE ?
5778 el_act2img(effective_element, action) :
5779 el_act_dir2img(effective_element, action, direction));
5780 struct GraphicInfo *g = &graphic_info[graphic];
5783 if (graphic_info[graphic].anim_global_sync)
5784 sync_frame = FrameCounter;
5786 sync_frame = 7 - frame_em;
5788 SetRandomAnimationValue(x, y);
5790 int frame = getAnimationFrame(g->anim_frames,
5793 g->anim_start_frame,
5796 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5799 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
5800 Bitmap **src_bitmap, int *src_x, int *src_y)
5802 int element = player_mapping[player_nr][anim].element_rnd;
5803 int action = player_mapping[player_nr][anim].action;
5804 int direction = player_mapping[player_nr][anim].direction;
5805 int graphic = (direction == MV_NONE ?
5806 el_act2img(element, action) :
5807 el_act_dir2img(element, action, direction));
5808 struct GraphicInfo *g = &graphic_info[graphic];
5811 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
5813 stored_player[player_nr].StepFrame = 7 - frame_em;
5815 sync_frame = stored_player[player_nr].Frame;
5818 printf("::: %d: %d, %d [%d]\n",
5820 stored_player[player_nr].Frame,
5821 stored_player[player_nr].StepFrame,
5825 int frame = getAnimationFrame(g->anim_frames,
5828 g->anim_start_frame,
5831 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5834 void InitGraphicInfo_EM(void)
5837 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5838 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5843 int num_em_gfx_errors = 0;
5845 if (graphic_info_em_object[0][0].bitmap == NULL)
5847 /* EM graphics not yet initialized in em_open_all() */
5852 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5855 /* always start with reliable default values */
5856 for (i = 0; i < TILE_MAX; i++)
5858 object_mapping[i].element_rnd = EL_UNKNOWN;
5859 object_mapping[i].is_backside = FALSE;
5860 object_mapping[i].action = ACTION_DEFAULT;
5861 object_mapping[i].direction = MV_NONE;
5864 /* always start with reliable default values */
5865 for (p = 0; p < MAX_PLAYERS; p++)
5867 for (i = 0; i < SPR_MAX; i++)
5869 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5870 player_mapping[p][i].action = ACTION_DEFAULT;
5871 player_mapping[p][i].direction = MV_NONE;
5875 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5877 int e = em_object_mapping_list[i].element_em;
5879 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5880 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5882 if (em_object_mapping_list[i].action != -1)
5883 object_mapping[e].action = em_object_mapping_list[i].action;
5885 if (em_object_mapping_list[i].direction != -1)
5886 object_mapping[e].direction =
5887 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5890 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5892 int a = em_player_mapping_list[i].action_em;
5893 int p = em_player_mapping_list[i].player_nr;
5895 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5897 if (em_player_mapping_list[i].action != -1)
5898 player_mapping[p][a].action = em_player_mapping_list[i].action;
5900 if (em_player_mapping_list[i].direction != -1)
5901 player_mapping[p][a].direction =
5902 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5905 for (i = 0; i < TILE_MAX; i++)
5907 int element = object_mapping[i].element_rnd;
5908 int action = object_mapping[i].action;
5909 int direction = object_mapping[i].direction;
5910 boolean is_backside = object_mapping[i].is_backside;
5911 boolean action_removing = (action == ACTION_DIGGING ||
5912 action == ACTION_SNAPPING ||
5913 action == ACTION_COLLECTING);
5914 boolean action_exploding = ((action == ACTION_EXPLODING ||
5915 action == ACTION_SMASHED_BY_ROCK ||
5916 action == ACTION_SMASHED_BY_SPRING) &&
5917 element != EL_DIAMOND);
5918 boolean action_active = (action == ACTION_ACTIVE);
5919 boolean action_other = (action == ACTION_OTHER);
5921 for (j = 0; j < 8; j++)
5923 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5924 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5926 i == Xdrip_stretch ? element :
5927 i == Xdrip_stretchB ? element :
5928 i == Ydrip_s1 ? element :
5929 i == Ydrip_s1B ? element :
5930 i == Xball_1B ? element :
5931 i == Xball_2 ? element :
5932 i == Xball_2B ? element :
5933 i == Yball_eat ? element :
5934 i == Ykey_1_eat ? element :
5935 i == Ykey_2_eat ? element :
5936 i == Ykey_3_eat ? element :
5937 i == Ykey_4_eat ? element :
5938 i == Ykey_5_eat ? element :
5939 i == Ykey_6_eat ? element :
5940 i == Ykey_7_eat ? element :
5941 i == Ykey_8_eat ? element :
5942 i == Ylenses_eat ? element :
5943 i == Ymagnify_eat ? element :
5944 i == Ygrass_eat ? element :
5945 i == Ydirt_eat ? element :
5946 i == Yemerald_stone ? EL_EMERALD :
5947 i == Ydiamond_stone ? EL_ROCK :
5948 i == Xsand_stonein_1 ? element :
5949 i == Xsand_stonein_2 ? element :
5950 i == Xsand_stonein_3 ? element :
5951 i == Xsand_stonein_4 ? element :
5952 is_backside ? EL_EMPTY :
5953 action_removing ? EL_EMPTY :
5955 int effective_action = (j < 7 ? action :
5956 i == Xdrip_stretch ? action :
5957 i == Xdrip_stretchB ? action :
5958 i == Ydrip_s1 ? action :
5959 i == Ydrip_s1B ? action :
5960 i == Xball_1B ? action :
5961 i == Xball_2 ? action :
5962 i == Xball_2B ? action :
5963 i == Yball_eat ? action :
5964 i == Ykey_1_eat ? action :
5965 i == Ykey_2_eat ? action :
5966 i == Ykey_3_eat ? action :
5967 i == Ykey_4_eat ? action :
5968 i == Ykey_5_eat ? action :
5969 i == Ykey_6_eat ? action :
5970 i == Ykey_7_eat ? action :
5971 i == Ykey_8_eat ? action :
5972 i == Ylenses_eat ? action :
5973 i == Ymagnify_eat ? action :
5974 i == Ygrass_eat ? action :
5975 i == Ydirt_eat ? action :
5976 i == Xsand_stonein_1 ? action :
5977 i == Xsand_stonein_2 ? action :
5978 i == Xsand_stonein_3 ? action :
5979 i == Xsand_stonein_4 ? action :
5980 i == Xsand_stoneout_1 ? action :
5981 i == Xsand_stoneout_2 ? action :
5982 i == Xboom_android ? ACTION_EXPLODING :
5983 action_exploding ? ACTION_EXPLODING :
5984 action_active ? action :
5985 action_other ? action :
5987 int graphic = (el_act_dir2img(effective_element, effective_action,
5989 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5991 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5992 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5993 boolean has_action_graphics = (graphic != base_graphic);
5994 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5995 struct GraphicInfo *g = &graphic_info[graphic];
5996 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5999 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6000 boolean special_animation = (action != ACTION_DEFAULT &&
6001 g->anim_frames == 3 &&
6002 g->anim_delay == 2 &&
6003 g->anim_mode & ANIM_LINEAR);
6004 int sync_frame = (i == Xdrip_stretch ? 7 :
6005 i == Xdrip_stretchB ? 7 :
6006 i == Ydrip_s2 ? j + 8 :
6007 i == Ydrip_s2B ? j + 8 :
6016 i == Xfake_acid_1 ? 0 :
6017 i == Xfake_acid_2 ? 10 :
6018 i == Xfake_acid_3 ? 20 :
6019 i == Xfake_acid_4 ? 30 :
6020 i == Xfake_acid_5 ? 40 :
6021 i == Xfake_acid_6 ? 50 :
6022 i == Xfake_acid_7 ? 60 :
6023 i == Xfake_acid_8 ? 70 :
6025 i == Xball_2B ? j + 8 :
6026 i == Yball_eat ? j + 1 :
6027 i == Ykey_1_eat ? j + 1 :
6028 i == Ykey_2_eat ? j + 1 :
6029 i == Ykey_3_eat ? j + 1 :
6030 i == Ykey_4_eat ? j + 1 :
6031 i == Ykey_5_eat ? j + 1 :
6032 i == Ykey_6_eat ? j + 1 :
6033 i == Ykey_7_eat ? j + 1 :
6034 i == Ykey_8_eat ? j + 1 :
6035 i == Ylenses_eat ? j + 1 :
6036 i == Ymagnify_eat ? j + 1 :
6037 i == Ygrass_eat ? j + 1 :
6038 i == Ydirt_eat ? j + 1 :
6039 i == Xamoeba_1 ? 0 :
6040 i == Xamoeba_2 ? 1 :
6041 i == Xamoeba_3 ? 2 :
6042 i == Xamoeba_4 ? 3 :
6043 i == Xamoeba_5 ? 0 :
6044 i == Xamoeba_6 ? 1 :
6045 i == Xamoeba_7 ? 2 :
6046 i == Xamoeba_8 ? 3 :
6047 i == Xexit_2 ? j + 8 :
6048 i == Xexit_3 ? j + 16 :
6049 i == Xdynamite_1 ? 0 :
6050 i == Xdynamite_2 ? 8 :
6051 i == Xdynamite_3 ? 16 :
6052 i == Xdynamite_4 ? 24 :
6053 i == Xsand_stonein_1 ? j + 1 :
6054 i == Xsand_stonein_2 ? j + 9 :
6055 i == Xsand_stonein_3 ? j + 17 :
6056 i == Xsand_stonein_4 ? j + 25 :
6057 i == Xsand_stoneout_1 && j == 0 ? 0 :
6058 i == Xsand_stoneout_1 && j == 1 ? 0 :
6059 i == Xsand_stoneout_1 && j == 2 ? 1 :
6060 i == Xsand_stoneout_1 && j == 3 ? 2 :
6061 i == Xsand_stoneout_1 && j == 4 ? 2 :
6062 i == Xsand_stoneout_1 && j == 5 ? 3 :
6063 i == Xsand_stoneout_1 && j == 6 ? 4 :
6064 i == Xsand_stoneout_1 && j == 7 ? 4 :
6065 i == Xsand_stoneout_2 && j == 0 ? 5 :
6066 i == Xsand_stoneout_2 && j == 1 ? 6 :
6067 i == Xsand_stoneout_2 && j == 2 ? 7 :
6068 i == Xsand_stoneout_2 && j == 3 ? 8 :
6069 i == Xsand_stoneout_2 && j == 4 ? 9 :
6070 i == Xsand_stoneout_2 && j == 5 ? 11 :
6071 i == Xsand_stoneout_2 && j == 6 ? 13 :
6072 i == Xsand_stoneout_2 && j == 7 ? 15 :
6073 i == Xboom_bug && j == 1 ? 2 :
6074 i == Xboom_bug && j == 2 ? 2 :
6075 i == Xboom_bug && j == 3 ? 4 :
6076 i == Xboom_bug && j == 4 ? 4 :
6077 i == Xboom_bug && j == 5 ? 2 :
6078 i == Xboom_bug && j == 6 ? 2 :
6079 i == Xboom_bug && j == 7 ? 0 :
6080 i == Xboom_bomb && j == 1 ? 2 :
6081 i == Xboom_bomb && j == 2 ? 2 :
6082 i == Xboom_bomb && j == 3 ? 4 :
6083 i == Xboom_bomb && j == 4 ? 4 :
6084 i == Xboom_bomb && j == 5 ? 2 :
6085 i == Xboom_bomb && j == 6 ? 2 :
6086 i == Xboom_bomb && j == 7 ? 0 :
6087 i == Xboom_android && j == 7 ? 6 :
6088 i == Xboom_1 && j == 1 ? 2 :
6089 i == Xboom_1 && j == 2 ? 2 :
6090 i == Xboom_1 && j == 3 ? 4 :
6091 i == Xboom_1 && j == 4 ? 4 :
6092 i == Xboom_1 && j == 5 ? 6 :
6093 i == Xboom_1 && j == 6 ? 6 :
6094 i == Xboom_1 && j == 7 ? 8 :
6095 i == Xboom_2 && j == 0 ? 8 :
6096 i == Xboom_2 && j == 1 ? 8 :
6097 i == Xboom_2 && j == 2 ? 10 :
6098 i == Xboom_2 && j == 3 ? 10 :
6099 i == Xboom_2 && j == 4 ? 10 :
6100 i == Xboom_2 && j == 5 ? 12 :
6101 i == Xboom_2 && j == 6 ? 12 :
6102 i == Xboom_2 && j == 7 ? 12 :
6103 special_animation && j == 4 ? 3 :
6104 effective_action != action ? 0 :
6108 Bitmap *debug_bitmap = g_em->bitmap;
6109 int debug_src_x = g_em->src_x;
6110 int debug_src_y = g_em->src_y;
6113 int frame = getAnimationFrame(g->anim_frames,
6116 g->anim_start_frame,
6119 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6120 g->double_movement && is_backside);
6122 g_em->bitmap = src_bitmap;
6123 g_em->src_x = src_x;
6124 g_em->src_y = src_y;
6125 g_em->src_offset_x = 0;
6126 g_em->src_offset_y = 0;
6127 g_em->dst_offset_x = 0;
6128 g_em->dst_offset_y = 0;
6129 g_em->width = TILEX;
6130 g_em->height = TILEY;
6132 g_em->crumbled_bitmap = NULL;
6133 g_em->crumbled_src_x = 0;
6134 g_em->crumbled_src_y = 0;
6135 g_em->crumbled_border_size = 0;
6137 g_em->has_crumbled_graphics = FALSE;
6138 g_em->preserve_background = FALSE;
6141 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6142 printf("::: empty crumbled: %d [%s], %d, %d\n",
6143 effective_element, element_info[effective_element].token_name,
6144 effective_action, direction);
6147 /* if element can be crumbled, but certain action graphics are just empty
6148 space (like snapping sand with the original R'n'D graphics), do not
6149 treat these empty space graphics as crumbled graphics in EMC engine */
6150 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6152 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6154 g_em->has_crumbled_graphics = TRUE;
6155 g_em->crumbled_bitmap = src_bitmap;
6156 g_em->crumbled_src_x = src_x;
6157 g_em->crumbled_src_y = src_y;
6158 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6162 if (element == EL_ROCK &&
6163 effective_action == ACTION_FILLING)
6164 printf("::: has_action_graphics == %d\n", has_action_graphics);
6167 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6168 effective_action == ACTION_MOVING ||
6169 effective_action == ACTION_PUSHING ||
6170 effective_action == ACTION_EATING)) ||
6171 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6172 effective_action == ACTION_EMPTYING)))
6175 (effective_action == ACTION_FALLING ||
6176 effective_action == ACTION_FILLING ||
6177 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6178 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6179 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6180 int num_steps = (i == Ydrip_s1 ? 16 :
6181 i == Ydrip_s1B ? 16 :
6182 i == Ydrip_s2 ? 16 :
6183 i == Ydrip_s2B ? 16 :
6184 i == Xsand_stonein_1 ? 32 :
6185 i == Xsand_stonein_2 ? 32 :
6186 i == Xsand_stonein_3 ? 32 :
6187 i == Xsand_stonein_4 ? 32 :
6188 i == Xsand_stoneout_1 ? 16 :
6189 i == Xsand_stoneout_2 ? 16 : 8);
6190 int cx = ABS(dx) * (TILEX / num_steps);
6191 int cy = ABS(dy) * (TILEY / num_steps);
6192 int step_frame = (i == Ydrip_s2 ? j + 8 :
6193 i == Ydrip_s2B ? j + 8 :
6194 i == Xsand_stonein_2 ? j + 8 :
6195 i == Xsand_stonein_3 ? j + 16 :
6196 i == Xsand_stonein_4 ? j + 24 :
6197 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6198 int step = (is_backside ? step_frame : num_steps - step_frame);
6200 if (is_backside) /* tile where movement starts */
6202 if (dx < 0 || dy < 0)
6204 g_em->src_offset_x = cx * step;
6205 g_em->src_offset_y = cy * step;
6209 g_em->dst_offset_x = cx * step;
6210 g_em->dst_offset_y = cy * step;
6213 else /* tile where movement ends */
6215 if (dx < 0 || dy < 0)
6217 g_em->dst_offset_x = cx * step;
6218 g_em->dst_offset_y = cy * step;
6222 g_em->src_offset_x = cx * step;
6223 g_em->src_offset_y = cy * step;
6227 g_em->width = TILEX - cx * step;
6228 g_em->height = TILEY - cy * step;
6231 /* create unique graphic identifier to decide if tile must be redrawn */
6232 /* bit 31 - 16 (16 bit): EM style graphic
6233 bit 15 - 12 ( 4 bit): EM style frame
6234 bit 11 - 6 ( 6 bit): graphic width
6235 bit 5 - 0 ( 6 bit): graphic height */
6236 g_em->unique_identifier =
6237 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6241 /* skip check for EMC elements not contained in original EMC artwork */
6242 if (element == EL_EMC_FAKE_ACID)
6245 if (g_em->bitmap != debug_bitmap ||
6246 g_em->src_x != debug_src_x ||
6247 g_em->src_y != debug_src_y ||
6248 g_em->src_offset_x != 0 ||
6249 g_em->src_offset_y != 0 ||
6250 g_em->dst_offset_x != 0 ||
6251 g_em->dst_offset_y != 0 ||
6252 g_em->width != TILEX ||
6253 g_em->height != TILEY)
6255 static int last_i = -1;
6263 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6264 i, element, element_info[element].token_name,
6265 element_action_info[effective_action].suffix, direction);
6267 if (element != effective_element)
6268 printf(" [%d ('%s')]",
6270 element_info[effective_element].token_name);
6274 if (g_em->bitmap != debug_bitmap)
6275 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6276 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6278 if (g_em->src_x != debug_src_x ||
6279 g_em->src_y != debug_src_y)
6280 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6281 j, (is_backside ? 'B' : 'F'),
6282 g_em->src_x, g_em->src_y,
6283 g_em->src_x / 32, g_em->src_y / 32,
6284 debug_src_x, debug_src_y,
6285 debug_src_x / 32, debug_src_y / 32);
6287 if (g_em->src_offset_x != 0 ||
6288 g_em->src_offset_y != 0 ||
6289 g_em->dst_offset_x != 0 ||
6290 g_em->dst_offset_y != 0)
6291 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6293 g_em->src_offset_x, g_em->src_offset_y,
6294 g_em->dst_offset_x, g_em->dst_offset_y);
6296 if (g_em->width != TILEX ||
6297 g_em->height != TILEY)
6298 printf(" %d (%d): size %d,%d should be %d,%d\n",
6300 g_em->width, g_em->height, TILEX, TILEY);
6302 num_em_gfx_errors++;
6309 for (i = 0; i < TILE_MAX; i++)
6311 for (j = 0; j < 8; j++)
6313 int element = object_mapping[i].element_rnd;
6314 int action = object_mapping[i].action;
6315 int direction = object_mapping[i].direction;
6316 boolean is_backside = object_mapping[i].is_backside;
6317 int graphic_action = el_act_dir2img(element, action, direction);
6318 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6320 if ((action == ACTION_SMASHED_BY_ROCK ||
6321 action == ACTION_SMASHED_BY_SPRING ||
6322 action == ACTION_EATING) &&
6323 graphic_action == graphic_default)
6325 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6326 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6327 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6328 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6331 /* no separate animation for "smashed by rock" -- use rock instead */
6332 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6333 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6335 g_em->bitmap = g_xx->bitmap;
6336 g_em->src_x = g_xx->src_x;
6337 g_em->src_y = g_xx->src_y;
6338 g_em->src_offset_x = g_xx->src_offset_x;
6339 g_em->src_offset_y = g_xx->src_offset_y;
6340 g_em->dst_offset_x = g_xx->dst_offset_x;
6341 g_em->dst_offset_y = g_xx->dst_offset_y;
6342 g_em->width = g_xx->width;
6343 g_em->height = g_xx->height;
6344 g_em->unique_identifier = g_xx->unique_identifier;
6347 g_em->preserve_background = TRUE;
6352 for (p = 0; p < MAX_PLAYERS; p++)
6354 for (i = 0; i < SPR_MAX; i++)
6356 int element = player_mapping[p][i].element_rnd;
6357 int action = player_mapping[p][i].action;
6358 int direction = player_mapping[p][i].direction;
6360 for (j = 0; j < 8; j++)
6362 int effective_element = element;
6363 int effective_action = action;
6364 int graphic = (direction == MV_NONE ?
6365 el_act2img(effective_element, effective_action) :
6366 el_act_dir2img(effective_element, effective_action,
6368 struct GraphicInfo *g = &graphic_info[graphic];
6369 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6375 Bitmap *debug_bitmap = g_em->bitmap;
6376 int debug_src_x = g_em->src_x;
6377 int debug_src_y = g_em->src_y;
6380 int frame = getAnimationFrame(g->anim_frames,
6383 g->anim_start_frame,
6386 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6388 g_em->bitmap = src_bitmap;
6389 g_em->src_x = src_x;
6390 g_em->src_y = src_y;
6391 g_em->src_offset_x = 0;
6392 g_em->src_offset_y = 0;
6393 g_em->dst_offset_x = 0;
6394 g_em->dst_offset_y = 0;
6395 g_em->width = TILEX;
6396 g_em->height = TILEY;
6400 /* skip check for EMC elements not contained in original EMC artwork */
6401 if (element == EL_PLAYER_3 ||
6402 element == EL_PLAYER_4)
6405 if (g_em->bitmap != debug_bitmap ||
6406 g_em->src_x != debug_src_x ||
6407 g_em->src_y != debug_src_y)
6409 static int last_i = -1;
6417 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6418 p, i, element, element_info[element].token_name,
6419 element_action_info[effective_action].suffix, direction);
6421 if (element != effective_element)
6422 printf(" [%d ('%s')]",
6424 element_info[effective_element].token_name);
6428 if (g_em->bitmap != debug_bitmap)
6429 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6430 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6432 if (g_em->src_x != debug_src_x ||
6433 g_em->src_y != debug_src_y)
6434 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6436 g_em->src_x, g_em->src_y,
6437 g_em->src_x / 32, g_em->src_y / 32,
6438 debug_src_x, debug_src_y,
6439 debug_src_x / 32, debug_src_y / 32);
6441 num_em_gfx_errors++;
6451 printf("::: [%d errors found]\n", num_em_gfx_errors);
6457 void PlayMenuSoundExt(int sound)
6459 if (sound == SND_UNDEFINED)
6462 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6463 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6466 if (IS_LOOP_SOUND(sound))
6467 PlaySoundLoop(sound);
6472 void PlayMenuSound()
6474 PlayMenuSoundExt(menu.sound[game_status]);
6477 void PlayMenuSoundStereo(int sound, int stereo_position)
6479 if (sound == SND_UNDEFINED)
6482 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6483 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6486 if (IS_LOOP_SOUND(sound))
6487 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6489 PlaySoundStereo(sound, stereo_position);
6492 void PlayMenuSoundIfLoopExt(int sound)
6494 if (sound == SND_UNDEFINED)
6497 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6498 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6501 if (IS_LOOP_SOUND(sound))
6502 PlaySoundLoop(sound);
6505 void PlayMenuSoundIfLoop()
6507 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6510 void PlayMenuMusicExt(int music)
6512 if (music == MUS_UNDEFINED)
6515 if (!setup.sound_music)
6521 void PlayMenuMusic()
6523 PlayMenuMusicExt(menu.music[game_status]);
6526 void PlaySoundActivating()
6529 PlaySound(SND_MENU_ITEM_ACTIVATING);
6533 void PlaySoundSelecting()
6536 PlaySound(SND_MENU_ITEM_SELECTING);
6540 void ToggleFullscreenIfNeeded()
6542 boolean change_fullscreen = (setup.fullscreen !=
6543 video.fullscreen_enabled);
6544 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6545 !strEqual(setup.fullscreen_mode,
6546 video.fullscreen_mode_current));
6548 if (!video.fullscreen_available)
6552 if (change_fullscreen || change_fullscreen_mode)
6554 if (setup.fullscreen != video.fullscreen_enabled ||
6555 setup.fullscreen_mode != video.fullscreen_mode_current)
6558 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6560 /* save backbuffer content which gets lost when toggling fullscreen mode */
6561 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6564 if (change_fullscreen_mode)
6566 if (setup.fullscreen && video.fullscreen_enabled)
6569 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6571 /* (this is now set in sdl.c) */
6573 video.fullscreen_mode_current = setup.fullscreen_mode;
6575 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6578 /* toggle fullscreen */
6579 ChangeVideoModeIfNeeded(setup.fullscreen);
6581 setup.fullscreen = video.fullscreen_enabled;
6583 /* restore backbuffer content from temporary backbuffer backup bitmap */
6584 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6586 FreeBitmap(tmp_backbuffer);
6589 /* update visible window/screen */
6590 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6592 redraw_mask = REDRAW_ALL;