1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX 0
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES 0
30 #define TOOL_CTRL_ID_NO 1
31 #define TOOL_CTRL_ID_CONFIRM 2
32 #define TOOL_CTRL_ID_PLAYER_1 3
33 #define TOOL_CTRL_ID_PLAYER_2 4
34 #define TOOL_CTRL_ID_PLAYER_3 5
35 #define TOOL_CTRL_ID_PLAYER_4 6
37 #define NUM_TOOL_BUTTONS 7
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
48 static char *print_if_not_empty(int element)
50 static char *s = NULL;
51 char *token_name = element_info[element].token_name;
56 s = checked_malloc(strlen(token_name) + 10 + 1);
58 if (element != EL_EMPTY)
59 sprintf(s, "%d\t['%s']", element, token_name);
61 sprintf(s, "%d", element);
66 void DumpTile(int x, int y)
71 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
78 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
81 if (!IN_LEV_FIELD(x, y))
83 printf("(not in level field)\n");
89 printf(" Feld: %d\t['%s']\n", Feld[x][y],
90 element_info[Feld[x][y]].token_name);
91 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
92 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
93 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
94 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95 printf(" MovPos: %d\n", MovPos[x][y]);
96 printf(" MovDir: %d\n", MovDir[x][y]);
97 printf(" MovDelay: %d\n", MovDelay[x][y]);
98 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
99 printf(" CustomValue: %d\n", CustomValue[x][y]);
100 printf(" GfxElement: %d\n", GfxElement[x][y]);
101 printf(" GfxAction: %d\n", GfxAction[x][y]);
102 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
106 void SetDrawtoField(int mode)
108 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
119 drawto_field = fieldbuffer;
121 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
138 if (game_status == GAME_MODE_PLAYING &&
139 level.game_engine_type == GAME_ENGINE_TYPE_EM)
141 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
153 width = gfx.sxsize + 2 * TILEX;
154 height = gfx.sysize + 2 * TILEY;
157 if (force_redraw || setup.direct_draw)
160 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
163 if (setup.direct_draw)
164 SetDrawtoField(DRAW_BACKBUFFER);
166 for (xx = BX1; xx <= BX2; xx++)
167 for (yy = BY1; yy <= BY2; yy++)
168 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
169 DrawScreenField(xx, yy);
172 if (setup.direct_draw)
173 SetDrawtoField(DRAW_DIRECT);
176 if (setup.soft_scrolling)
178 int fx = FX, fy = FY;
180 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
181 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
183 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
195 BlitBitmap(drawto, window, x, y, width, height, x, y);
198 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
200 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
202 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
203 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
206 void DrawMaskedBorder_FIELD()
208 if (game_status >= GAME_MODE_TITLE &&
209 game_status <= GAME_MODE_PLAYING &&
210 border.draw_masked[game_status])
211 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
214 void DrawMaskedBorder_DOOR_1()
216 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
217 (game_status != GAME_MODE_EDITOR ||
218 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
219 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
222 void DrawMaskedBorder_DOOR_2()
224 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
225 game_status != GAME_MODE_EDITOR)
226 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
229 void DrawMaskedBorder_DOOR_3()
231 /* currently not available */
234 void DrawMaskedBorder_ALL()
236 DrawMaskedBorder_FIELD();
237 DrawMaskedBorder_DOOR_1();
238 DrawMaskedBorder_DOOR_2();
239 DrawMaskedBorder_DOOR_3();
242 void DrawMaskedBorder(int redraw_mask)
244 /* do not draw masked screen borders when displaying title screens */
245 if (effectiveGameStatus() == GAME_MODE_TITLE ||
246 effectiveGameStatus() == GAME_MODE_MESSAGE)
249 if (redraw_mask & REDRAW_ALL)
250 DrawMaskedBorder_ALL();
253 if (redraw_mask & REDRAW_FIELD)
254 DrawMaskedBorder_FIELD();
255 if (redraw_mask & REDRAW_DOOR_1)
256 DrawMaskedBorder_DOOR_1();
257 if (redraw_mask & REDRAW_DOOR_2)
258 DrawMaskedBorder_DOOR_2();
259 if (redraw_mask & REDRAW_DOOR_3)
260 DrawMaskedBorder_DOOR_3();
267 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
269 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
270 redraw_mask &= ~REDRAW_MAIN;
272 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
273 redraw_mask |= REDRAW_FIELD;
275 if (redraw_mask & REDRAW_FIELD)
276 redraw_mask &= ~REDRAW_TILES;
278 if (redraw_mask == REDRAW_NONE)
281 if (redraw_mask & REDRAW_TILES &&
282 game_status == GAME_MODE_PLAYING &&
283 border.draw_masked[GAME_MODE_PLAYING])
284 redraw_mask |= REDRAW_FIELD;
286 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
288 static boolean last_frame_skipped = FALSE;
289 boolean skip_even_when_not_scrolling = TRUE;
290 boolean just_scrolling = (ScreenMovDir != 0);
291 boolean verbose = FALSE;
293 if (global.fps_slowdown_factor > 1 &&
294 (FrameCounter % global.fps_slowdown_factor) &&
295 (just_scrolling || skip_even_when_not_scrolling))
297 redraw_mask &= ~REDRAW_MAIN;
299 last_frame_skipped = TRUE;
302 printf("FRAME SKIPPED\n");
306 if (last_frame_skipped)
307 redraw_mask |= REDRAW_FIELD;
309 last_frame_skipped = FALSE;
312 printf("frame not skipped\n");
316 /* synchronize X11 graphics at this point; if we would synchronize the
317 display immediately after the buffer switching (after the XFlush),
318 this could mean that we have to wait for the graphics to complete,
319 although we could go on doing calculations for the next frame */
323 /* prevent drawing masked border to backbuffer when using playfield buffer */
324 if (game_status != GAME_MODE_PLAYING ||
325 redraw_mask & REDRAW_FROM_BACKBUFFER ||
326 buffer == backbuffer)
327 DrawMaskedBorder(redraw_mask);
329 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
331 if (redraw_mask & REDRAW_ALL)
333 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
335 redraw_mask = REDRAW_NONE;
338 if (redraw_mask & REDRAW_FIELD)
340 if (game_status != GAME_MODE_PLAYING ||
341 redraw_mask & REDRAW_FROM_BACKBUFFER)
343 BlitBitmap(backbuffer, window,
344 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
348 int fx = FX, fy = FY;
350 if (setup.soft_scrolling)
352 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
353 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
356 if (setup.soft_scrolling ||
357 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
358 ABS(ScreenMovPos) == ScrollStepSize ||
359 redraw_tiles > REDRAWTILES_THRESHOLD)
361 if (border.draw_masked[GAME_MODE_PLAYING])
363 if (buffer != backbuffer)
365 /* copy playfield buffer to backbuffer to add masked border */
366 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
367 DrawMaskedBorder(REDRAW_FIELD);
370 BlitBitmap(backbuffer, window,
371 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
376 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
381 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
383 (setup.soft_scrolling ?
384 "setup.soft_scrolling" :
385 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
386 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
387 ABS(ScreenGfxPos) == ScrollStepSize ?
388 "ABS(ScreenGfxPos) == ScrollStepSize" :
389 "redraw_tiles > REDRAWTILES_THRESHOLD"));
395 redraw_mask &= ~REDRAW_MAIN;
398 if (redraw_mask & REDRAW_DOORS)
400 if (redraw_mask & REDRAW_DOOR_1)
401 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
403 if (redraw_mask & REDRAW_DOOR_2)
404 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
406 if (redraw_mask & REDRAW_DOOR_3)
407 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
409 redraw_mask &= ~REDRAW_DOORS;
412 if (redraw_mask & REDRAW_MICROLEVEL)
414 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
415 SX, SY + 10 * TILEY);
417 redraw_mask &= ~REDRAW_MICROLEVEL;
420 if (redraw_mask & REDRAW_TILES)
422 for (x = 0; x < SCR_FIELDX; x++)
423 for (y = 0 ; y < SCR_FIELDY; y++)
424 if (redraw[redraw_x1 + x][redraw_y1 + y])
425 BlitBitmap(buffer, window,
426 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
427 SX + x * TILEX, SY + y * TILEY);
430 if (redraw_mask & REDRAW_FPS) /* display frames per second */
435 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
436 if (!global.fps_slowdown)
439 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
440 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
445 for (x = 0; x < MAX_BUF_XSIZE; x++)
446 for (y = 0; y < MAX_BUF_YSIZE; y++)
449 redraw_mask = REDRAW_NONE;
455 long fading_delay = 300;
457 if (setup.fading && (redraw_mask & REDRAW_FIELD))
464 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
467 for (i = 0; i < 2 * FULL_SYSIZE; i++)
469 for (y = 0; y < FULL_SYSIZE; y++)
471 BlitBitmap(backbuffer, window,
472 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
480 for (i = 1; i < FULL_SYSIZE; i+=2)
481 BlitBitmap(backbuffer, window,
482 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
488 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
489 BlitBitmapMasked(backbuffer, window,
490 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
495 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
496 BlitBitmapMasked(backbuffer, window,
497 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
502 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
503 BlitBitmapMasked(backbuffer, window,
504 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
509 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
510 BlitBitmapMasked(backbuffer, window,
511 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
516 redraw_mask &= ~REDRAW_MAIN;
523 void FadeExt(int fade_mask, int fade_mode)
525 void (*draw_border_function)(void) = NULL;
526 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
527 int x, y, width, height;
528 int fade_delay, post_delay;
530 if (fade_mask & REDRAW_FIELD)
535 height = FULL_SYSIZE;
537 fade_delay = menu.fade_delay;
538 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
540 draw_border_function = DrawMaskedBorder_FIELD;
542 else /* REDRAW_ALL */
549 fade_delay = title.fade_delay_final;
550 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? title.post_delay_final : 0);
553 redraw_mask |= fade_mask;
555 if (!setup.fade_screens || fade_delay == 0)
557 if (fade_mode == FADE_MODE_FADE_OUT)
558 ClearRectangle(backbuffer, x, y, width, height);
565 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
566 draw_border_function);
568 redraw_mask &= ~fade_mask;
571 void FadeIn(int fade_mask)
573 FadeExt(fade_mask, FADE_MODE_FADE_IN);
576 void FadeOut(int fade_mask)
578 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
581 void FadeCross(int fade_mask)
583 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
586 void FadeCrossSaveBackbuffer()
588 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
591 void SetWindowBackgroundImageIfDefined(int graphic)
593 if (graphic_info[graphic].bitmap)
594 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
597 void SetMainBackgroundImageIfDefined(int graphic)
599 if (graphic_info[graphic].bitmap)
600 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
603 void SetDoorBackgroundImageIfDefined(int graphic)
605 if (graphic_info[graphic].bitmap)
606 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
609 void SetWindowBackgroundImage(int graphic)
611 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
612 graphic_info[graphic].bitmap ?
613 graphic_info[graphic].bitmap :
614 graphic_info[IMG_BACKGROUND].bitmap);
617 void SetMainBackgroundImage(int graphic)
619 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
620 graphic_info[graphic].bitmap ?
621 graphic_info[graphic].bitmap :
622 graphic_info[IMG_BACKGROUND].bitmap);
625 void SetDoorBackgroundImage(int graphic)
627 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
628 graphic_info[graphic].bitmap ?
629 graphic_info[graphic].bitmap :
630 graphic_info[IMG_BACKGROUND].bitmap);
633 void SetPanelBackground()
635 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
636 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
638 SetDoorBackgroundBitmap(bitmap_db_panel);
641 void DrawBackground(int x, int y, int width, int height)
643 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
644 /* (when entering hall of fame after playing) */
646 ClearRectangleOnBackground(drawto, x, y, width, height);
648 ClearRectangleOnBackground(backbuffer, x, y, width, height);
651 redraw_mask |= REDRAW_FIELD;
654 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
656 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
658 if (font->bitmap == NULL)
661 DrawBackground(x, y, width, height);
664 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
666 struct GraphicInfo *g = &graphic_info[graphic];
668 if (g->bitmap == NULL)
671 DrawBackground(x, y, width, height);
676 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
677 /* (when entering hall of fame after playing) */
678 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
680 /* !!! maybe this should be done before clearing the background !!! */
681 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
683 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
684 SetDrawtoField(DRAW_BUFFERED);
687 SetDrawtoField(DRAW_BACKBUFFER);
689 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
691 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
692 SetDrawtoField(DRAW_DIRECT);
696 void MarkTileDirty(int x, int y)
698 int xx = redraw_x1 + x;
699 int yy = redraw_y1 + y;
704 redraw[xx][yy] = TRUE;
705 redraw_mask |= REDRAW_TILES;
708 void SetBorderElement()
712 BorderElement = EL_EMPTY;
714 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
716 for (x = 0; x < lev_fieldx; x++)
718 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
719 BorderElement = EL_STEELWALL;
721 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
727 void FloodFillLevel(int from_x, int from_y, int fill_element,
728 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
729 int max_fieldx, int max_fieldy)
733 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
734 static int safety = 0;
736 /* check if starting field still has the desired content */
737 if (field[from_x][from_y] == fill_element)
742 if (safety > max_fieldx * max_fieldy)
743 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
745 old_element = field[from_x][from_y];
746 field[from_x][from_y] = fill_element;
748 for (i = 0; i < 4; i++)
750 x = from_x + check[i][0];
751 y = from_y + check[i][1];
753 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
754 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
760 void SetRandomAnimationValue(int x, int y)
762 gfx.anim_random_frame = GfxRandom[x][y];
765 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
767 /* animation synchronized with global frame counter, not move position */
768 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
769 sync_frame = FrameCounter;
771 return getAnimationFrame(graphic_info[graphic].anim_frames,
772 graphic_info[graphic].anim_delay,
773 graphic_info[graphic].anim_mode,
774 graphic_info[graphic].anim_start_frame,
778 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
779 int *x, int *y, boolean get_backside)
781 struct GraphicInfo *g = &graphic_info[graphic];
782 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
783 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
787 if (g->offset_y == 0) /* frames are ordered horizontally */
789 int max_width = g->anim_frames_per_line * g->width;
790 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
792 *x = pos % max_width;
793 *y = src_y % g->height + pos / max_width * g->height;
795 else if (g->offset_x == 0) /* frames are ordered vertically */
797 int max_height = g->anim_frames_per_line * g->height;
798 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
800 *x = src_x % g->width + pos / max_height * g->width;
801 *y = pos % max_height;
803 else /* frames are ordered diagonally */
805 *x = src_x + frame * g->offset_x;
806 *y = src_y + frame * g->offset_y;
810 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
812 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
815 void DrawGraphic(int x, int y, int graphic, int frame)
818 if (!IN_SCR_FIELD(x, y))
820 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
821 printf("DrawGraphic(): This should never happen!\n");
826 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
830 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
836 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
837 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
840 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
843 if (!IN_SCR_FIELD(x, y))
845 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
846 printf("DrawGraphicThruMask(): This should never happen!\n");
851 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
856 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
862 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
864 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
865 dst_x - src_x, dst_y - src_y);
866 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
869 void DrawMiniGraphic(int x, int y, int graphic)
871 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
872 MarkTileDirty(x / 2, y / 2);
875 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
877 struct GraphicInfo *g = &graphic_info[graphic];
879 int mini_starty = g->bitmap->height * 2 / 3;
882 *x = mini_startx + g->src_x / 2;
883 *y = mini_starty + g->src_y / 2;
886 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
891 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
892 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
895 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
896 int graphic, int frame,
897 int cut_mode, int mask_mode)
902 int width = TILEX, height = TILEY;
905 if (dx || dy) /* shifted graphic */
907 if (x < BX1) /* object enters playfield from the left */
914 else if (x > BX2) /* object enters playfield from the right */
920 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
926 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
928 else if (dx) /* general horizontal movement */
929 MarkTileDirty(x + SIGN(dx), y);
931 if (y < BY1) /* object enters playfield from the top */
933 if (cut_mode==CUT_BELOW) /* object completely above top border */
941 else if (y > BY2) /* object enters playfield from the bottom */
947 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
953 else if (dy > 0 && cut_mode == CUT_ABOVE)
955 if (y == BY2) /* object completely above bottom border */
961 MarkTileDirty(x, y + 1);
962 } /* object leaves playfield to the bottom */
963 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
965 else if (dy) /* general vertical movement */
966 MarkTileDirty(x, y + SIGN(dy));
970 if (!IN_SCR_FIELD(x, y))
972 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
973 printf("DrawGraphicShifted(): This should never happen!\n");
978 if (width > 0 && height > 0)
980 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
985 dst_x = FX + x * TILEX + dx;
986 dst_y = FY + y * TILEY + dy;
988 if (mask_mode == USE_MASKING)
990 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
991 dst_x - src_x, dst_y - src_y);
992 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
996 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1003 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1004 int graphic, int frame,
1005 int cut_mode, int mask_mode)
1010 int width = TILEX, height = TILEY;
1013 int x2 = x + SIGN(dx);
1014 int y2 = y + SIGN(dy);
1015 int anim_frames = graphic_info[graphic].anim_frames;
1016 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1017 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1018 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1020 /* re-calculate animation frame for two-tile movement animation */
1021 frame = getGraphicAnimationFrame(graphic, sync_frame);
1023 /* check if movement start graphic inside screen area and should be drawn */
1024 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1026 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1028 dst_x = FX + x1 * TILEX;
1029 dst_y = FY + y1 * TILEY;
1031 if (mask_mode == USE_MASKING)
1033 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1034 dst_x - src_x, dst_y - src_y);
1035 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1039 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1042 MarkTileDirty(x1, y1);
1045 /* check if movement end graphic inside screen area and should be drawn */
1046 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1048 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1050 dst_x = FX + x2 * TILEX;
1051 dst_y = FY + y2 * TILEY;
1053 if (mask_mode == USE_MASKING)
1055 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1056 dst_x - src_x, dst_y - src_y);
1057 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1061 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1064 MarkTileDirty(x2, y2);
1068 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1069 int graphic, int frame,
1070 int cut_mode, int mask_mode)
1074 DrawGraphic(x, y, graphic, frame);
1079 if (graphic_info[graphic].double_movement) /* EM style movement images */
1080 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1082 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1085 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1086 int frame, int cut_mode)
1088 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1091 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1092 int cut_mode, int mask_mode)
1094 int lx = LEVELX(x), ly = LEVELY(y);
1098 if (IN_LEV_FIELD(lx, ly))
1100 SetRandomAnimationValue(lx, ly);
1102 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1103 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1105 /* do not use double (EM style) movement graphic when not moving */
1106 if (graphic_info[graphic].double_movement && !dx && !dy)
1108 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1109 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1112 else /* border element */
1114 graphic = el2img(element);
1115 frame = getGraphicAnimationFrame(graphic, -1);
1118 if (element == EL_EXPANDABLE_WALL)
1120 boolean left_stopped = FALSE, right_stopped = FALSE;
1122 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1123 left_stopped = TRUE;
1124 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1125 right_stopped = TRUE;
1127 if (left_stopped && right_stopped)
1129 else if (left_stopped)
1131 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1132 frame = graphic_info[graphic].anim_frames - 1;
1134 else if (right_stopped)
1136 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1137 frame = graphic_info[graphic].anim_frames - 1;
1142 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1143 else if (mask_mode == USE_MASKING)
1144 DrawGraphicThruMask(x, y, graphic, frame);
1146 DrawGraphic(x, y, graphic, frame);
1149 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1150 int cut_mode, int mask_mode)
1152 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1153 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1154 cut_mode, mask_mode);
1157 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1160 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1163 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1166 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1169 void DrawLevelElementThruMask(int x, int y, int element)
1171 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1174 void DrawLevelFieldThruMask(int x, int y)
1176 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1179 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1183 int sx = SCREENX(x), sy = SCREENY(y);
1185 int width, height, cx, cy, i;
1186 int crumbled_border_size = graphic_info[graphic].border_size;
1187 static int xy[4][2] =
1195 if (!IN_LEV_FIELD(x, y))
1198 element = TILE_GFX_ELEMENT(x, y);
1200 /* crumble field itself */
1201 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1203 if (!IN_SCR_FIELD(sx, sy))
1206 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1208 for (i = 0; i < 4; i++)
1210 int xx = x + xy[i][0];
1211 int yy = y + xy[i][1];
1213 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1216 /* check if neighbour field is of same type */
1217 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1220 if (i == 1 || i == 2)
1222 width = crumbled_border_size;
1224 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1230 height = crumbled_border_size;
1232 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1235 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1236 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1239 MarkTileDirty(sx, sy);
1241 else /* crumble neighbour fields */
1243 for (i = 0; i < 4; i++)
1245 int xx = x + xy[i][0];
1246 int yy = y + xy[i][1];
1247 int sxx = sx + xy[i][0];
1248 int syy = sy + xy[i][1];
1250 if (!IN_LEV_FIELD(xx, yy) ||
1251 !IN_SCR_FIELD(sxx, syy) ||
1255 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1258 element = TILE_GFX_ELEMENT(xx, yy);
1260 if (!GFX_CRUMBLED(element))
1263 graphic = el_act2crm(element, ACTION_DEFAULT);
1264 crumbled_border_size = graphic_info[graphic].border_size;
1266 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1268 if (i == 1 || i == 2)
1270 width = crumbled_border_size;
1272 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1278 height = crumbled_border_size;
1280 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1283 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1284 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1286 MarkTileDirty(sxx, syy);
1291 void DrawLevelFieldCrumbledSand(int x, int y)
1295 if (!IN_LEV_FIELD(x, y))
1299 /* !!! CHECK THIS !!! */
1302 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1303 GFX_CRUMBLED(GfxElement[x][y]))
1306 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1307 GfxElement[x][y] != EL_UNDEFINED &&
1308 GFX_CRUMBLED(GfxElement[x][y]))
1310 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1317 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1319 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1322 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1325 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1328 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1329 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1330 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1331 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1332 int sx = SCREENX(x), sy = SCREENY(y);
1334 DrawGraphic(sx, sy, graphic1, frame1);
1335 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1338 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1340 int sx = SCREENX(x), sy = SCREENY(y);
1341 static int xy[4][2] =
1350 for (i = 0; i < 4; i++)
1352 int xx = x + xy[i][0];
1353 int yy = y + xy[i][1];
1354 int sxx = sx + xy[i][0];
1355 int syy = sy + xy[i][1];
1357 if (!IN_LEV_FIELD(xx, yy) ||
1358 !IN_SCR_FIELD(sxx, syy) ||
1359 !GFX_CRUMBLED(Feld[xx][yy]) ||
1363 DrawLevelField(xx, yy);
1367 static int getBorderElement(int x, int y)
1371 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1372 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1373 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1374 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1375 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1376 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1377 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1379 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1380 int steel_position = (x == -1 && y == -1 ? 0 :
1381 x == lev_fieldx && y == -1 ? 1 :
1382 x == -1 && y == lev_fieldy ? 2 :
1383 x == lev_fieldx && y == lev_fieldy ? 3 :
1384 x == -1 || x == lev_fieldx ? 4 :
1385 y == -1 || y == lev_fieldy ? 5 : 6);
1387 return border[steel_position][steel_type];
1390 void DrawScreenElement(int x, int y, int element)
1392 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1393 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1396 void DrawLevelElement(int x, int y, int element)
1398 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1399 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1402 void DrawScreenField(int x, int y)
1404 int lx = LEVELX(x), ly = LEVELY(y);
1405 int element, content;
1407 if (!IN_LEV_FIELD(lx, ly))
1409 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1412 element = getBorderElement(lx, ly);
1414 DrawScreenElement(x, y, element);
1418 element = Feld[lx][ly];
1419 content = Store[lx][ly];
1421 if (IS_MOVING(lx, ly))
1423 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1424 boolean cut_mode = NO_CUTTING;
1426 if (element == EL_QUICKSAND_EMPTYING ||
1427 element == EL_QUICKSAND_FAST_EMPTYING ||
1428 element == EL_MAGIC_WALL_EMPTYING ||
1429 element == EL_BD_MAGIC_WALL_EMPTYING ||
1430 element == EL_DC_MAGIC_WALL_EMPTYING ||
1431 element == EL_AMOEBA_DROPPING)
1432 cut_mode = CUT_ABOVE;
1433 else if (element == EL_QUICKSAND_FILLING ||
1434 element == EL_QUICKSAND_FAST_FILLING ||
1435 element == EL_MAGIC_WALL_FILLING ||
1436 element == EL_BD_MAGIC_WALL_FILLING ||
1437 element == EL_DC_MAGIC_WALL_FILLING)
1438 cut_mode = CUT_BELOW;
1440 if (cut_mode == CUT_ABOVE)
1441 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1443 DrawScreenElement(x, y, EL_EMPTY);
1446 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1447 else if (cut_mode == NO_CUTTING)
1448 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1450 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1452 if (content == EL_ACID)
1454 int dir = MovDir[lx][ly];
1455 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1456 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1458 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1461 else if (IS_BLOCKED(lx, ly))
1466 boolean cut_mode = NO_CUTTING;
1467 int element_old, content_old;
1469 Blocked2Moving(lx, ly, &oldx, &oldy);
1472 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1473 MovDir[oldx][oldy] == MV_RIGHT);
1475 element_old = Feld[oldx][oldy];
1476 content_old = Store[oldx][oldy];
1478 if (element_old == EL_QUICKSAND_EMPTYING ||
1479 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1480 element_old == EL_MAGIC_WALL_EMPTYING ||
1481 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1482 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1483 element_old == EL_AMOEBA_DROPPING)
1484 cut_mode = CUT_ABOVE;
1486 DrawScreenElement(x, y, EL_EMPTY);
1489 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1491 else if (cut_mode == NO_CUTTING)
1492 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1495 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1498 else if (IS_DRAWABLE(element))
1499 DrawScreenElement(x, y, element);
1501 DrawScreenElement(x, y, EL_EMPTY);
1504 void DrawLevelField(int x, int y)
1506 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1507 DrawScreenField(SCREENX(x), SCREENY(y));
1508 else if (IS_MOVING(x, y))
1512 Moving2Blocked(x, y, &newx, &newy);
1513 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1514 DrawScreenField(SCREENX(newx), SCREENY(newy));
1516 else if (IS_BLOCKED(x, y))
1520 Blocked2Moving(x, y, &oldx, &oldy);
1521 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1522 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1526 void DrawMiniElement(int x, int y, int element)
1530 graphic = el2edimg(element);
1531 DrawMiniGraphic(x, y, graphic);
1534 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1536 int x = sx + scroll_x, y = sy + scroll_y;
1538 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1539 DrawMiniElement(sx, sy, EL_EMPTY);
1540 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1541 DrawMiniElement(sx, sy, Feld[x][y]);
1543 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1546 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1547 int x, int y, int xsize, int ysize, int font_nr)
1549 int font_width = getFontWidth(font_nr);
1550 int font_height = getFontHeight(font_nr);
1551 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1554 int dst_x = SX + startx + x * font_width;
1555 int dst_y = SY + starty + y * font_height;
1556 int width = graphic_info[graphic].width;
1557 int height = graphic_info[graphic].height;
1558 int inner_width = MAX(width - 2 * font_width, font_width);
1559 int inner_height = MAX(height - 2 * font_height, font_height);
1560 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1561 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1562 boolean draw_masked = graphic_info[graphic].draw_masked;
1564 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1566 if (src_bitmap == NULL || width < font_width || height < font_height)
1568 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1572 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1573 inner_sx + (x - 1) * font_width % inner_width);
1574 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1575 inner_sy + (y - 1) * font_height % inner_height);
1579 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1580 dst_x - src_x, dst_y - src_y);
1581 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1585 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1589 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1591 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1592 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1593 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1594 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1595 boolean no_delay = (tape.warp_forward);
1596 unsigned long anim_delay = 0;
1597 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1598 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1599 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1600 int font_width = getFontWidth(font_nr);
1601 int font_height = getFontHeight(font_nr);
1602 int max_xsize = level.envelope[envelope_nr].xsize;
1603 int max_ysize = level.envelope[envelope_nr].ysize;
1604 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1605 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1606 int xend = max_xsize;
1607 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1608 int xstep = (xstart < xend ? 1 : 0);
1609 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1612 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1614 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1615 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1616 int sx = (SXSIZE - xsize * font_width) / 2;
1617 int sy = (SYSIZE - ysize * font_height) / 2;
1620 SetDrawtoField(DRAW_BUFFERED);
1622 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1624 SetDrawtoField(DRAW_BACKBUFFER);
1626 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1627 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1630 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1631 level.envelope[envelope_nr].text, font_nr, max_xsize,
1632 xsize - 2, ysize - 2, mask_mode,
1633 level.envelope[envelope_nr].autowrap,
1634 level.envelope[envelope_nr].centered, FALSE);
1636 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1637 level.envelope[envelope_nr].text, font_nr, max_xsize,
1638 xsize - 2, ysize - 2, mask_mode);
1641 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1644 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1648 void ShowEnvelope(int envelope_nr)
1650 int element = EL_ENVELOPE_1 + envelope_nr;
1651 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1652 int sound_opening = element_info[element].sound[ACTION_OPENING];
1653 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1654 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1655 boolean no_delay = (tape.warp_forward);
1656 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1657 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1658 int anim_mode = graphic_info[graphic].anim_mode;
1659 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1660 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1662 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1664 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1666 if (anim_mode == ANIM_DEFAULT)
1667 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1669 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1672 Delay(wait_delay_value);
1674 WaitForEventToContinue();
1676 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1678 if (anim_mode != ANIM_NONE)
1679 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1681 if (anim_mode == ANIM_DEFAULT)
1682 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1684 game.envelope_active = FALSE;
1686 SetDrawtoField(DRAW_BUFFERED);
1688 redraw_mask |= REDRAW_FIELD;
1692 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1697 int width_mult, width_div;
1698 int height_mult, height_div;
1706 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1707 5 - log_2(tilesize));
1708 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1709 int width_mult = offset_calc[offset_calc_pos].width_mult;
1710 int width_div = offset_calc[offset_calc_pos].width_div;
1711 int height_mult = offset_calc[offset_calc_pos].height_mult;
1712 int height_div = offset_calc[offset_calc_pos].height_div;
1713 int mini_startx = src_bitmap->width * width_mult / width_div;
1714 int mini_starty = src_bitmap->height * height_mult / height_div;
1715 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1716 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1718 *bitmap = src_bitmap;
1723 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1727 int graphic = el2preimg(element);
1729 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1730 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1737 SetDrawBackgroundMask(REDRAW_NONE);
1740 for (x = BX1; x <= BX2; x++)
1741 for (y = BY1; y <= BY2; y++)
1742 DrawScreenField(x, y);
1744 redraw_mask |= REDRAW_FIELD;
1747 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1751 for (x = 0; x < size_x; x++)
1752 for (y = 0; y < size_y; y++)
1753 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1755 redraw_mask |= REDRAW_FIELD;
1758 static void DrawPreviewLevelExt(int from_x, int from_y)
1760 boolean show_level_border = (BorderElement != EL_EMPTY);
1761 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1762 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1763 int tile_size = preview.tile_size;
1764 int preview_width = preview.xsize * tile_size;
1765 int preview_height = preview.ysize * tile_size;
1766 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1767 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1768 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1770 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1772 int dst_y = SY + preview.y;
1776 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1778 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1779 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1781 for (x = 0; x < real_preview_xsize; x++)
1783 for (y = 0; y < real_preview_ysize; y++)
1785 int lx = from_x + x + (show_level_border ? -1 : 0);
1786 int ly = from_y + y + (show_level_border ? -1 : 0);
1787 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1788 getBorderElement(lx, ly));
1790 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1791 element, tile_size);
1795 redraw_mask |= REDRAW_MICROLEVEL;
1798 #define MICROLABEL_EMPTY 0
1799 #define MICROLABEL_LEVEL_NAME 1
1800 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1801 #define MICROLABEL_LEVEL_AUTHOR 3
1802 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1803 #define MICROLABEL_IMPORTED_FROM 5
1804 #define MICROLABEL_IMPORTED_BY_HEAD 6
1805 #define MICROLABEL_IMPORTED_BY 7
1807 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
1809 int max_text_width = SXSIZE;
1810 int font_width = getFontWidth(font_nr);
1812 if (pos->align == ALIGN_CENTER)
1813 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1814 else if (pos->align == ALIGN_RIGHT)
1815 max_text_width = pos->x;
1817 max_text_width = SXSIZE - pos->x;
1819 return max_text_width / font_width;
1822 static void DrawPreviewLevelLabelExt(int mode)
1824 struct TextPosInfo *pos = &menu.main.text.level_info_2;
1825 char label_text[MAX_OUTPUT_LINESIZE + 1];
1826 int max_len_label_text;
1828 int font_nr = pos->font;
1831 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1832 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1833 mode == MICROLABEL_IMPORTED_BY_HEAD)
1834 font_nr = pos->font_alt;
1836 int font_nr = FONT_TEXT_2;
1839 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1840 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1841 mode == MICROLABEL_IMPORTED_BY_HEAD)
1842 font_nr = FONT_TEXT_3;
1846 max_len_label_text = getMaxTextLength(pos, font_nr);
1848 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1852 if (pos->chars != -1)
1853 max_len_label_text = pos->chars;
1856 for (i = 0; i < max_len_label_text; i++)
1857 label_text[i] = ' ';
1858 label_text[max_len_label_text] = '\0';
1860 if (strlen(label_text) > 0)
1863 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1865 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1866 int lypos = MICROLABEL2_YPOS;
1868 DrawText(lxpos, lypos, label_text, font_nr);
1873 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1874 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1875 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1876 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1877 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1878 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1879 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1880 max_len_label_text);
1881 label_text[max_len_label_text] = '\0';
1883 if (strlen(label_text) > 0)
1886 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1888 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1889 int lypos = MICROLABEL2_YPOS;
1891 DrawText(lxpos, lypos, label_text, font_nr);
1895 redraw_mask |= REDRAW_MICROLEVEL;
1898 void DrawPreviewLevel(boolean restart)
1900 static unsigned long scroll_delay = 0;
1901 static unsigned long label_delay = 0;
1902 static int from_x, from_y, scroll_direction;
1903 static int label_state, label_counter;
1904 unsigned long scroll_delay_value = preview.step_delay;
1905 boolean show_level_border = (BorderElement != EL_EMPTY);
1906 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1907 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1908 int last_game_status = game_status; /* save current game status */
1911 /* force PREVIEW font on preview level */
1912 game_status = GAME_MODE_PSEUDO_PREVIEW;
1920 if (preview.anim_mode == ANIM_CENTERED)
1922 if (level_xsize > preview.xsize)
1923 from_x = (level_xsize - preview.xsize) / 2;
1924 if (level_ysize > preview.ysize)
1925 from_y = (level_ysize - preview.ysize) / 2;
1928 from_x += preview.xoffset;
1929 from_y += preview.yoffset;
1931 scroll_direction = MV_RIGHT;
1935 DrawPreviewLevelExt(from_x, from_y);
1936 DrawPreviewLevelLabelExt(label_state);
1938 /* initialize delay counters */
1939 DelayReached(&scroll_delay, 0);
1940 DelayReached(&label_delay, 0);
1942 if (leveldir_current->name)
1944 struct TextPosInfo *pos = &menu.main.text.level_info_1;
1945 char label_text[MAX_OUTPUT_LINESIZE + 1];
1947 int font_nr = pos->font;
1949 int font_nr = FONT_TEXT_1;
1952 int max_len_label_text = getMaxTextLength(pos, font_nr);
1954 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1962 if (pos->chars != -1)
1963 max_len_label_text = pos->chars;
1966 strncpy(label_text, leveldir_current->name, max_len_label_text);
1967 label_text[max_len_label_text] = '\0';
1970 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1972 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1973 lypos = SY + MICROLABEL1_YPOS;
1975 DrawText(lxpos, lypos, label_text, font_nr);
1979 game_status = last_game_status; /* restore current game status */
1984 /* scroll preview level, if needed */
1985 if (preview.anim_mode != ANIM_NONE &&
1986 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1987 DelayReached(&scroll_delay, scroll_delay_value))
1989 switch (scroll_direction)
1994 from_x -= preview.step_offset;
1995 from_x = (from_x < 0 ? 0 : from_x);
1998 scroll_direction = MV_UP;
2002 if (from_x < level_xsize - preview.xsize)
2004 from_x += preview.step_offset;
2005 from_x = (from_x > level_xsize - preview.xsize ?
2006 level_xsize - preview.xsize : from_x);
2009 scroll_direction = MV_DOWN;
2015 from_y -= preview.step_offset;
2016 from_y = (from_y < 0 ? 0 : from_y);
2019 scroll_direction = MV_RIGHT;
2023 if (from_y < level_ysize - preview.ysize)
2025 from_y += preview.step_offset;
2026 from_y = (from_y > level_ysize - preview.ysize ?
2027 level_ysize - preview.ysize : from_y);
2030 scroll_direction = MV_LEFT;
2037 DrawPreviewLevelExt(from_x, from_y);
2040 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2041 /* redraw micro level label, if needed */
2042 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2043 !strEqual(level.author, ANONYMOUS_NAME) &&
2044 !strEqual(level.author, leveldir_current->name) &&
2045 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2047 int max_label_counter = 23;
2049 if (leveldir_current->imported_from != NULL &&
2050 strlen(leveldir_current->imported_from) > 0)
2051 max_label_counter += 14;
2052 if (leveldir_current->imported_by != NULL &&
2053 strlen(leveldir_current->imported_by) > 0)
2054 max_label_counter += 14;
2056 label_counter = (label_counter + 1) % max_label_counter;
2057 label_state = (label_counter >= 0 && label_counter <= 7 ?
2058 MICROLABEL_LEVEL_NAME :
2059 label_counter >= 9 && label_counter <= 12 ?
2060 MICROLABEL_LEVEL_AUTHOR_HEAD :
2061 label_counter >= 14 && label_counter <= 21 ?
2062 MICROLABEL_LEVEL_AUTHOR :
2063 label_counter >= 23 && label_counter <= 26 ?
2064 MICROLABEL_IMPORTED_FROM_HEAD :
2065 label_counter >= 28 && label_counter <= 35 ?
2066 MICROLABEL_IMPORTED_FROM :
2067 label_counter >= 37 && label_counter <= 40 ?
2068 MICROLABEL_IMPORTED_BY_HEAD :
2069 label_counter >= 42 && label_counter <= 49 ?
2070 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2072 if (leveldir_current->imported_from == NULL &&
2073 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2074 label_state == MICROLABEL_IMPORTED_FROM))
2075 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2076 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2078 DrawPreviewLevelLabelExt(label_state);
2081 game_status = last_game_status; /* restore current game status */
2084 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2085 int graphic, int sync_frame, int mask_mode)
2087 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2089 if (mask_mode == USE_MASKING)
2090 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2092 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2095 inline void DrawGraphicAnimation(int x, int y, int graphic)
2097 int lx = LEVELX(x), ly = LEVELY(y);
2099 if (!IN_SCR_FIELD(x, y))
2102 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2103 graphic, GfxFrame[lx][ly], NO_MASKING);
2104 MarkTileDirty(x, y);
2107 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2109 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2112 void DrawLevelElementAnimation(int x, int y, int element)
2114 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2116 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2119 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2121 int sx = SCREENX(x), sy = SCREENY(y);
2123 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2126 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2129 DrawGraphicAnimation(sx, sy, graphic);
2132 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2133 DrawLevelFieldCrumbledSand(x, y);
2135 if (GFX_CRUMBLED(Feld[x][y]))
2136 DrawLevelFieldCrumbledSand(x, y);
2140 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2142 int sx = SCREENX(x), sy = SCREENY(y);
2145 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2148 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2150 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2153 DrawGraphicAnimation(sx, sy, graphic);
2155 if (GFX_CRUMBLED(element))
2156 DrawLevelFieldCrumbledSand(x, y);
2159 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2161 if (player->use_murphy)
2163 /* this works only because currently only one player can be "murphy" ... */
2164 static int last_horizontal_dir = MV_LEFT;
2165 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2167 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2168 last_horizontal_dir = move_dir;
2170 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2172 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2174 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2180 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2183 static boolean equalGraphics(int graphic1, int graphic2)
2185 struct GraphicInfo *g1 = &graphic_info[graphic1];
2186 struct GraphicInfo *g2 = &graphic_info[graphic2];
2188 return (g1->bitmap == g2->bitmap &&
2189 g1->src_x == g2->src_x &&
2190 g1->src_y == g2->src_y &&
2191 g1->anim_frames == g2->anim_frames &&
2192 g1->anim_delay == g2->anim_delay &&
2193 g1->anim_mode == g2->anim_mode);
2196 void DrawAllPlayers()
2200 for (i = 0; i < MAX_PLAYERS; i++)
2201 if (stored_player[i].active)
2202 DrawPlayer(&stored_player[i]);
2205 void DrawPlayerField(int x, int y)
2207 if (!IS_PLAYER(x, y))
2210 DrawPlayer(PLAYERINFO(x, y));
2213 void DrawPlayer(struct PlayerInfo *player)
2215 int jx = player->jx;
2216 int jy = player->jy;
2217 int move_dir = player->MovDir;
2218 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2219 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2220 int last_jx = (player->is_moving ? jx - dx : jx);
2221 int last_jy = (player->is_moving ? jy - dy : jy);
2222 int next_jx = jx + dx;
2223 int next_jy = jy + dy;
2224 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2225 boolean player_is_opaque = FALSE;
2226 int sx = SCREENX(jx), sy = SCREENY(jy);
2227 int sxx = 0, syy = 0;
2228 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2230 int action = ACTION_DEFAULT;
2231 int last_player_graphic = getPlayerGraphic(player, move_dir);
2232 int last_player_frame = player->Frame;
2235 /* GfxElement[][] is set to the element the player is digging or collecting;
2236 remove also for off-screen player if the player is not moving anymore */
2237 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2238 GfxElement[jx][jy] = EL_UNDEFINED;
2240 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2244 if (!IN_LEV_FIELD(jx, jy))
2246 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2247 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2248 printf("DrawPlayerField(): This should never happen!\n");
2253 if (element == EL_EXPLOSION)
2256 action = (player->is_pushing ? ACTION_PUSHING :
2257 player->is_digging ? ACTION_DIGGING :
2258 player->is_collecting ? ACTION_COLLECTING :
2259 player->is_moving ? ACTION_MOVING :
2260 player->is_snapping ? ACTION_SNAPPING :
2261 player->is_dropping ? ACTION_DROPPING :
2262 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2264 if (player->is_waiting)
2265 move_dir = player->dir_waiting;
2267 InitPlayerGfxAnimation(player, action, move_dir);
2269 /* ----------------------------------------------------------------------- */
2270 /* draw things in the field the player is leaving, if needed */
2271 /* ----------------------------------------------------------------------- */
2273 if (player->is_moving)
2275 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2277 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2279 if (last_element == EL_DYNAMITE_ACTIVE ||
2280 last_element == EL_EM_DYNAMITE_ACTIVE ||
2281 last_element == EL_SP_DISK_RED_ACTIVE)
2282 DrawDynamite(last_jx, last_jy);
2284 DrawLevelFieldThruMask(last_jx, last_jy);
2286 else if (last_element == EL_DYNAMITE_ACTIVE ||
2287 last_element == EL_EM_DYNAMITE_ACTIVE ||
2288 last_element == EL_SP_DISK_RED_ACTIVE)
2289 DrawDynamite(last_jx, last_jy);
2291 /* !!! this is not enough to prevent flickering of players which are
2292 moving next to each others without a free tile between them -- this
2293 can only be solved by drawing all players layer by layer (first the
2294 background, then the foreground etc.) !!! => TODO */
2295 else if (!IS_PLAYER(last_jx, last_jy))
2296 DrawLevelField(last_jx, last_jy);
2299 DrawLevelField(last_jx, last_jy);
2302 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2303 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2306 if (!IN_SCR_FIELD(sx, sy))
2309 if (setup.direct_draw)
2310 SetDrawtoField(DRAW_BUFFERED);
2312 /* ----------------------------------------------------------------------- */
2313 /* draw things behind the player, if needed */
2314 /* ----------------------------------------------------------------------- */
2317 DrawLevelElement(jx, jy, Back[jx][jy]);
2318 else if (IS_ACTIVE_BOMB(element))
2319 DrawLevelElement(jx, jy, EL_EMPTY);
2322 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2324 int old_element = GfxElement[jx][jy];
2325 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2326 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2328 if (GFX_CRUMBLED(old_element))
2329 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2331 DrawGraphic(sx, sy, old_graphic, frame);
2333 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2334 player_is_opaque = TRUE;
2338 GfxElement[jx][jy] = EL_UNDEFINED;
2340 /* make sure that pushed elements are drawn with correct frame rate */
2342 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2344 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2345 GfxFrame[jx][jy] = player->StepFrame;
2347 if (player->is_pushing && player->is_moving)
2348 GfxFrame[jx][jy] = player->StepFrame;
2351 DrawLevelField(jx, jy);
2355 /* ----------------------------------------------------------------------- */
2356 /* draw player himself */
2357 /* ----------------------------------------------------------------------- */
2359 graphic = getPlayerGraphic(player, move_dir);
2361 /* in the case of changed player action or direction, prevent the current
2362 animation frame from being restarted for identical animations */
2363 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2364 player->Frame = last_player_frame;
2366 frame = getGraphicAnimationFrame(graphic, player->Frame);
2370 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2371 sxx = player->GfxPos;
2373 syy = player->GfxPos;
2376 if (!setup.soft_scrolling && ScreenMovPos)
2379 if (player_is_opaque)
2380 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2382 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2384 if (SHIELD_ON(player))
2386 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2387 IMG_SHIELD_NORMAL_ACTIVE);
2388 int frame = getGraphicAnimationFrame(graphic, -1);
2390 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2393 /* ----------------------------------------------------------------------- */
2394 /* draw things the player is pushing, if needed */
2395 /* ----------------------------------------------------------------------- */
2398 printf("::: %d, %d [%d, %d] [%d]\n",
2399 player->is_pushing, player_is_moving, player->GfxAction,
2400 player->is_moving, player_is_moving);
2404 if (player->is_pushing && player->is_moving)
2406 int px = SCREENX(jx), py = SCREENY(jy);
2407 int pxx = (TILEX - ABS(sxx)) * dx;
2408 int pyy = (TILEY - ABS(syy)) * dy;
2409 int gfx_frame = GfxFrame[jx][jy];
2415 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2417 element = Feld[next_jx][next_jy];
2418 gfx_frame = GfxFrame[next_jx][next_jy];
2421 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2424 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2425 frame = getGraphicAnimationFrame(graphic, sync_frame);
2427 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2430 /* draw background element under pushed element (like the Sokoban field) */
2431 if (Back[next_jx][next_jy])
2432 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2434 /* masked drawing is needed for EMC style (double) movement graphics */
2435 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2439 /* ----------------------------------------------------------------------- */
2440 /* draw things in front of player (active dynamite or dynabombs) */
2441 /* ----------------------------------------------------------------------- */
2443 if (IS_ACTIVE_BOMB(element))
2445 graphic = el2img(element);
2446 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2448 if (game.emulation == EMU_SUPAPLEX)
2449 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2451 DrawGraphicThruMask(sx, sy, graphic, frame);
2454 if (player_is_moving && last_element == EL_EXPLOSION)
2456 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2457 GfxElement[last_jx][last_jy] : EL_EMPTY);
2458 int graphic = el_act2img(element, ACTION_EXPLODING);
2459 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2460 int phase = ExplodePhase[last_jx][last_jy] - 1;
2461 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2464 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2467 /* ----------------------------------------------------------------------- */
2468 /* draw elements the player is just walking/passing through/under */
2469 /* ----------------------------------------------------------------------- */
2471 if (player_is_moving)
2473 /* handle the field the player is leaving ... */
2474 if (IS_ACCESSIBLE_INSIDE(last_element))
2475 DrawLevelField(last_jx, last_jy);
2476 else if (IS_ACCESSIBLE_UNDER(last_element))
2477 DrawLevelFieldThruMask(last_jx, last_jy);
2480 /* do not redraw accessible elements if the player is just pushing them */
2481 if (!player_is_moving || !player->is_pushing)
2483 /* ... and the field the player is entering */
2484 if (IS_ACCESSIBLE_INSIDE(element))
2485 DrawLevelField(jx, jy);
2486 else if (IS_ACCESSIBLE_UNDER(element))
2487 DrawLevelFieldThruMask(jx, jy);
2490 if (setup.direct_draw)
2492 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2493 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2494 int x_size = TILEX * (1 + ABS(jx - last_jx));
2495 int y_size = TILEY * (1 + ABS(jy - last_jy));
2497 BlitBitmap(drawto_field, window,
2498 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2499 SetDrawtoField(DRAW_DIRECT);
2502 MarkTileDirty(sx, sy);
2505 /* ------------------------------------------------------------------------- */
2507 void WaitForEventToContinue()
2509 boolean still_wait = TRUE;
2511 /* simulate releasing mouse button over last gadget, if still pressed */
2513 HandleGadgets(-1, -1, 0);
2515 button_status = MB_RELEASED;
2531 case EVENT_BUTTONPRESS:
2532 case EVENT_KEYPRESS:
2536 case EVENT_KEYRELEASE:
2537 ClearPlayerAction();
2541 HandleOtherEvents(&event);
2545 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2552 /* don't eat all CPU time */
2557 #define MAX_REQUEST_LINES 13
2558 #define MAX_REQUEST_LINE_FONT1_LEN 7
2559 #define MAX_REQUEST_LINE_FONT2_LEN 10
2561 boolean Request(char *text, unsigned int req_state)
2563 int mx, my, ty, result = -1;
2564 unsigned int old_door_state;
2565 int last_game_status = game_status; /* save current game status */
2566 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2567 int font_nr = FONT_TEXT_2;
2568 int max_word_len = 0;
2571 for (text_ptr = text; *text_ptr; text_ptr++)
2573 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2575 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2577 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2579 font_nr = FONT_TEXT_1;
2581 font_nr = FONT_LEVEL_NUMBER;
2588 if (game_status == GAME_MODE_PLAYING &&
2589 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2590 BlitScreenToBitmap_EM(backbuffer);
2592 /* disable deactivated drawing when quick-loading level tape recording */
2593 if (tape.playing && tape.deactivate_display)
2594 TapeDeactivateDisplayOff(TRUE);
2596 SetMouseCursor(CURSOR_DEFAULT);
2598 #if defined(NETWORK_AVALIABLE)
2599 /* pause network game while waiting for request to answer */
2600 if (options.network &&
2601 game_status == GAME_MODE_PLAYING &&
2602 req_state & REQUEST_WAIT_FOR_INPUT)
2603 SendToServer_PausePlaying();
2606 old_door_state = GetDoorState();
2608 /* simulate releasing mouse button over last gadget, if still pressed */
2610 HandleGadgets(-1, -1, 0);
2614 if (old_door_state & DOOR_OPEN_1)
2616 CloseDoor(DOOR_CLOSE_1);
2618 /* save old door content */
2619 BlitBitmap(bitmap_db_door, bitmap_db_door,
2620 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2621 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2625 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2628 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2630 /* clear door drawing field */
2631 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2633 /* force DOOR font inside door area */
2634 game_status = GAME_MODE_PSEUDO_DOOR;
2636 /* write text for request */
2637 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2639 char text_line[max_request_line_len + 1];
2645 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2648 if (!tc || tc == ' ')
2659 strncpy(text_line, text, tl);
2662 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2663 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2664 text_line, font_nr);
2666 text += tl + (tc == ' ' ? 1 : 0);
2669 game_status = last_game_status; /* restore current game status */
2671 if (req_state & REQ_ASK)
2673 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2674 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2676 else if (req_state & REQ_CONFIRM)
2678 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2680 else if (req_state & REQ_PLAYER)
2682 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2683 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2684 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2685 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2688 /* copy request gadgets to door backbuffer */
2689 BlitBitmap(drawto, bitmap_db_door,
2690 DX, DY, DXSIZE, DYSIZE,
2691 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2693 OpenDoor(DOOR_OPEN_1);
2695 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2697 if (game_status == GAME_MODE_PLAYING)
2699 SetPanelBackground();
2700 SetDrawBackgroundMask(REDRAW_DOOR_1);
2704 SetDrawBackgroundMask(REDRAW_FIELD);
2710 if (game_status != GAME_MODE_MAIN)
2713 button_status = MB_RELEASED;
2715 request_gadget_id = -1;
2717 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2729 case EVENT_BUTTONPRESS:
2730 case EVENT_BUTTONRELEASE:
2731 case EVENT_MOTIONNOTIFY:
2733 if (event.type == EVENT_MOTIONNOTIFY)
2735 if (!PointerInWindow(window))
2736 continue; /* window and pointer are on different screens */
2741 motion_status = TRUE;
2742 mx = ((MotionEvent *) &event)->x;
2743 my = ((MotionEvent *) &event)->y;
2747 motion_status = FALSE;
2748 mx = ((ButtonEvent *) &event)->x;
2749 my = ((ButtonEvent *) &event)->y;
2750 if (event.type == EVENT_BUTTONPRESS)
2751 button_status = ((ButtonEvent *) &event)->button;
2753 button_status = MB_RELEASED;
2756 /* this sets 'request_gadget_id' */
2757 HandleGadgets(mx, my, button_status);
2759 switch (request_gadget_id)
2761 case TOOL_CTRL_ID_YES:
2764 case TOOL_CTRL_ID_NO:
2767 case TOOL_CTRL_ID_CONFIRM:
2768 result = TRUE | FALSE;
2771 case TOOL_CTRL_ID_PLAYER_1:
2774 case TOOL_CTRL_ID_PLAYER_2:
2777 case TOOL_CTRL_ID_PLAYER_3:
2780 case TOOL_CTRL_ID_PLAYER_4:
2791 case EVENT_KEYPRESS:
2792 switch (GetEventKey((KeyEvent *)&event, TRUE))
2805 if (req_state & REQ_PLAYER)
2809 case EVENT_KEYRELEASE:
2810 ClearPlayerAction();
2814 HandleOtherEvents(&event);
2818 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2820 int joy = AnyJoystick();
2822 if (joy & JOY_BUTTON_1)
2824 else if (joy & JOY_BUTTON_2)
2830 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2832 HandleGameActions();
2839 if (!PendingEvent()) /* delay only if no pending events */
2848 if (!PendingEvent()) /* delay only if no pending events */
2851 /* don't eat all CPU time */
2858 if (game_status != GAME_MODE_MAIN)
2863 if (!(req_state & REQ_STAY_OPEN))
2865 CloseDoor(DOOR_CLOSE_1);
2867 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2868 (req_state & REQ_REOPEN))
2869 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2874 if (game_status == GAME_MODE_PLAYING)
2876 SetPanelBackground();
2877 SetDrawBackgroundMask(REDRAW_DOOR_1);
2881 SetDrawBackgroundMask(REDRAW_FIELD);
2884 #if defined(NETWORK_AVALIABLE)
2885 /* continue network game after request */
2886 if (options.network &&
2887 game_status == GAME_MODE_PLAYING &&
2888 req_state & REQUEST_WAIT_FOR_INPUT)
2889 SendToServer_ContinuePlaying();
2892 /* restore deactivated drawing when quick-loading level tape recording */
2893 if (tape.playing && tape.deactivate_display)
2894 TapeDeactivateDisplayOn();
2899 unsigned int OpenDoor(unsigned int door_state)
2901 if (door_state & DOOR_COPY_BACK)
2903 if (door_state & DOOR_OPEN_1)
2904 BlitBitmap(bitmap_db_door, bitmap_db_door,
2905 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2906 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2908 if (door_state & DOOR_OPEN_2)
2909 BlitBitmap(bitmap_db_door, bitmap_db_door,
2910 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2911 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2913 door_state &= ~DOOR_COPY_BACK;
2916 return MoveDoor(door_state);
2919 unsigned int CloseDoor(unsigned int door_state)
2921 unsigned int old_door_state = GetDoorState();
2923 if (!(door_state & DOOR_NO_COPY_BACK))
2925 if (old_door_state & DOOR_OPEN_1)
2926 BlitBitmap(backbuffer, bitmap_db_door,
2927 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2929 if (old_door_state & DOOR_OPEN_2)
2930 BlitBitmap(backbuffer, bitmap_db_door,
2931 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2933 door_state &= ~DOOR_NO_COPY_BACK;
2936 return MoveDoor(door_state);
2939 unsigned int GetDoorState()
2941 return MoveDoor(DOOR_GET_STATE);
2944 unsigned int SetDoorState(unsigned int door_state)
2946 return MoveDoor(door_state | DOOR_SET_STATE);
2949 unsigned int MoveDoor(unsigned int door_state)
2951 static int door1 = DOOR_OPEN_1;
2952 static int door2 = DOOR_CLOSE_2;
2953 unsigned long door_delay = 0;
2954 unsigned long door_delay_value;
2957 if (door_1.width < 0 || door_1.width > DXSIZE)
2958 door_1.width = DXSIZE;
2959 if (door_1.height < 0 || door_1.height > DYSIZE)
2960 door_1.height = DYSIZE;
2961 if (door_2.width < 0 || door_2.width > VXSIZE)
2962 door_2.width = VXSIZE;
2963 if (door_2.height < 0 || door_2.height > VYSIZE)
2964 door_2.height = VYSIZE;
2966 if (door_state == DOOR_GET_STATE)
2967 return (door1 | door2);
2969 if (door_state & DOOR_SET_STATE)
2971 if (door_state & DOOR_ACTION_1)
2972 door1 = door_state & DOOR_ACTION_1;
2973 if (door_state & DOOR_ACTION_2)
2974 door2 = door_state & DOOR_ACTION_2;
2976 return (door1 | door2);
2979 if (!(door_state & DOOR_FORCE_REDRAW))
2981 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2982 door_state &= ~DOOR_OPEN_1;
2983 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2984 door_state &= ~DOOR_CLOSE_1;
2985 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2986 door_state &= ~DOOR_OPEN_2;
2987 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2988 door_state &= ~DOOR_CLOSE_2;
2991 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2994 if (setup.quick_doors)
2996 stepsize = 20; /* must be choosen to always draw last frame */
2997 door_delay_value = 0;
3000 if (global.autoplay_leveldir)
3002 door_state |= DOOR_NO_DELAY;
3003 door_state &= ~DOOR_CLOSE_ALL;
3006 if (door_state & DOOR_ACTION)
3008 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3009 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3010 boolean door_1_done = (!handle_door_1);
3011 boolean door_2_done = (!handle_door_2);
3012 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3013 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3014 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3015 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3016 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3017 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3018 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3019 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3020 int door_skip = max_door_size - door_size;
3021 int end = door_size;
3022 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3025 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3027 /* opening door sound has priority over simultaneously closing door */
3028 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3029 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3030 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3031 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3034 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3037 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3038 GC gc = bitmap->stored_clip_gc;
3040 if (door_state & DOOR_ACTION_1)
3042 int a = MIN(x * door_1.step_offset, end);
3043 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3044 int i = p + door_skip;
3046 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3048 BlitBitmap(bitmap_db_door, drawto,
3049 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3050 DXSIZE, DYSIZE, DX, DY);
3054 BlitBitmap(bitmap_db_door, drawto,
3055 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3056 DXSIZE, DYSIZE - p / 2, DX, DY);
3058 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3061 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3063 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3064 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3065 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3066 int dst2_x = DX, dst2_y = DY;
3067 int width = i, height = DYSIZE;
3069 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3070 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3073 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3074 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3077 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3079 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3080 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3081 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3082 int dst2_x = DX, dst2_y = DY;
3083 int width = DXSIZE, height = i;
3085 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3086 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3089 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3090 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3093 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3095 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3097 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3098 BlitBitmapMasked(bitmap, drawto,
3099 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3100 DX + DXSIZE - i, DY + j);
3101 BlitBitmapMasked(bitmap, drawto,
3102 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3103 DX + DXSIZE - i, DY + 140 + j);
3104 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3105 DY - (DOOR_GFX_PAGEY1 + j));
3106 BlitBitmapMasked(bitmap, drawto,
3107 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3109 BlitBitmapMasked(bitmap, drawto,
3110 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3113 BlitBitmapMasked(bitmap, drawto,
3114 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3116 BlitBitmapMasked(bitmap, drawto,
3117 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3119 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3120 BlitBitmapMasked(bitmap, drawto,
3121 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3122 DX + DXSIZE - i, DY + 77 + j);
3123 BlitBitmapMasked(bitmap, drawto,
3124 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3125 DX + DXSIZE - i, DY + 203 + j);
3128 redraw_mask |= REDRAW_DOOR_1;
3129 door_1_done = (a == end);
3132 if (door_state & DOOR_ACTION_2)
3134 int a = MIN(x * door_2.step_offset, door_size);
3135 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3136 int i = p + door_skip;
3138 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3140 BlitBitmap(bitmap_db_door, drawto,
3141 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3142 VXSIZE, VYSIZE, VX, VY);
3144 else if (x <= VYSIZE)
3146 BlitBitmap(bitmap_db_door, drawto,
3147 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3148 VXSIZE, VYSIZE - p / 2, VX, VY);
3150 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3153 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3155 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3156 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3157 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3158 int dst2_x = VX, dst2_y = VY;
3159 int width = i, height = VYSIZE;
3161 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3162 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3165 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3166 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3169 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3171 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3172 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3173 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3174 int dst2_x = VX, dst2_y = VY;
3175 int width = VXSIZE, height = i;
3177 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3178 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3181 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3182 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3185 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3187 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3189 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3190 BlitBitmapMasked(bitmap, drawto,
3191 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3192 VX + VXSIZE - i, VY + j);
3193 SetClipOrigin(bitmap, gc,
3194 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3195 BlitBitmapMasked(bitmap, drawto,
3196 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3199 BlitBitmapMasked(bitmap, drawto,
3200 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3201 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3202 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3203 BlitBitmapMasked(bitmap, drawto,
3204 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3206 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3209 redraw_mask |= REDRAW_DOOR_2;
3210 door_2_done = (a == VXSIZE);
3213 if (!(door_state & DOOR_NO_DELAY))
3217 if (game_status == GAME_MODE_MAIN)
3220 WaitUntilDelayReached(&door_delay, door_delay_value);
3225 if (door_state & DOOR_ACTION_1)
3226 door1 = door_state & DOOR_ACTION_1;
3227 if (door_state & DOOR_ACTION_2)
3228 door2 = door_state & DOOR_ACTION_2;
3230 return (door1 | door2);
3233 void DrawSpecialEditorDoor()
3235 /* draw bigger toolbox window */
3236 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3237 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3239 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3240 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3243 redraw_mask |= REDRAW_ALL;
3246 void UndrawSpecialEditorDoor()
3248 /* draw normal tape recorder window */
3249 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3250 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3253 redraw_mask |= REDRAW_ALL;
3257 /* ---------- new tool button stuff ---------------------------------------- */
3259 /* graphic position values for tool buttons */
3260 #define TOOL_BUTTON_YES_XPOS 2
3261 #define TOOL_BUTTON_YES_YPOS 250
3262 #define TOOL_BUTTON_YES_GFX_YPOS 0
3263 #define TOOL_BUTTON_YES_XSIZE 46
3264 #define TOOL_BUTTON_YES_YSIZE 28
3265 #define TOOL_BUTTON_NO_XPOS 52
3266 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3267 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3268 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3269 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3270 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3271 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3272 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3273 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3274 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3275 #define TOOL_BUTTON_PLAYER_XSIZE 30
3276 #define TOOL_BUTTON_PLAYER_YSIZE 30
3277 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3278 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3279 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3280 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3281 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3282 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3283 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3284 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3285 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3286 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3287 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3288 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3289 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3290 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3291 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3292 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3293 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3294 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3295 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3296 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3305 } toolbutton_info[NUM_TOOL_BUTTONS] =
3308 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3309 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3310 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3315 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3316 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3317 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3322 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3323 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3324 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3325 TOOL_CTRL_ID_CONFIRM,
3329 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3330 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3331 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3332 TOOL_CTRL_ID_PLAYER_1,
3336 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3337 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3338 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3339 TOOL_CTRL_ID_PLAYER_2,
3343 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3344 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3345 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3346 TOOL_CTRL_ID_PLAYER_3,
3350 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3351 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3352 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3353 TOOL_CTRL_ID_PLAYER_4,
3358 void CreateToolButtons()
3362 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3364 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3365 Bitmap *deco_bitmap = None;
3366 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3367 struct GadgetInfo *gi;
3368 unsigned long event_mask;
3369 int gd_xoffset, gd_yoffset;
3370 int gd_x1, gd_x2, gd_y;
3373 event_mask = GD_EVENT_RELEASED;
3375 gd_xoffset = toolbutton_info[i].xpos;
3376 gd_yoffset = toolbutton_info[i].ypos;
3377 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3378 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3379 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3381 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3383 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3385 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3386 &deco_bitmap, &deco_x, &deco_y);
3387 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3388 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3391 gi = CreateGadget(GDI_CUSTOM_ID, id,
3392 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3393 GDI_X, DX + toolbutton_info[i].x,
3394 GDI_Y, DY + toolbutton_info[i].y,
3395 GDI_WIDTH, toolbutton_info[i].width,
3396 GDI_HEIGHT, toolbutton_info[i].height,
3397 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3398 GDI_STATE, GD_BUTTON_UNPRESSED,
3399 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3400 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3401 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3402 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3403 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3404 GDI_DECORATION_SHIFTING, 1, 1,
3405 GDI_DIRECT_DRAW, FALSE,
3406 GDI_EVENT_MASK, event_mask,
3407 GDI_CALLBACK_ACTION, HandleToolButtons,
3411 Error(ERR_EXIT, "cannot create gadget");
3413 tool_gadget[id] = gi;
3417 void FreeToolButtons()
3421 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3422 FreeGadget(tool_gadget[i]);
3425 static void UnmapToolButtons()
3429 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3430 UnmapGadget(tool_gadget[i]);
3433 static void HandleToolButtons(struct GadgetInfo *gi)
3435 request_gadget_id = gi->custom_id;
3438 static struct Mapping_EM_to_RND_object
3441 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3442 boolean is_backside; /* backside of moving element */
3448 em_object_mapping_list[] =
3451 Xblank, TRUE, FALSE,
3455 Yacid_splash_eB, FALSE, FALSE,
3456 EL_ACID_SPLASH_RIGHT, -1, -1
3459 Yacid_splash_wB, FALSE, FALSE,
3460 EL_ACID_SPLASH_LEFT, -1, -1
3463 #ifdef EM_ENGINE_BAD_ROLL
3465 Xstone_force_e, FALSE, FALSE,
3466 EL_ROCK, -1, MV_BIT_RIGHT
3469 Xstone_force_w, FALSE, FALSE,
3470 EL_ROCK, -1, MV_BIT_LEFT
3473 Xnut_force_e, FALSE, FALSE,
3474 EL_NUT, -1, MV_BIT_RIGHT
3477 Xnut_force_w, FALSE, FALSE,
3478 EL_NUT, -1, MV_BIT_LEFT
3481 Xspring_force_e, FALSE, FALSE,
3482 EL_SPRING, -1, MV_BIT_RIGHT
3485 Xspring_force_w, FALSE, FALSE,
3486 EL_SPRING, -1, MV_BIT_LEFT
3489 Xemerald_force_e, FALSE, FALSE,
3490 EL_EMERALD, -1, MV_BIT_RIGHT
3493 Xemerald_force_w, FALSE, FALSE,
3494 EL_EMERALD, -1, MV_BIT_LEFT
3497 Xdiamond_force_e, FALSE, FALSE,
3498 EL_DIAMOND, -1, MV_BIT_RIGHT
3501 Xdiamond_force_w, FALSE, FALSE,
3502 EL_DIAMOND, -1, MV_BIT_LEFT
3505 Xbomb_force_e, FALSE, FALSE,
3506 EL_BOMB, -1, MV_BIT_RIGHT
3509 Xbomb_force_w, FALSE, FALSE,
3510 EL_BOMB, -1, MV_BIT_LEFT
3512 #endif /* EM_ENGINE_BAD_ROLL */
3515 Xstone, TRUE, FALSE,
3519 Xstone_pause, FALSE, FALSE,
3523 Xstone_fall, FALSE, FALSE,
3527 Ystone_s, FALSE, FALSE,
3528 EL_ROCK, ACTION_FALLING, -1
3531 Ystone_sB, FALSE, TRUE,
3532 EL_ROCK, ACTION_FALLING, -1
3535 Ystone_e, FALSE, FALSE,
3536 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3539 Ystone_eB, FALSE, TRUE,
3540 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3543 Ystone_w, FALSE, FALSE,
3544 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3547 Ystone_wB, FALSE, TRUE,
3548 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3555 Xnut_pause, FALSE, FALSE,
3559 Xnut_fall, FALSE, FALSE,
3563 Ynut_s, FALSE, FALSE,
3564 EL_NUT, ACTION_FALLING, -1
3567 Ynut_sB, FALSE, TRUE,
3568 EL_NUT, ACTION_FALLING, -1
3571 Ynut_e, FALSE, FALSE,
3572 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3575 Ynut_eB, FALSE, TRUE,
3576 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3579 Ynut_w, FALSE, FALSE,
3580 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3583 Ynut_wB, FALSE, TRUE,
3584 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3587 Xbug_n, TRUE, FALSE,
3591 Xbug_e, TRUE, FALSE,
3592 EL_BUG_RIGHT, -1, -1
3595 Xbug_s, TRUE, FALSE,
3599 Xbug_w, TRUE, FALSE,
3603 Xbug_gon, FALSE, FALSE,
3607 Xbug_goe, FALSE, FALSE,
3608 EL_BUG_RIGHT, -1, -1
3611 Xbug_gos, FALSE, FALSE,
3615 Xbug_gow, FALSE, FALSE,
3619 Ybug_n, FALSE, FALSE,
3620 EL_BUG, ACTION_MOVING, MV_BIT_UP
3623 Ybug_nB, FALSE, TRUE,
3624 EL_BUG, ACTION_MOVING, MV_BIT_UP
3627 Ybug_e, FALSE, FALSE,
3628 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3631 Ybug_eB, FALSE, TRUE,
3632 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3635 Ybug_s, FALSE, FALSE,
3636 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3639 Ybug_sB, FALSE, TRUE,
3640 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3643 Ybug_w, FALSE, FALSE,
3644 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3647 Ybug_wB, FALSE, TRUE,
3648 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3651 Ybug_w_n, FALSE, FALSE,
3652 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3655 Ybug_n_e, FALSE, FALSE,
3656 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3659 Ybug_e_s, FALSE, FALSE,
3660 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3663 Ybug_s_w, FALSE, FALSE,
3664 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3667 Ybug_e_n, FALSE, FALSE,
3668 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3671 Ybug_s_e, FALSE, FALSE,
3672 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3675 Ybug_w_s, FALSE, FALSE,
3676 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3679 Ybug_n_w, FALSE, FALSE,
3680 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3683 Ybug_stone, FALSE, FALSE,
3684 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3687 Ybug_spring, FALSE, FALSE,
3688 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3691 Xtank_n, TRUE, FALSE,
3692 EL_SPACESHIP_UP, -1, -1
3695 Xtank_e, TRUE, FALSE,
3696 EL_SPACESHIP_RIGHT, -1, -1
3699 Xtank_s, TRUE, FALSE,
3700 EL_SPACESHIP_DOWN, -1, -1
3703 Xtank_w, TRUE, FALSE,
3704 EL_SPACESHIP_LEFT, -1, -1
3707 Xtank_gon, FALSE, FALSE,
3708 EL_SPACESHIP_UP, -1, -1
3711 Xtank_goe, FALSE, FALSE,
3712 EL_SPACESHIP_RIGHT, -1, -1
3715 Xtank_gos, FALSE, FALSE,
3716 EL_SPACESHIP_DOWN, -1, -1
3719 Xtank_gow, FALSE, FALSE,
3720 EL_SPACESHIP_LEFT, -1, -1
3723 Ytank_n, FALSE, FALSE,
3724 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3727 Ytank_nB, FALSE, TRUE,
3728 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3731 Ytank_e, FALSE, FALSE,
3732 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3735 Ytank_eB, FALSE, TRUE,
3736 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3739 Ytank_s, FALSE, FALSE,
3740 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3743 Ytank_sB, FALSE, TRUE,
3744 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3747 Ytank_w, FALSE, FALSE,
3748 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3751 Ytank_wB, FALSE, TRUE,
3752 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3755 Ytank_w_n, FALSE, FALSE,
3756 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3759 Ytank_n_e, FALSE, FALSE,
3760 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3763 Ytank_e_s, FALSE, FALSE,
3764 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3767 Ytank_s_w, FALSE, FALSE,
3768 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3771 Ytank_e_n, FALSE, FALSE,
3772 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3775 Ytank_s_e, FALSE, FALSE,
3776 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3779 Ytank_w_s, FALSE, FALSE,
3780 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3783 Ytank_n_w, FALSE, FALSE,
3784 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3787 Ytank_stone, FALSE, FALSE,
3788 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3791 Ytank_spring, FALSE, FALSE,
3792 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3795 Xandroid, TRUE, FALSE,
3796 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3799 Xandroid_1_n, FALSE, FALSE,
3800 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3803 Xandroid_2_n, FALSE, FALSE,
3804 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3807 Xandroid_1_e, FALSE, FALSE,
3808 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3811 Xandroid_2_e, FALSE, FALSE,
3812 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3815 Xandroid_1_w, FALSE, FALSE,
3816 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3819 Xandroid_2_w, FALSE, FALSE,
3820 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3823 Xandroid_1_s, FALSE, FALSE,
3824 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3827 Xandroid_2_s, FALSE, FALSE,
3828 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3831 Yandroid_n, FALSE, FALSE,
3832 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3835 Yandroid_nB, FALSE, TRUE,
3836 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3839 Yandroid_ne, FALSE, FALSE,
3840 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3843 Yandroid_neB, FALSE, TRUE,
3844 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3847 Yandroid_e, FALSE, FALSE,
3848 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3851 Yandroid_eB, FALSE, TRUE,
3852 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3855 Yandroid_se, FALSE, FALSE,
3856 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3859 Yandroid_seB, FALSE, TRUE,
3860 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3863 Yandroid_s, FALSE, FALSE,
3864 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3867 Yandroid_sB, FALSE, TRUE,
3868 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3871 Yandroid_sw, FALSE, FALSE,
3872 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3875 Yandroid_swB, FALSE, TRUE,
3876 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3879 Yandroid_w, FALSE, FALSE,
3880 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3883 Yandroid_wB, FALSE, TRUE,
3884 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3887 Yandroid_nw, FALSE, FALSE,
3888 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3891 Yandroid_nwB, FALSE, TRUE,
3892 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3895 Xspring, TRUE, FALSE,
3899 Xspring_pause, FALSE, FALSE,
3903 Xspring_e, FALSE, FALSE,
3907 Xspring_w, FALSE, FALSE,
3911 Xspring_fall, FALSE, FALSE,
3915 Yspring_s, FALSE, FALSE,
3916 EL_SPRING, ACTION_FALLING, -1
3919 Yspring_sB, FALSE, TRUE,
3920 EL_SPRING, ACTION_FALLING, -1
3923 Yspring_e, FALSE, FALSE,
3924 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3927 Yspring_eB, FALSE, TRUE,
3928 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3931 Yspring_w, FALSE, FALSE,
3932 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3935 Yspring_wB, FALSE, TRUE,
3936 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3939 Yspring_kill_e, FALSE, FALSE,
3940 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3943 Yspring_kill_eB, FALSE, TRUE,
3944 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3947 Yspring_kill_w, FALSE, FALSE,
3948 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3951 Yspring_kill_wB, FALSE, TRUE,
3952 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3955 Xeater_n, TRUE, FALSE,
3956 EL_YAMYAM_UP, -1, -1
3959 Xeater_e, TRUE, FALSE,
3960 EL_YAMYAM_RIGHT, -1, -1
3963 Xeater_w, TRUE, FALSE,
3964 EL_YAMYAM_LEFT, -1, -1
3967 Xeater_s, TRUE, FALSE,
3968 EL_YAMYAM_DOWN, -1, -1
3971 Yeater_n, FALSE, FALSE,
3972 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3975 Yeater_nB, FALSE, TRUE,
3976 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3979 Yeater_e, FALSE, FALSE,
3980 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3983 Yeater_eB, FALSE, TRUE,
3984 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3987 Yeater_s, FALSE, FALSE,
3988 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3991 Yeater_sB, FALSE, TRUE,
3992 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3995 Yeater_w, FALSE, FALSE,
3996 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3999 Yeater_wB, FALSE, TRUE,
4000 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4003 Yeater_stone, FALSE, FALSE,
4004 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4007 Yeater_spring, FALSE, FALSE,
4008 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4011 Xalien, TRUE, FALSE,
4015 Xalien_pause, FALSE, FALSE,
4019 Yalien_n, FALSE, FALSE,
4020 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4023 Yalien_nB, FALSE, TRUE,
4024 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4027 Yalien_e, FALSE, FALSE,
4028 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4031 Yalien_eB, FALSE, TRUE,
4032 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4035 Yalien_s, FALSE, FALSE,
4036 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4039 Yalien_sB, FALSE, TRUE,
4040 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4043 Yalien_w, FALSE, FALSE,
4044 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4047 Yalien_wB, FALSE, TRUE,
4048 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4051 Yalien_stone, FALSE, FALSE,
4052 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4055 Yalien_spring, FALSE, FALSE,
4056 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4059 Xemerald, TRUE, FALSE,
4063 Xemerald_pause, FALSE, FALSE,
4067 Xemerald_fall, FALSE, FALSE,
4071 Xemerald_shine, FALSE, FALSE,
4072 EL_EMERALD, ACTION_TWINKLING, -1
4075 Yemerald_s, FALSE, FALSE,
4076 EL_EMERALD, ACTION_FALLING, -1
4079 Yemerald_sB, FALSE, TRUE,
4080 EL_EMERALD, ACTION_FALLING, -1
4083 Yemerald_e, FALSE, FALSE,
4084 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4087 Yemerald_eB, FALSE, TRUE,
4088 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4091 Yemerald_w, FALSE, FALSE,
4092 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4095 Yemerald_wB, FALSE, TRUE,
4096 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4099 Yemerald_eat, FALSE, FALSE,
4100 EL_EMERALD, ACTION_COLLECTING, -1
4103 Yemerald_stone, FALSE, FALSE,
4104 EL_NUT, ACTION_BREAKING, -1
4107 Xdiamond, TRUE, FALSE,
4111 Xdiamond_pause, FALSE, FALSE,
4115 Xdiamond_fall, FALSE, FALSE,
4119 Xdiamond_shine, FALSE, FALSE,
4120 EL_DIAMOND, ACTION_TWINKLING, -1
4123 Ydiamond_s, FALSE, FALSE,
4124 EL_DIAMOND, ACTION_FALLING, -1
4127 Ydiamond_sB, FALSE, TRUE,
4128 EL_DIAMOND, ACTION_FALLING, -1
4131 Ydiamond_e, FALSE, FALSE,
4132 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4135 Ydiamond_eB, FALSE, TRUE,
4136 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4139 Ydiamond_w, FALSE, FALSE,
4140 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4143 Ydiamond_wB, FALSE, TRUE,
4144 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4147 Ydiamond_eat, FALSE, FALSE,
4148 EL_DIAMOND, ACTION_COLLECTING, -1
4151 Ydiamond_stone, FALSE, FALSE,
4152 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4155 Xdrip_fall, TRUE, FALSE,
4156 EL_AMOEBA_DROP, -1, -1
4159 Xdrip_stretch, FALSE, FALSE,
4160 EL_AMOEBA_DROP, ACTION_FALLING, -1
4163 Xdrip_stretchB, FALSE, TRUE,
4164 EL_AMOEBA_DROP, ACTION_FALLING, -1
4167 Xdrip_eat, FALSE, FALSE,
4168 EL_AMOEBA_DROP, ACTION_GROWING, -1
4171 Ydrip_s1, FALSE, FALSE,
4172 EL_AMOEBA_DROP, ACTION_FALLING, -1
4175 Ydrip_s1B, FALSE, TRUE,
4176 EL_AMOEBA_DROP, ACTION_FALLING, -1
4179 Ydrip_s2, FALSE, FALSE,
4180 EL_AMOEBA_DROP, ACTION_FALLING, -1
4183 Ydrip_s2B, FALSE, TRUE,
4184 EL_AMOEBA_DROP, ACTION_FALLING, -1
4191 Xbomb_pause, FALSE, FALSE,
4195 Xbomb_fall, FALSE, FALSE,
4199 Ybomb_s, FALSE, FALSE,
4200 EL_BOMB, ACTION_FALLING, -1
4203 Ybomb_sB, FALSE, TRUE,
4204 EL_BOMB, ACTION_FALLING, -1
4207 Ybomb_e, FALSE, FALSE,
4208 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4211 Ybomb_eB, FALSE, TRUE,
4212 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4215 Ybomb_w, FALSE, FALSE,
4216 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4219 Ybomb_wB, FALSE, TRUE,
4220 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4223 Ybomb_eat, FALSE, FALSE,
4224 EL_BOMB, ACTION_ACTIVATING, -1
4227 Xballoon, TRUE, FALSE,
4231 Yballoon_n, FALSE, FALSE,
4232 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4235 Yballoon_nB, FALSE, TRUE,
4236 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4239 Yballoon_e, FALSE, FALSE,
4240 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4243 Yballoon_eB, FALSE, TRUE,
4244 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4247 Yballoon_s, FALSE, FALSE,
4248 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4251 Yballoon_sB, FALSE, TRUE,
4252 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4255 Yballoon_w, FALSE, FALSE,
4256 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4259 Yballoon_wB, FALSE, TRUE,
4260 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4263 Xgrass, TRUE, FALSE,
4264 EL_EMC_GRASS, -1, -1
4267 Ygrass_nB, FALSE, FALSE,
4268 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4271 Ygrass_eB, FALSE, FALSE,
4272 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4275 Ygrass_sB, FALSE, FALSE,
4276 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4279 Ygrass_wB, FALSE, FALSE,
4280 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4287 Ydirt_nB, FALSE, FALSE,
4288 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4291 Ydirt_eB, FALSE, FALSE,
4292 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4295 Ydirt_sB, FALSE, FALSE,
4296 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4299 Ydirt_wB, FALSE, FALSE,
4300 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4303 Xacid_ne, TRUE, FALSE,
4304 EL_ACID_POOL_TOPRIGHT, -1, -1
4307 Xacid_se, TRUE, FALSE,
4308 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4311 Xacid_s, TRUE, FALSE,
4312 EL_ACID_POOL_BOTTOM, -1, -1
4315 Xacid_sw, TRUE, FALSE,
4316 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4319 Xacid_nw, TRUE, FALSE,
4320 EL_ACID_POOL_TOPLEFT, -1, -1
4323 Xacid_1, TRUE, FALSE,
4327 Xacid_2, FALSE, FALSE,
4331 Xacid_3, FALSE, FALSE,
4335 Xacid_4, FALSE, FALSE,
4339 Xacid_5, FALSE, FALSE,
4343 Xacid_6, FALSE, FALSE,
4347 Xacid_7, FALSE, FALSE,
4351 Xacid_8, FALSE, FALSE,
4355 Xball_1, TRUE, FALSE,
4356 EL_EMC_MAGIC_BALL, -1, -1
4359 Xball_1B, FALSE, FALSE,
4360 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4363 Xball_2, FALSE, FALSE,
4364 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4367 Xball_2B, FALSE, FALSE,
4368 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4371 Yball_eat, FALSE, FALSE,
4372 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4375 Ykey_1_eat, FALSE, FALSE,
4376 EL_EM_KEY_1, ACTION_COLLECTING, -1
4379 Ykey_2_eat, FALSE, FALSE,
4380 EL_EM_KEY_2, ACTION_COLLECTING, -1
4383 Ykey_3_eat, FALSE, FALSE,
4384 EL_EM_KEY_3, ACTION_COLLECTING, -1
4387 Ykey_4_eat, FALSE, FALSE,
4388 EL_EM_KEY_4, ACTION_COLLECTING, -1
4391 Ykey_5_eat, FALSE, FALSE,
4392 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4395 Ykey_6_eat, FALSE, FALSE,
4396 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4399 Ykey_7_eat, FALSE, FALSE,
4400 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4403 Ykey_8_eat, FALSE, FALSE,
4404 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4407 Ylenses_eat, FALSE, FALSE,
4408 EL_EMC_LENSES, ACTION_COLLECTING, -1
4411 Ymagnify_eat, FALSE, FALSE,
4412 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4415 Ygrass_eat, FALSE, FALSE,
4416 EL_EMC_GRASS, ACTION_SNAPPING, -1
4419 Ydirt_eat, FALSE, FALSE,
4420 EL_SAND, ACTION_SNAPPING, -1
4423 Xgrow_ns, TRUE, FALSE,
4424 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4427 Ygrow_ns_eat, FALSE, FALSE,
4428 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4431 Xgrow_ew, TRUE, FALSE,
4432 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4435 Ygrow_ew_eat, FALSE, FALSE,
4436 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4439 Xwonderwall, TRUE, FALSE,
4440 EL_MAGIC_WALL, -1, -1
4443 XwonderwallB, FALSE, FALSE,
4444 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4447 Xamoeba_1, TRUE, FALSE,
4448 EL_AMOEBA_DRY, ACTION_OTHER, -1
4451 Xamoeba_2, FALSE, FALSE,
4452 EL_AMOEBA_DRY, ACTION_OTHER, -1
4455 Xamoeba_3, FALSE, FALSE,
4456 EL_AMOEBA_DRY, ACTION_OTHER, -1
4459 Xamoeba_4, FALSE, FALSE,
4460 EL_AMOEBA_DRY, ACTION_OTHER, -1
4463 Xamoeba_5, TRUE, FALSE,
4464 EL_AMOEBA_WET, ACTION_OTHER, -1
4467 Xamoeba_6, FALSE, FALSE,
4468 EL_AMOEBA_WET, ACTION_OTHER, -1
4471 Xamoeba_7, FALSE, FALSE,
4472 EL_AMOEBA_WET, ACTION_OTHER, -1
4475 Xamoeba_8, FALSE, FALSE,
4476 EL_AMOEBA_WET, ACTION_OTHER, -1
4479 Xdoor_1, TRUE, FALSE,
4480 EL_EM_GATE_1, -1, -1
4483 Xdoor_2, TRUE, FALSE,
4484 EL_EM_GATE_2, -1, -1
4487 Xdoor_3, TRUE, FALSE,
4488 EL_EM_GATE_3, -1, -1
4491 Xdoor_4, TRUE, FALSE,
4492 EL_EM_GATE_4, -1, -1
4495 Xdoor_5, TRUE, FALSE,
4496 EL_EMC_GATE_5, -1, -1
4499 Xdoor_6, TRUE, FALSE,
4500 EL_EMC_GATE_6, -1, -1
4503 Xdoor_7, TRUE, FALSE,
4504 EL_EMC_GATE_7, -1, -1
4507 Xdoor_8, TRUE, FALSE,
4508 EL_EMC_GATE_8, -1, -1
4511 Xkey_1, TRUE, FALSE,
4515 Xkey_2, TRUE, FALSE,
4519 Xkey_3, TRUE, FALSE,
4523 Xkey_4, TRUE, FALSE,
4527 Xkey_5, TRUE, FALSE,
4528 EL_EMC_KEY_5, -1, -1
4531 Xkey_6, TRUE, FALSE,
4532 EL_EMC_KEY_6, -1, -1
4535 Xkey_7, TRUE, FALSE,
4536 EL_EMC_KEY_7, -1, -1
4539 Xkey_8, TRUE, FALSE,
4540 EL_EMC_KEY_8, -1, -1
4543 Xwind_n, TRUE, FALSE,
4544 EL_BALLOON_SWITCH_UP, -1, -1
4547 Xwind_e, TRUE, FALSE,
4548 EL_BALLOON_SWITCH_RIGHT, -1, -1
4551 Xwind_s, TRUE, FALSE,
4552 EL_BALLOON_SWITCH_DOWN, -1, -1
4555 Xwind_w, TRUE, FALSE,
4556 EL_BALLOON_SWITCH_LEFT, -1, -1
4559 Xwind_nesw, TRUE, FALSE,
4560 EL_BALLOON_SWITCH_ANY, -1, -1
4563 Xwind_stop, TRUE, FALSE,
4564 EL_BALLOON_SWITCH_NONE, -1, -1
4568 EL_EM_EXIT_CLOSED, -1, -1
4571 Xexit_1, TRUE, FALSE,
4572 EL_EM_EXIT_OPEN, -1, -1
4575 Xexit_2, FALSE, FALSE,
4576 EL_EM_EXIT_OPEN, -1, -1
4579 Xexit_3, FALSE, FALSE,
4580 EL_EM_EXIT_OPEN, -1, -1
4583 Xdynamite, TRUE, FALSE,
4584 EL_EM_DYNAMITE, -1, -1
4587 Ydynamite_eat, FALSE, FALSE,
4588 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4591 Xdynamite_1, TRUE, FALSE,
4592 EL_EM_DYNAMITE_ACTIVE, -1, -1
4595 Xdynamite_2, FALSE, FALSE,
4596 EL_EM_DYNAMITE_ACTIVE, -1, -1
4599 Xdynamite_3, FALSE, FALSE,
4600 EL_EM_DYNAMITE_ACTIVE, -1, -1
4603 Xdynamite_4, FALSE, FALSE,
4604 EL_EM_DYNAMITE_ACTIVE, -1, -1
4607 Xbumper, TRUE, FALSE,
4608 EL_EMC_SPRING_BUMPER, -1, -1
4611 XbumperB, FALSE, FALSE,
4612 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4615 Xwheel, TRUE, FALSE,
4616 EL_ROBOT_WHEEL, -1, -1
4619 XwheelB, FALSE, FALSE,
4620 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4623 Xswitch, TRUE, FALSE,
4624 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4627 XswitchB, FALSE, FALSE,
4628 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4632 EL_QUICKSAND_EMPTY, -1, -1
4635 Xsand_stone, TRUE, FALSE,
4636 EL_QUICKSAND_FULL, -1, -1
4639 Xsand_stonein_1, FALSE, TRUE,
4640 EL_ROCK, ACTION_FILLING, -1
4643 Xsand_stonein_2, FALSE, TRUE,
4644 EL_ROCK, ACTION_FILLING, -1
4647 Xsand_stonein_3, FALSE, TRUE,
4648 EL_ROCK, ACTION_FILLING, -1
4651 Xsand_stonein_4, FALSE, TRUE,
4652 EL_ROCK, ACTION_FILLING, -1
4655 Xsand_stonesand_1, FALSE, FALSE,
4656 EL_QUICKSAND_FULL, -1, -1
4659 Xsand_stonesand_2, FALSE, FALSE,
4660 EL_QUICKSAND_FULL, -1, -1
4663 Xsand_stonesand_3, FALSE, FALSE,
4664 EL_QUICKSAND_FULL, -1, -1
4667 Xsand_stonesand_4, FALSE, FALSE,
4668 EL_QUICKSAND_FULL, -1, -1
4671 Xsand_stoneout_1, FALSE, FALSE,
4672 EL_ROCK, ACTION_EMPTYING, -1
4675 Xsand_stoneout_2, FALSE, FALSE,
4676 EL_ROCK, ACTION_EMPTYING, -1
4679 Xsand_sandstone_1, FALSE, FALSE,
4680 EL_QUICKSAND_FULL, -1, -1
4683 Xsand_sandstone_2, FALSE, FALSE,
4684 EL_QUICKSAND_FULL, -1, -1
4687 Xsand_sandstone_3, FALSE, FALSE,
4688 EL_QUICKSAND_FULL, -1, -1
4691 Xsand_sandstone_4, FALSE, FALSE,
4692 EL_QUICKSAND_FULL, -1, -1
4695 Xplant, TRUE, FALSE,
4696 EL_EMC_PLANT, -1, -1
4699 Yplant, FALSE, FALSE,
4700 EL_EMC_PLANT, -1, -1
4703 Xlenses, TRUE, FALSE,
4704 EL_EMC_LENSES, -1, -1
4707 Xmagnify, TRUE, FALSE,
4708 EL_EMC_MAGNIFIER, -1, -1
4711 Xdripper, TRUE, FALSE,
4712 EL_EMC_DRIPPER, -1, -1
4715 XdripperB, FALSE, FALSE,
4716 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4719 Xfake_blank, TRUE, FALSE,
4720 EL_INVISIBLE_WALL, -1, -1
4723 Xfake_blankB, FALSE, FALSE,
4724 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4727 Xfake_grass, TRUE, FALSE,
4728 EL_EMC_FAKE_GRASS, -1, -1
4731 Xfake_grassB, FALSE, FALSE,
4732 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4735 Xfake_door_1, TRUE, FALSE,
4736 EL_EM_GATE_1_GRAY, -1, -1
4739 Xfake_door_2, TRUE, FALSE,
4740 EL_EM_GATE_2_GRAY, -1, -1
4743 Xfake_door_3, TRUE, FALSE,
4744 EL_EM_GATE_3_GRAY, -1, -1
4747 Xfake_door_4, TRUE, FALSE,
4748 EL_EM_GATE_4_GRAY, -1, -1
4751 Xfake_door_5, TRUE, FALSE,
4752 EL_EMC_GATE_5_GRAY, -1, -1
4755 Xfake_door_6, TRUE, FALSE,
4756 EL_EMC_GATE_6_GRAY, -1, -1
4759 Xfake_door_7, TRUE, FALSE,
4760 EL_EMC_GATE_7_GRAY, -1, -1
4763 Xfake_door_8, TRUE, FALSE,
4764 EL_EMC_GATE_8_GRAY, -1, -1
4767 Xfake_acid_1, TRUE, FALSE,
4768 EL_EMC_FAKE_ACID, -1, -1
4771 Xfake_acid_2, FALSE, FALSE,
4772 EL_EMC_FAKE_ACID, -1, -1
4775 Xfake_acid_3, FALSE, FALSE,
4776 EL_EMC_FAKE_ACID, -1, -1
4779 Xfake_acid_4, FALSE, FALSE,
4780 EL_EMC_FAKE_ACID, -1, -1
4783 Xfake_acid_5, FALSE, FALSE,
4784 EL_EMC_FAKE_ACID, -1, -1
4787 Xfake_acid_6, FALSE, FALSE,
4788 EL_EMC_FAKE_ACID, -1, -1
4791 Xfake_acid_7, FALSE, FALSE,
4792 EL_EMC_FAKE_ACID, -1, -1
4795 Xfake_acid_8, FALSE, FALSE,
4796 EL_EMC_FAKE_ACID, -1, -1
4799 Xsteel_1, TRUE, FALSE,
4800 EL_STEELWALL, -1, -1
4803 Xsteel_2, TRUE, FALSE,
4804 EL_EMC_STEELWALL_2, -1, -1
4807 Xsteel_3, TRUE, FALSE,
4808 EL_EMC_STEELWALL_3, -1, -1
4811 Xsteel_4, TRUE, FALSE,
4812 EL_EMC_STEELWALL_4, -1, -1
4815 Xwall_1, TRUE, FALSE,
4819 Xwall_2, TRUE, FALSE,
4820 EL_EMC_WALL_14, -1, -1
4823 Xwall_3, TRUE, FALSE,
4824 EL_EMC_WALL_15, -1, -1
4827 Xwall_4, TRUE, FALSE,
4828 EL_EMC_WALL_16, -1, -1
4831 Xround_wall_1, TRUE, FALSE,
4832 EL_WALL_SLIPPERY, -1, -1
4835 Xround_wall_2, TRUE, FALSE,
4836 EL_EMC_WALL_SLIPPERY_2, -1, -1
4839 Xround_wall_3, TRUE, FALSE,
4840 EL_EMC_WALL_SLIPPERY_3, -1, -1
4843 Xround_wall_4, TRUE, FALSE,
4844 EL_EMC_WALL_SLIPPERY_4, -1, -1
4847 Xdecor_1, TRUE, FALSE,
4848 EL_EMC_WALL_8, -1, -1
4851 Xdecor_2, TRUE, FALSE,
4852 EL_EMC_WALL_6, -1, -1
4855 Xdecor_3, TRUE, FALSE,
4856 EL_EMC_WALL_4, -1, -1
4859 Xdecor_4, TRUE, FALSE,
4860 EL_EMC_WALL_7, -1, -1
4863 Xdecor_5, TRUE, FALSE,
4864 EL_EMC_WALL_5, -1, -1
4867 Xdecor_6, TRUE, FALSE,
4868 EL_EMC_WALL_9, -1, -1
4871 Xdecor_7, TRUE, FALSE,
4872 EL_EMC_WALL_10, -1, -1
4875 Xdecor_8, TRUE, FALSE,
4876 EL_EMC_WALL_1, -1, -1
4879 Xdecor_9, TRUE, FALSE,
4880 EL_EMC_WALL_2, -1, -1
4883 Xdecor_10, TRUE, FALSE,
4884 EL_EMC_WALL_3, -1, -1
4887 Xdecor_11, TRUE, FALSE,
4888 EL_EMC_WALL_11, -1, -1
4891 Xdecor_12, TRUE, FALSE,
4892 EL_EMC_WALL_12, -1, -1
4895 Xalpha_0, TRUE, FALSE,
4896 EL_CHAR('0'), -1, -1
4899 Xalpha_1, TRUE, FALSE,
4900 EL_CHAR('1'), -1, -1
4903 Xalpha_2, TRUE, FALSE,
4904 EL_CHAR('2'), -1, -1
4907 Xalpha_3, TRUE, FALSE,
4908 EL_CHAR('3'), -1, -1
4911 Xalpha_4, TRUE, FALSE,
4912 EL_CHAR('4'), -1, -1
4915 Xalpha_5, TRUE, FALSE,
4916 EL_CHAR('5'), -1, -1
4919 Xalpha_6, TRUE, FALSE,
4920 EL_CHAR('6'), -1, -1
4923 Xalpha_7, TRUE, FALSE,
4924 EL_CHAR('7'), -1, -1
4927 Xalpha_8, TRUE, FALSE,
4928 EL_CHAR('8'), -1, -1
4931 Xalpha_9, TRUE, FALSE,
4932 EL_CHAR('9'), -1, -1
4935 Xalpha_excla, TRUE, FALSE,
4936 EL_CHAR('!'), -1, -1
4939 Xalpha_quote, TRUE, FALSE,
4940 EL_CHAR('"'), -1, -1
4943 Xalpha_comma, TRUE, FALSE,
4944 EL_CHAR(','), -1, -1
4947 Xalpha_minus, TRUE, FALSE,
4948 EL_CHAR('-'), -1, -1
4951 Xalpha_perio, TRUE, FALSE,
4952 EL_CHAR('.'), -1, -1
4955 Xalpha_colon, TRUE, FALSE,
4956 EL_CHAR(':'), -1, -1
4959 Xalpha_quest, TRUE, FALSE,
4960 EL_CHAR('?'), -1, -1
4963 Xalpha_a, TRUE, FALSE,
4964 EL_CHAR('A'), -1, -1
4967 Xalpha_b, TRUE, FALSE,
4968 EL_CHAR('B'), -1, -1
4971 Xalpha_c, TRUE, FALSE,
4972 EL_CHAR('C'), -1, -1
4975 Xalpha_d, TRUE, FALSE,
4976 EL_CHAR('D'), -1, -1
4979 Xalpha_e, TRUE, FALSE,
4980 EL_CHAR('E'), -1, -1
4983 Xalpha_f, TRUE, FALSE,
4984 EL_CHAR('F'), -1, -1
4987 Xalpha_g, TRUE, FALSE,
4988 EL_CHAR('G'), -1, -1
4991 Xalpha_h, TRUE, FALSE,
4992 EL_CHAR('H'), -1, -1
4995 Xalpha_i, TRUE, FALSE,
4996 EL_CHAR('I'), -1, -1
4999 Xalpha_j, TRUE, FALSE,
5000 EL_CHAR('J'), -1, -1
5003 Xalpha_k, TRUE, FALSE,
5004 EL_CHAR('K'), -1, -1
5007 Xalpha_l, TRUE, FALSE,
5008 EL_CHAR('L'), -1, -1
5011 Xalpha_m, TRUE, FALSE,
5012 EL_CHAR('M'), -1, -1
5015 Xalpha_n, TRUE, FALSE,
5016 EL_CHAR('N'), -1, -1
5019 Xalpha_o, TRUE, FALSE,
5020 EL_CHAR('O'), -1, -1
5023 Xalpha_p, TRUE, FALSE,
5024 EL_CHAR('P'), -1, -1
5027 Xalpha_q, TRUE, FALSE,
5028 EL_CHAR('Q'), -1, -1
5031 Xalpha_r, TRUE, FALSE,
5032 EL_CHAR('R'), -1, -1
5035 Xalpha_s, TRUE, FALSE,
5036 EL_CHAR('S'), -1, -1
5039 Xalpha_t, TRUE, FALSE,
5040 EL_CHAR('T'), -1, -1
5043 Xalpha_u, TRUE, FALSE,
5044 EL_CHAR('U'), -1, -1
5047 Xalpha_v, TRUE, FALSE,
5048 EL_CHAR('V'), -1, -1
5051 Xalpha_w, TRUE, FALSE,
5052 EL_CHAR('W'), -1, -1
5055 Xalpha_x, TRUE, FALSE,
5056 EL_CHAR('X'), -1, -1
5059 Xalpha_y, TRUE, FALSE,
5060 EL_CHAR('Y'), -1, -1
5063 Xalpha_z, TRUE, FALSE,
5064 EL_CHAR('Z'), -1, -1
5067 Xalpha_arrow_e, TRUE, FALSE,
5068 EL_CHAR('>'), -1, -1
5071 Xalpha_arrow_w, TRUE, FALSE,
5072 EL_CHAR('<'), -1, -1
5075 Xalpha_copyr, TRUE, FALSE,
5076 EL_CHAR('©'), -1, -1
5080 Xboom_bug, FALSE, FALSE,
5081 EL_BUG, ACTION_EXPLODING, -1
5084 Xboom_bomb, FALSE, FALSE,
5085 EL_BOMB, ACTION_EXPLODING, -1
5088 Xboom_android, FALSE, FALSE,
5089 EL_EMC_ANDROID, ACTION_OTHER, -1
5092 Xboom_1, FALSE, FALSE,
5093 EL_DEFAULT, ACTION_EXPLODING, -1
5096 Xboom_2, FALSE, FALSE,
5097 EL_DEFAULT, ACTION_EXPLODING, -1
5100 Znormal, FALSE, FALSE,
5104 Zdynamite, FALSE, FALSE,
5108 Zplayer, FALSE, FALSE,
5112 ZBORDER, FALSE, FALSE,
5122 static struct Mapping_EM_to_RND_player
5131 em_player_mapping_list[] =
5135 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5139 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5143 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5147 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5151 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5155 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5159 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5163 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5167 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5171 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5175 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5179 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5183 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5187 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5191 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5195 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5199 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5203 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5207 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5211 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5215 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5219 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5223 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5227 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5231 EL_PLAYER_1, ACTION_DEFAULT, -1,
5235 EL_PLAYER_2, ACTION_DEFAULT, -1,
5239 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5243 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5247 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5251 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5255 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5259 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5263 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5267 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5271 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5275 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5279 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5283 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5287 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5291 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5295 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5299 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5303 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5307 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5311 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5315 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5319 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5323 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5327 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5331 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5335 EL_PLAYER_3, ACTION_DEFAULT, -1,
5339 EL_PLAYER_4, ACTION_DEFAULT, -1,
5348 int map_element_RND_to_EM(int element_rnd)
5350 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5351 static boolean mapping_initialized = FALSE;
5353 if (!mapping_initialized)
5357 /* return "Xalpha_quest" for all undefined elements in mapping array */
5358 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5359 mapping_RND_to_EM[i] = Xalpha_quest;
5361 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5362 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5363 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5364 em_object_mapping_list[i].element_em;
5366 mapping_initialized = TRUE;
5369 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5370 return mapping_RND_to_EM[element_rnd];
5372 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5377 int map_element_EM_to_RND(int element_em)
5379 static unsigned short mapping_EM_to_RND[TILE_MAX];
5380 static boolean mapping_initialized = FALSE;
5382 if (!mapping_initialized)
5386 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5387 for (i = 0; i < TILE_MAX; i++)
5388 mapping_EM_to_RND[i] = EL_UNKNOWN;
5390 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5391 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5392 em_object_mapping_list[i].element_rnd;
5394 mapping_initialized = TRUE;
5397 if (element_em >= 0 && element_em < TILE_MAX)
5398 return mapping_EM_to_RND[element_em];
5400 Error(ERR_WARN, "invalid EM level element %d", element_em);
5405 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5407 struct LevelInfo_EM *level_em = level->native_em_level;
5408 struct LEVEL *lev = level_em->lev;
5411 for (i = 0; i < TILE_MAX; i++)
5412 lev->android_array[i] = Xblank;
5414 for (i = 0; i < level->num_android_clone_elements; i++)
5416 int element_rnd = level->android_clone_element[i];
5417 int element_em = map_element_RND_to_EM(element_rnd);
5419 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5420 if (em_object_mapping_list[j].element_rnd == element_rnd)
5421 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5425 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5427 struct LevelInfo_EM *level_em = level->native_em_level;
5428 struct LEVEL *lev = level_em->lev;
5431 level->num_android_clone_elements = 0;
5433 for (i = 0; i < TILE_MAX; i++)
5435 int element_em = lev->android_array[i];
5437 boolean element_found = FALSE;
5439 if (element_em == Xblank)
5442 element_rnd = map_element_EM_to_RND(element_em);
5444 for (j = 0; j < level->num_android_clone_elements; j++)
5445 if (level->android_clone_element[j] == element_rnd)
5446 element_found = TRUE;
5450 level->android_clone_element[level->num_android_clone_elements++] =
5453 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5458 if (level->num_android_clone_elements == 0)
5460 level->num_android_clone_elements = 1;
5461 level->android_clone_element[0] = EL_EMPTY;
5465 int map_direction_RND_to_EM(int direction)
5467 return (direction == MV_UP ? 0 :
5468 direction == MV_RIGHT ? 1 :
5469 direction == MV_DOWN ? 2 :
5470 direction == MV_LEFT ? 3 :
5474 int map_direction_EM_to_RND(int direction)
5476 return (direction == 0 ? MV_UP :
5477 direction == 1 ? MV_RIGHT :
5478 direction == 2 ? MV_DOWN :
5479 direction == 3 ? MV_LEFT :
5483 int get_next_element(int element)
5487 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5488 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5489 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5490 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5491 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5492 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5493 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5494 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5495 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5496 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5497 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5499 default: return element;
5504 int el_act_dir2img(int element, int action, int direction)
5506 element = GFX_ELEMENT(element);
5508 if (direction == MV_NONE)
5509 return element_info[element].graphic[action];
5511 direction = MV_DIR_TO_BIT(direction);
5513 return element_info[element].direction_graphic[action][direction];
5516 int el_act_dir2img(int element, int action, int direction)
5518 element = GFX_ELEMENT(element);
5519 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5521 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5522 return element_info[element].direction_graphic[action][direction];
5527 static int el_act_dir2crm(int element, int action, int direction)
5529 element = GFX_ELEMENT(element);
5531 if (direction == MV_NONE)
5532 return element_info[element].crumbled[action];
5534 direction = MV_DIR_TO_BIT(direction);
5536 return element_info[element].direction_crumbled[action][direction];
5539 static int el_act_dir2crm(int element, int action, int direction)
5541 element = GFX_ELEMENT(element);
5542 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5544 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5545 return element_info[element].direction_crumbled[action][direction];
5549 int el_act2img(int element, int action)
5551 element = GFX_ELEMENT(element);
5553 return element_info[element].graphic[action];
5556 int el_act2crm(int element, int action)
5558 element = GFX_ELEMENT(element);
5560 return element_info[element].crumbled[action];
5563 int el_dir2img(int element, int direction)
5565 element = GFX_ELEMENT(element);
5567 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5570 int el2baseimg(int element)
5572 return element_info[element].graphic[ACTION_DEFAULT];
5575 int el2img(int element)
5577 element = GFX_ELEMENT(element);
5579 return element_info[element].graphic[ACTION_DEFAULT];
5582 int el2edimg(int element)
5584 element = GFX_ELEMENT(element);
5586 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5589 int el2preimg(int element)
5591 element = GFX_ELEMENT(element);
5593 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5596 int font2baseimg(int font_nr)
5598 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5601 int getBeltNrFromBeltElement(int element)
5603 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5604 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5605 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5608 int getBeltNrFromBeltActiveElement(int element)
5610 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5611 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5612 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5615 int getBeltNrFromBeltSwitchElement(int element)
5617 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5618 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5619 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5622 int getBeltDirNrFromBeltElement(int element)
5624 static int belt_base_element[4] =
5626 EL_CONVEYOR_BELT_1_LEFT,
5627 EL_CONVEYOR_BELT_2_LEFT,
5628 EL_CONVEYOR_BELT_3_LEFT,
5629 EL_CONVEYOR_BELT_4_LEFT
5632 int belt_nr = getBeltNrFromBeltElement(element);
5633 int belt_dir_nr = element - belt_base_element[belt_nr];
5635 return (belt_dir_nr % 3);
5638 int getBeltDirNrFromBeltSwitchElement(int element)
5640 static int belt_base_element[4] =
5642 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5643 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5644 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5645 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5648 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5649 int belt_dir_nr = element - belt_base_element[belt_nr];
5651 return (belt_dir_nr % 3);
5654 int getBeltDirFromBeltElement(int element)
5656 static int belt_move_dir[3] =
5663 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5665 return belt_move_dir[belt_dir_nr];
5668 int getBeltDirFromBeltSwitchElement(int element)
5670 static int belt_move_dir[3] =
5677 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5679 return belt_move_dir[belt_dir_nr];
5682 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5684 static int belt_base_element[4] =
5686 EL_CONVEYOR_BELT_1_LEFT,
5687 EL_CONVEYOR_BELT_2_LEFT,
5688 EL_CONVEYOR_BELT_3_LEFT,
5689 EL_CONVEYOR_BELT_4_LEFT
5691 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5693 return belt_base_element[belt_nr] + belt_dir_nr;
5696 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5698 static int belt_base_element[4] =
5700 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5701 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5702 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5703 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5705 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5707 return belt_base_element[belt_nr] + belt_dir_nr;
5710 int getNumActivePlayers_EM()
5712 int num_players = 0;
5718 for (i = 0; i < MAX_PLAYERS; i++)
5719 if (tape.player_participates[i])
5725 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5727 int game_frame_delay_value;
5729 game_frame_delay_value =
5730 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5731 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5734 if (tape.playing && tape.warp_forward && !tape.pausing)
5735 game_frame_delay_value = 0;
5737 return game_frame_delay_value;
5740 unsigned int InitRND(long seed)
5742 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5743 return InitEngineRandom_EM(seed);
5745 return InitEngineRandom_RND(seed);
5749 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5750 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5753 void ResetGfxAnimation_EM(int x, int y, int tile)
5758 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5759 Bitmap **src_bitmap, int *src_x, int *src_y,
5762 int element = object_mapping[tile].element_rnd;
5763 int action = object_mapping[tile].action;
5764 int direction = object_mapping[tile].direction;
5765 boolean is_backside = object_mapping[tile].is_backside;
5766 boolean action_removing = (action == ACTION_DIGGING ||
5767 action == ACTION_SNAPPING ||
5768 action == ACTION_COLLECTING);
5769 int effective_element = (frame_em > 0 ? element :
5770 is_backside ? EL_EMPTY :
5771 action_removing ? EL_EMPTY :
5773 int graphic = (direction == MV_NONE ?
5774 el_act2img(effective_element, action) :
5775 el_act_dir2img(effective_element, action, direction));
5776 struct GraphicInfo *g = &graphic_info[graphic];
5779 if (graphic_info[graphic].anim_global_sync)
5780 sync_frame = FrameCounter;
5782 sync_frame = 7 - frame_em;
5784 SetRandomAnimationValue(x, y);
5786 int frame = getAnimationFrame(g->anim_frames,
5789 g->anim_start_frame,
5792 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5795 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
5796 Bitmap **src_bitmap, int *src_x, int *src_y)
5798 int element = player_mapping[player_nr][anim].element_rnd;
5799 int action = player_mapping[player_nr][anim].action;
5800 int direction = player_mapping[player_nr][anim].direction;
5801 int graphic = (direction == MV_NONE ?
5802 el_act2img(element, action) :
5803 el_act_dir2img(element, action, direction));
5804 struct GraphicInfo *g = &graphic_info[graphic];
5807 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
5809 stored_player[player_nr].StepFrame = 7 - frame_em;
5811 sync_frame = stored_player[player_nr].Frame;
5814 printf("::: %d: %d, %d [%d]\n",
5816 stored_player[player_nr].Frame,
5817 stored_player[player_nr].StepFrame,
5821 int frame = getAnimationFrame(g->anim_frames,
5824 g->anim_start_frame,
5827 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5830 void InitGraphicInfo_EM(void)
5833 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5834 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5839 int num_em_gfx_errors = 0;
5841 if (graphic_info_em_object[0][0].bitmap == NULL)
5843 /* EM graphics not yet initialized in em_open_all() */
5848 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5851 /* always start with reliable default values */
5852 for (i = 0; i < TILE_MAX; i++)
5854 object_mapping[i].element_rnd = EL_UNKNOWN;
5855 object_mapping[i].is_backside = FALSE;
5856 object_mapping[i].action = ACTION_DEFAULT;
5857 object_mapping[i].direction = MV_NONE;
5860 /* always start with reliable default values */
5861 for (p = 0; p < MAX_PLAYERS; p++)
5863 for (i = 0; i < SPR_MAX; i++)
5865 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5866 player_mapping[p][i].action = ACTION_DEFAULT;
5867 player_mapping[p][i].direction = MV_NONE;
5871 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5873 int e = em_object_mapping_list[i].element_em;
5875 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5876 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5878 if (em_object_mapping_list[i].action != -1)
5879 object_mapping[e].action = em_object_mapping_list[i].action;
5881 if (em_object_mapping_list[i].direction != -1)
5882 object_mapping[e].direction =
5883 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5886 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5888 int a = em_player_mapping_list[i].action_em;
5889 int p = em_player_mapping_list[i].player_nr;
5891 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5893 if (em_player_mapping_list[i].action != -1)
5894 player_mapping[p][a].action = em_player_mapping_list[i].action;
5896 if (em_player_mapping_list[i].direction != -1)
5897 player_mapping[p][a].direction =
5898 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5901 for (i = 0; i < TILE_MAX; i++)
5903 int element = object_mapping[i].element_rnd;
5904 int action = object_mapping[i].action;
5905 int direction = object_mapping[i].direction;
5906 boolean is_backside = object_mapping[i].is_backside;
5907 boolean action_removing = (action == ACTION_DIGGING ||
5908 action == ACTION_SNAPPING ||
5909 action == ACTION_COLLECTING);
5910 boolean action_exploding = ((action == ACTION_EXPLODING ||
5911 action == ACTION_SMASHED_BY_ROCK ||
5912 action == ACTION_SMASHED_BY_SPRING) &&
5913 element != EL_DIAMOND);
5914 boolean action_active = (action == ACTION_ACTIVE);
5915 boolean action_other = (action == ACTION_OTHER);
5917 for (j = 0; j < 8; j++)
5919 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5920 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5922 i == Xdrip_stretch ? element :
5923 i == Xdrip_stretchB ? element :
5924 i == Ydrip_s1 ? element :
5925 i == Ydrip_s1B ? element :
5926 i == Xball_1B ? element :
5927 i == Xball_2 ? element :
5928 i == Xball_2B ? element :
5929 i == Yball_eat ? element :
5930 i == Ykey_1_eat ? element :
5931 i == Ykey_2_eat ? element :
5932 i == Ykey_3_eat ? element :
5933 i == Ykey_4_eat ? element :
5934 i == Ykey_5_eat ? element :
5935 i == Ykey_6_eat ? element :
5936 i == Ykey_7_eat ? element :
5937 i == Ykey_8_eat ? element :
5938 i == Ylenses_eat ? element :
5939 i == Ymagnify_eat ? element :
5940 i == Ygrass_eat ? element :
5941 i == Ydirt_eat ? element :
5942 i == Yemerald_stone ? EL_EMERALD :
5943 i == Ydiamond_stone ? EL_ROCK :
5944 i == Xsand_stonein_1 ? element :
5945 i == Xsand_stonein_2 ? element :
5946 i == Xsand_stonein_3 ? element :
5947 i == Xsand_stonein_4 ? element :
5948 is_backside ? EL_EMPTY :
5949 action_removing ? EL_EMPTY :
5951 int effective_action = (j < 7 ? action :
5952 i == Xdrip_stretch ? action :
5953 i == Xdrip_stretchB ? action :
5954 i == Ydrip_s1 ? action :
5955 i == Ydrip_s1B ? action :
5956 i == Xball_1B ? action :
5957 i == Xball_2 ? action :
5958 i == Xball_2B ? action :
5959 i == Yball_eat ? action :
5960 i == Ykey_1_eat ? action :
5961 i == Ykey_2_eat ? action :
5962 i == Ykey_3_eat ? action :
5963 i == Ykey_4_eat ? action :
5964 i == Ykey_5_eat ? action :
5965 i == Ykey_6_eat ? action :
5966 i == Ykey_7_eat ? action :
5967 i == Ykey_8_eat ? action :
5968 i == Ylenses_eat ? action :
5969 i == Ymagnify_eat ? action :
5970 i == Ygrass_eat ? action :
5971 i == Ydirt_eat ? action :
5972 i == Xsand_stonein_1 ? action :
5973 i == Xsand_stonein_2 ? action :
5974 i == Xsand_stonein_3 ? action :
5975 i == Xsand_stonein_4 ? action :
5976 i == Xsand_stoneout_1 ? action :
5977 i == Xsand_stoneout_2 ? action :
5978 i == Xboom_android ? ACTION_EXPLODING :
5979 action_exploding ? ACTION_EXPLODING :
5980 action_active ? action :
5981 action_other ? action :
5983 int graphic = (el_act_dir2img(effective_element, effective_action,
5985 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5987 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5988 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5989 boolean has_action_graphics = (graphic != base_graphic);
5990 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5991 struct GraphicInfo *g = &graphic_info[graphic];
5992 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5995 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5996 boolean special_animation = (action != ACTION_DEFAULT &&
5997 g->anim_frames == 3 &&
5998 g->anim_delay == 2 &&
5999 g->anim_mode & ANIM_LINEAR);
6000 int sync_frame = (i == Xdrip_stretch ? 7 :
6001 i == Xdrip_stretchB ? 7 :
6002 i == Ydrip_s2 ? j + 8 :
6003 i == Ydrip_s2B ? j + 8 :
6012 i == Xfake_acid_1 ? 0 :
6013 i == Xfake_acid_2 ? 10 :
6014 i == Xfake_acid_3 ? 20 :
6015 i == Xfake_acid_4 ? 30 :
6016 i == Xfake_acid_5 ? 40 :
6017 i == Xfake_acid_6 ? 50 :
6018 i == Xfake_acid_7 ? 60 :
6019 i == Xfake_acid_8 ? 70 :
6021 i == Xball_2B ? j + 8 :
6022 i == Yball_eat ? j + 1 :
6023 i == Ykey_1_eat ? j + 1 :
6024 i == Ykey_2_eat ? j + 1 :
6025 i == Ykey_3_eat ? j + 1 :
6026 i == Ykey_4_eat ? j + 1 :
6027 i == Ykey_5_eat ? j + 1 :
6028 i == Ykey_6_eat ? j + 1 :
6029 i == Ykey_7_eat ? j + 1 :
6030 i == Ykey_8_eat ? j + 1 :
6031 i == Ylenses_eat ? j + 1 :
6032 i == Ymagnify_eat ? j + 1 :
6033 i == Ygrass_eat ? j + 1 :
6034 i == Ydirt_eat ? j + 1 :
6035 i == Xamoeba_1 ? 0 :
6036 i == Xamoeba_2 ? 1 :
6037 i == Xamoeba_3 ? 2 :
6038 i == Xamoeba_4 ? 3 :
6039 i == Xamoeba_5 ? 0 :
6040 i == Xamoeba_6 ? 1 :
6041 i == Xamoeba_7 ? 2 :
6042 i == Xamoeba_8 ? 3 :
6043 i == Xexit_2 ? j + 8 :
6044 i == Xexit_3 ? j + 16 :
6045 i == Xdynamite_1 ? 0 :
6046 i == Xdynamite_2 ? 8 :
6047 i == Xdynamite_3 ? 16 :
6048 i == Xdynamite_4 ? 24 :
6049 i == Xsand_stonein_1 ? j + 1 :
6050 i == Xsand_stonein_2 ? j + 9 :
6051 i == Xsand_stonein_3 ? j + 17 :
6052 i == Xsand_stonein_4 ? j + 25 :
6053 i == Xsand_stoneout_1 && j == 0 ? 0 :
6054 i == Xsand_stoneout_1 && j == 1 ? 0 :
6055 i == Xsand_stoneout_1 && j == 2 ? 1 :
6056 i == Xsand_stoneout_1 && j == 3 ? 2 :
6057 i == Xsand_stoneout_1 && j == 4 ? 2 :
6058 i == Xsand_stoneout_1 && j == 5 ? 3 :
6059 i == Xsand_stoneout_1 && j == 6 ? 4 :
6060 i == Xsand_stoneout_1 && j == 7 ? 4 :
6061 i == Xsand_stoneout_2 && j == 0 ? 5 :
6062 i == Xsand_stoneout_2 && j == 1 ? 6 :
6063 i == Xsand_stoneout_2 && j == 2 ? 7 :
6064 i == Xsand_stoneout_2 && j == 3 ? 8 :
6065 i == Xsand_stoneout_2 && j == 4 ? 9 :
6066 i == Xsand_stoneout_2 && j == 5 ? 11 :
6067 i == Xsand_stoneout_2 && j == 6 ? 13 :
6068 i == Xsand_stoneout_2 && j == 7 ? 15 :
6069 i == Xboom_bug && j == 1 ? 2 :
6070 i == Xboom_bug && j == 2 ? 2 :
6071 i == Xboom_bug && j == 3 ? 4 :
6072 i == Xboom_bug && j == 4 ? 4 :
6073 i == Xboom_bug && j == 5 ? 2 :
6074 i == Xboom_bug && j == 6 ? 2 :
6075 i == Xboom_bug && j == 7 ? 0 :
6076 i == Xboom_bomb && j == 1 ? 2 :
6077 i == Xboom_bomb && j == 2 ? 2 :
6078 i == Xboom_bomb && j == 3 ? 4 :
6079 i == Xboom_bomb && j == 4 ? 4 :
6080 i == Xboom_bomb && j == 5 ? 2 :
6081 i == Xboom_bomb && j == 6 ? 2 :
6082 i == Xboom_bomb && j == 7 ? 0 :
6083 i == Xboom_android && j == 7 ? 6 :
6084 i == Xboom_1 && j == 1 ? 2 :
6085 i == Xboom_1 && j == 2 ? 2 :
6086 i == Xboom_1 && j == 3 ? 4 :
6087 i == Xboom_1 && j == 4 ? 4 :
6088 i == Xboom_1 && j == 5 ? 6 :
6089 i == Xboom_1 && j == 6 ? 6 :
6090 i == Xboom_1 && j == 7 ? 8 :
6091 i == Xboom_2 && j == 0 ? 8 :
6092 i == Xboom_2 && j == 1 ? 8 :
6093 i == Xboom_2 && j == 2 ? 10 :
6094 i == Xboom_2 && j == 3 ? 10 :
6095 i == Xboom_2 && j == 4 ? 10 :
6096 i == Xboom_2 && j == 5 ? 12 :
6097 i == Xboom_2 && j == 6 ? 12 :
6098 i == Xboom_2 && j == 7 ? 12 :
6099 special_animation && j == 4 ? 3 :
6100 effective_action != action ? 0 :
6104 Bitmap *debug_bitmap = g_em->bitmap;
6105 int debug_src_x = g_em->src_x;
6106 int debug_src_y = g_em->src_y;
6109 int frame = getAnimationFrame(g->anim_frames,
6112 g->anim_start_frame,
6115 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6116 g->double_movement && is_backside);
6118 g_em->bitmap = src_bitmap;
6119 g_em->src_x = src_x;
6120 g_em->src_y = src_y;
6121 g_em->src_offset_x = 0;
6122 g_em->src_offset_y = 0;
6123 g_em->dst_offset_x = 0;
6124 g_em->dst_offset_y = 0;
6125 g_em->width = TILEX;
6126 g_em->height = TILEY;
6128 g_em->crumbled_bitmap = NULL;
6129 g_em->crumbled_src_x = 0;
6130 g_em->crumbled_src_y = 0;
6131 g_em->crumbled_border_size = 0;
6133 g_em->has_crumbled_graphics = FALSE;
6134 g_em->preserve_background = FALSE;
6137 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6138 printf("::: empty crumbled: %d [%s], %d, %d\n",
6139 effective_element, element_info[effective_element].token_name,
6140 effective_action, direction);
6143 /* if element can be crumbled, but certain action graphics are just empty
6144 space (like snapping sand with the original R'n'D graphics), do not
6145 treat these empty space graphics as crumbled graphics in EMC engine */
6146 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6148 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6150 g_em->has_crumbled_graphics = TRUE;
6151 g_em->crumbled_bitmap = src_bitmap;
6152 g_em->crumbled_src_x = src_x;
6153 g_em->crumbled_src_y = src_y;
6154 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6158 if (element == EL_ROCK &&
6159 effective_action == ACTION_FILLING)
6160 printf("::: has_action_graphics == %d\n", has_action_graphics);
6163 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6164 effective_action == ACTION_MOVING ||
6165 effective_action == ACTION_PUSHING ||
6166 effective_action == ACTION_EATING)) ||
6167 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6168 effective_action == ACTION_EMPTYING)))
6171 (effective_action == ACTION_FALLING ||
6172 effective_action == ACTION_FILLING ||
6173 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6174 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6175 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6176 int num_steps = (i == Ydrip_s1 ? 16 :
6177 i == Ydrip_s1B ? 16 :
6178 i == Ydrip_s2 ? 16 :
6179 i == Ydrip_s2B ? 16 :
6180 i == Xsand_stonein_1 ? 32 :
6181 i == Xsand_stonein_2 ? 32 :
6182 i == Xsand_stonein_3 ? 32 :
6183 i == Xsand_stonein_4 ? 32 :
6184 i == Xsand_stoneout_1 ? 16 :
6185 i == Xsand_stoneout_2 ? 16 : 8);
6186 int cx = ABS(dx) * (TILEX / num_steps);
6187 int cy = ABS(dy) * (TILEY / num_steps);
6188 int step_frame = (i == Ydrip_s2 ? j + 8 :
6189 i == Ydrip_s2B ? j + 8 :
6190 i == Xsand_stonein_2 ? j + 8 :
6191 i == Xsand_stonein_3 ? j + 16 :
6192 i == Xsand_stonein_4 ? j + 24 :
6193 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6194 int step = (is_backside ? step_frame : num_steps - step_frame);
6196 if (is_backside) /* tile where movement starts */
6198 if (dx < 0 || dy < 0)
6200 g_em->src_offset_x = cx * step;
6201 g_em->src_offset_y = cy * step;
6205 g_em->dst_offset_x = cx * step;
6206 g_em->dst_offset_y = cy * step;
6209 else /* tile where movement ends */
6211 if (dx < 0 || dy < 0)
6213 g_em->dst_offset_x = cx * step;
6214 g_em->dst_offset_y = cy * step;
6218 g_em->src_offset_x = cx * step;
6219 g_em->src_offset_y = cy * step;
6223 g_em->width = TILEX - cx * step;
6224 g_em->height = TILEY - cy * step;
6227 /* create unique graphic identifier to decide if tile must be redrawn */
6228 /* bit 31 - 16 (16 bit): EM style graphic
6229 bit 15 - 12 ( 4 bit): EM style frame
6230 bit 11 - 6 ( 6 bit): graphic width
6231 bit 5 - 0 ( 6 bit): graphic height */
6232 g_em->unique_identifier =
6233 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6237 /* skip check for EMC elements not contained in original EMC artwork */
6238 if (element == EL_EMC_FAKE_ACID)
6241 if (g_em->bitmap != debug_bitmap ||
6242 g_em->src_x != debug_src_x ||
6243 g_em->src_y != debug_src_y ||
6244 g_em->src_offset_x != 0 ||
6245 g_em->src_offset_y != 0 ||
6246 g_em->dst_offset_x != 0 ||
6247 g_em->dst_offset_y != 0 ||
6248 g_em->width != TILEX ||
6249 g_em->height != TILEY)
6251 static int last_i = -1;
6259 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6260 i, element, element_info[element].token_name,
6261 element_action_info[effective_action].suffix, direction);
6263 if (element != effective_element)
6264 printf(" [%d ('%s')]",
6266 element_info[effective_element].token_name);
6270 if (g_em->bitmap != debug_bitmap)
6271 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6272 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6274 if (g_em->src_x != debug_src_x ||
6275 g_em->src_y != debug_src_y)
6276 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6277 j, (is_backside ? 'B' : 'F'),
6278 g_em->src_x, g_em->src_y,
6279 g_em->src_x / 32, g_em->src_y / 32,
6280 debug_src_x, debug_src_y,
6281 debug_src_x / 32, debug_src_y / 32);
6283 if (g_em->src_offset_x != 0 ||
6284 g_em->src_offset_y != 0 ||
6285 g_em->dst_offset_x != 0 ||
6286 g_em->dst_offset_y != 0)
6287 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6289 g_em->src_offset_x, g_em->src_offset_y,
6290 g_em->dst_offset_x, g_em->dst_offset_y);
6292 if (g_em->width != TILEX ||
6293 g_em->height != TILEY)
6294 printf(" %d (%d): size %d,%d should be %d,%d\n",
6296 g_em->width, g_em->height, TILEX, TILEY);
6298 num_em_gfx_errors++;
6305 for (i = 0; i < TILE_MAX; i++)
6307 for (j = 0; j < 8; j++)
6309 int element = object_mapping[i].element_rnd;
6310 int action = object_mapping[i].action;
6311 int direction = object_mapping[i].direction;
6312 boolean is_backside = object_mapping[i].is_backside;
6313 int graphic_action = el_act_dir2img(element, action, direction);
6314 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6316 if ((action == ACTION_SMASHED_BY_ROCK ||
6317 action == ACTION_SMASHED_BY_SPRING ||
6318 action == ACTION_EATING) &&
6319 graphic_action == graphic_default)
6321 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6322 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6323 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6324 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6327 /* no separate animation for "smashed by rock" -- use rock instead */
6328 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6329 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6331 g_em->bitmap = g_xx->bitmap;
6332 g_em->src_x = g_xx->src_x;
6333 g_em->src_y = g_xx->src_y;
6334 g_em->src_offset_x = g_xx->src_offset_x;
6335 g_em->src_offset_y = g_xx->src_offset_y;
6336 g_em->dst_offset_x = g_xx->dst_offset_x;
6337 g_em->dst_offset_y = g_xx->dst_offset_y;
6338 g_em->width = g_xx->width;
6339 g_em->height = g_xx->height;
6340 g_em->unique_identifier = g_xx->unique_identifier;
6343 g_em->preserve_background = TRUE;
6348 for (p = 0; p < MAX_PLAYERS; p++)
6350 for (i = 0; i < SPR_MAX; i++)
6352 int element = player_mapping[p][i].element_rnd;
6353 int action = player_mapping[p][i].action;
6354 int direction = player_mapping[p][i].direction;
6356 for (j = 0; j < 8; j++)
6358 int effective_element = element;
6359 int effective_action = action;
6360 int graphic = (direction == MV_NONE ?
6361 el_act2img(effective_element, effective_action) :
6362 el_act_dir2img(effective_element, effective_action,
6364 struct GraphicInfo *g = &graphic_info[graphic];
6365 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6371 Bitmap *debug_bitmap = g_em->bitmap;
6372 int debug_src_x = g_em->src_x;
6373 int debug_src_y = g_em->src_y;
6376 int frame = getAnimationFrame(g->anim_frames,
6379 g->anim_start_frame,
6382 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6384 g_em->bitmap = src_bitmap;
6385 g_em->src_x = src_x;
6386 g_em->src_y = src_y;
6387 g_em->src_offset_x = 0;
6388 g_em->src_offset_y = 0;
6389 g_em->dst_offset_x = 0;
6390 g_em->dst_offset_y = 0;
6391 g_em->width = TILEX;
6392 g_em->height = TILEY;
6396 /* skip check for EMC elements not contained in original EMC artwork */
6397 if (element == EL_PLAYER_3 ||
6398 element == EL_PLAYER_4)
6401 if (g_em->bitmap != debug_bitmap ||
6402 g_em->src_x != debug_src_x ||
6403 g_em->src_y != debug_src_y)
6405 static int last_i = -1;
6413 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6414 p, i, element, element_info[element].token_name,
6415 element_action_info[effective_action].suffix, direction);
6417 if (element != effective_element)
6418 printf(" [%d ('%s')]",
6420 element_info[effective_element].token_name);
6424 if (g_em->bitmap != debug_bitmap)
6425 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6426 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6428 if (g_em->src_x != debug_src_x ||
6429 g_em->src_y != debug_src_y)
6430 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6432 g_em->src_x, g_em->src_y,
6433 g_em->src_x / 32, g_em->src_y / 32,
6434 debug_src_x, debug_src_y,
6435 debug_src_x / 32, debug_src_y / 32);
6437 num_em_gfx_errors++;
6447 printf("::: [%d errors found]\n", num_em_gfx_errors);
6453 void PlayMenuSound()
6455 int sound = menu.sound[game_status];
6457 if (sound == SND_UNDEFINED)
6460 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6461 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6464 if (IS_LOOP_SOUND(sound))
6465 PlaySoundLoop(sound);
6470 void PlayMenuSoundStereo(int sound, int stereo_position)
6472 if (sound == SND_UNDEFINED)
6475 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6476 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6479 if (IS_LOOP_SOUND(sound))
6480 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6482 PlaySoundStereo(sound, stereo_position);
6485 void PlayMenuSoundIfLoop()
6487 int sound = menu.sound[game_status];
6489 if (sound == SND_UNDEFINED)
6492 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6493 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6496 if (IS_LOOP_SOUND(sound))
6497 PlaySoundLoop(sound);
6500 void PlayMenuMusic()
6502 int music = menu.music[game_status];
6504 if (music == MUS_UNDEFINED)
6507 if (!setup.sound_music)
6513 void PlaySoundActivating()
6516 PlaySound(SND_MENU_ITEM_ACTIVATING);
6520 void PlaySoundSelecting()
6523 PlaySound(SND_MENU_ITEM_SELECTING);
6527 void ToggleFullscreenIfNeeded()
6529 boolean change_fullscreen = (setup.fullscreen !=
6530 video.fullscreen_enabled);
6531 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6532 !strEqual(setup.fullscreen_mode,
6533 video.fullscreen_mode_current));
6535 if (!video.fullscreen_available)
6539 if (change_fullscreen || change_fullscreen_mode)
6541 if (setup.fullscreen != video.fullscreen_enabled ||
6542 setup.fullscreen_mode != video.fullscreen_mode_current)
6545 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6547 /* save backbuffer content which gets lost when toggling fullscreen mode */
6548 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6551 if (change_fullscreen_mode)
6553 if (setup.fullscreen && video.fullscreen_enabled)
6556 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6558 /* (this is now set in sdl.c) */
6560 video.fullscreen_mode_current = setup.fullscreen_mode;
6562 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6565 /* toggle fullscreen */
6566 ChangeVideoModeIfNeeded(setup.fullscreen);
6568 setup.fullscreen = video.fullscreen_enabled;
6570 /* restore backbuffer content from temporary backbuffer backup bitmap */
6571 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6573 FreeBitmap(tmp_backbuffer);
6576 /* update visible window/screen */
6577 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6579 redraw_mask = REDRAW_ALL;