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);
1769 int dst_y = SY + preview.y;
1772 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1774 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1775 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1777 for (x = 0; x < real_preview_xsize; x++)
1779 for (y = 0; y < real_preview_ysize; y++)
1781 int lx = from_x + x + (show_level_border ? -1 : 0);
1782 int ly = from_y + y + (show_level_border ? -1 : 0);
1783 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1784 getBorderElement(lx, ly));
1786 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1787 element, tile_size);
1791 redraw_mask |= REDRAW_MICROLEVEL;
1794 #define MICROLABEL_EMPTY 0
1795 #define MICROLABEL_LEVEL_NAME 1
1796 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1797 #define MICROLABEL_LEVEL_AUTHOR 3
1798 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1799 #define MICROLABEL_IMPORTED_FROM 5
1800 #define MICROLABEL_IMPORTED_BY_HEAD 6
1801 #define MICROLABEL_IMPORTED_BY 7
1803 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
1805 int max_text_width = SXSIZE;
1806 int font_width = getFontWidth(font_nr);
1808 if (pos->align == ALIGN_CENTER)
1809 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1810 else if (pos->align == ALIGN_RIGHT)
1811 max_text_width = pos->x;
1813 max_text_width = SXSIZE - pos->x;
1815 return max_text_width / font_width;
1818 static void DrawPreviewLevelLabelExt(int mode)
1820 struct TextPosInfo *pos = &menu.main.text.level_info_2;
1821 char label_text[MAX_OUTPUT_LINESIZE + 1];
1822 int max_len_label_text;
1824 int font_nr = pos->font;
1827 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1828 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1829 mode == MICROLABEL_IMPORTED_BY_HEAD)
1830 font_nr = pos->font_alt;
1832 int font_nr = FONT_TEXT_2;
1835 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1836 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1837 mode == MICROLABEL_IMPORTED_BY_HEAD)
1838 font_nr = FONT_TEXT_3;
1842 max_len_label_text = getMaxTextLength(pos, font_nr);
1844 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1848 if (pos->chars != -1)
1849 max_len_label_text = pos->chars;
1852 for (i = 0; i < max_len_label_text; i++)
1853 label_text[i] = ' ';
1854 label_text[max_len_label_text] = '\0';
1856 if (strlen(label_text) > 0)
1859 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1861 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1862 int lypos = MICROLABEL2_YPOS;
1864 DrawText(lxpos, lypos, label_text, font_nr);
1869 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1870 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1871 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1872 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1873 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1874 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1875 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1876 max_len_label_text);
1877 label_text[max_len_label_text] = '\0';
1879 if (strlen(label_text) > 0)
1882 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1884 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1885 int lypos = MICROLABEL2_YPOS;
1887 DrawText(lxpos, lypos, label_text, font_nr);
1891 redraw_mask |= REDRAW_MICROLEVEL;
1894 void DrawPreviewLevel(boolean restart)
1896 static unsigned long scroll_delay = 0;
1897 static unsigned long label_delay = 0;
1898 static int from_x, from_y, scroll_direction;
1899 static int label_state, label_counter;
1900 unsigned long scroll_delay_value = preview.step_delay;
1901 boolean show_level_border = (BorderElement != EL_EMPTY);
1902 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1903 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1904 int last_game_status = game_status; /* save current game status */
1907 /* force PREVIEW font on preview level */
1908 game_status = GAME_MODE_PSEUDO_PREVIEW;
1916 if (preview.anim_mode == ANIM_CENTERED)
1918 if (level_xsize > preview.xsize)
1919 from_x = (level_xsize - preview.xsize) / 2;
1920 if (level_ysize > preview.ysize)
1921 from_y = (level_ysize - preview.ysize) / 2;
1924 from_x += preview.xoffset;
1925 from_y += preview.yoffset;
1927 scroll_direction = MV_RIGHT;
1931 DrawPreviewLevelExt(from_x, from_y);
1932 DrawPreviewLevelLabelExt(label_state);
1934 /* initialize delay counters */
1935 DelayReached(&scroll_delay, 0);
1936 DelayReached(&label_delay, 0);
1938 if (leveldir_current->name)
1940 struct TextPosInfo *pos = &menu.main.text.level_info_1;
1941 char label_text[MAX_OUTPUT_LINESIZE + 1];
1943 int font_nr = pos->font;
1945 int font_nr = FONT_TEXT_1;
1948 int max_len_label_text = getMaxTextLength(pos, font_nr);
1950 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1958 if (pos->chars != -1)
1959 max_len_label_text = pos->chars;
1962 strncpy(label_text, leveldir_current->name, max_len_label_text);
1963 label_text[max_len_label_text] = '\0';
1966 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1968 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1969 lypos = SY + MICROLABEL1_YPOS;
1971 DrawText(lxpos, lypos, label_text, font_nr);
1975 game_status = last_game_status; /* restore current game status */
1980 /* scroll preview level, if needed */
1981 if (preview.anim_mode != ANIM_NONE &&
1982 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1983 DelayReached(&scroll_delay, scroll_delay_value))
1985 switch (scroll_direction)
1990 from_x -= preview.step_offset;
1991 from_x = (from_x < 0 ? 0 : from_x);
1994 scroll_direction = MV_UP;
1998 if (from_x < level_xsize - preview.xsize)
2000 from_x += preview.step_offset;
2001 from_x = (from_x > level_xsize - preview.xsize ?
2002 level_xsize - preview.xsize : from_x);
2005 scroll_direction = MV_DOWN;
2011 from_y -= preview.step_offset;
2012 from_y = (from_y < 0 ? 0 : from_y);
2015 scroll_direction = MV_RIGHT;
2019 if (from_y < level_ysize - preview.ysize)
2021 from_y += preview.step_offset;
2022 from_y = (from_y > level_ysize - preview.ysize ?
2023 level_ysize - preview.ysize : from_y);
2026 scroll_direction = MV_LEFT;
2033 DrawPreviewLevelExt(from_x, from_y);
2036 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2037 /* redraw micro level label, if needed */
2038 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2039 !strEqual(level.author, ANONYMOUS_NAME) &&
2040 !strEqual(level.author, leveldir_current->name) &&
2041 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2043 int max_label_counter = 23;
2045 if (leveldir_current->imported_from != NULL &&
2046 strlen(leveldir_current->imported_from) > 0)
2047 max_label_counter += 14;
2048 if (leveldir_current->imported_by != NULL &&
2049 strlen(leveldir_current->imported_by) > 0)
2050 max_label_counter += 14;
2052 label_counter = (label_counter + 1) % max_label_counter;
2053 label_state = (label_counter >= 0 && label_counter <= 7 ?
2054 MICROLABEL_LEVEL_NAME :
2055 label_counter >= 9 && label_counter <= 12 ?
2056 MICROLABEL_LEVEL_AUTHOR_HEAD :
2057 label_counter >= 14 && label_counter <= 21 ?
2058 MICROLABEL_LEVEL_AUTHOR :
2059 label_counter >= 23 && label_counter <= 26 ?
2060 MICROLABEL_IMPORTED_FROM_HEAD :
2061 label_counter >= 28 && label_counter <= 35 ?
2062 MICROLABEL_IMPORTED_FROM :
2063 label_counter >= 37 && label_counter <= 40 ?
2064 MICROLABEL_IMPORTED_BY_HEAD :
2065 label_counter >= 42 && label_counter <= 49 ?
2066 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2068 if (leveldir_current->imported_from == NULL &&
2069 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2070 label_state == MICROLABEL_IMPORTED_FROM))
2071 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2072 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2074 DrawPreviewLevelLabelExt(label_state);
2077 game_status = last_game_status; /* restore current game status */
2080 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2081 int graphic, int sync_frame, int mask_mode)
2083 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2085 if (mask_mode == USE_MASKING)
2086 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2088 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2091 inline void DrawGraphicAnimation(int x, int y, int graphic)
2093 int lx = LEVELX(x), ly = LEVELY(y);
2095 if (!IN_SCR_FIELD(x, y))
2098 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2099 graphic, GfxFrame[lx][ly], NO_MASKING);
2100 MarkTileDirty(x, y);
2103 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2105 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2108 void DrawLevelElementAnimation(int x, int y, int element)
2110 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2112 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2115 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2117 int sx = SCREENX(x), sy = SCREENY(y);
2119 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2122 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2125 DrawGraphicAnimation(sx, sy, graphic);
2128 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2129 DrawLevelFieldCrumbledSand(x, y);
2131 if (GFX_CRUMBLED(Feld[x][y]))
2132 DrawLevelFieldCrumbledSand(x, y);
2136 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2138 int sx = SCREENX(x), sy = SCREENY(y);
2141 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2144 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2146 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2149 DrawGraphicAnimation(sx, sy, graphic);
2151 if (GFX_CRUMBLED(element))
2152 DrawLevelFieldCrumbledSand(x, y);
2155 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2157 if (player->use_murphy)
2159 /* this works only because currently only one player can be "murphy" ... */
2160 static int last_horizontal_dir = MV_LEFT;
2161 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2163 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2164 last_horizontal_dir = move_dir;
2166 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2168 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2170 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2176 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2179 static boolean equalGraphics(int graphic1, int graphic2)
2181 struct GraphicInfo *g1 = &graphic_info[graphic1];
2182 struct GraphicInfo *g2 = &graphic_info[graphic2];
2184 return (g1->bitmap == g2->bitmap &&
2185 g1->src_x == g2->src_x &&
2186 g1->src_y == g2->src_y &&
2187 g1->anim_frames == g2->anim_frames &&
2188 g1->anim_delay == g2->anim_delay &&
2189 g1->anim_mode == g2->anim_mode);
2192 void DrawAllPlayers()
2196 for (i = 0; i < MAX_PLAYERS; i++)
2197 if (stored_player[i].active)
2198 DrawPlayer(&stored_player[i]);
2201 void DrawPlayerField(int x, int y)
2203 if (!IS_PLAYER(x, y))
2206 DrawPlayer(PLAYERINFO(x, y));
2209 void DrawPlayer(struct PlayerInfo *player)
2211 int jx = player->jx;
2212 int jy = player->jy;
2213 int move_dir = player->MovDir;
2214 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2215 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2216 int last_jx = (player->is_moving ? jx - dx : jx);
2217 int last_jy = (player->is_moving ? jy - dy : jy);
2218 int next_jx = jx + dx;
2219 int next_jy = jy + dy;
2220 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2221 boolean player_is_opaque = FALSE;
2222 int sx = SCREENX(jx), sy = SCREENY(jy);
2223 int sxx = 0, syy = 0;
2224 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2226 int action = ACTION_DEFAULT;
2227 int last_player_graphic = getPlayerGraphic(player, move_dir);
2228 int last_player_frame = player->Frame;
2231 /* GfxElement[][] is set to the element the player is digging or collecting;
2232 remove also for off-screen player if the player is not moving anymore */
2233 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2234 GfxElement[jx][jy] = EL_UNDEFINED;
2236 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2240 if (!IN_LEV_FIELD(jx, jy))
2242 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2243 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2244 printf("DrawPlayerField(): This should never happen!\n");
2249 if (element == EL_EXPLOSION)
2252 action = (player->is_pushing ? ACTION_PUSHING :
2253 player->is_digging ? ACTION_DIGGING :
2254 player->is_collecting ? ACTION_COLLECTING :
2255 player->is_moving ? ACTION_MOVING :
2256 player->is_snapping ? ACTION_SNAPPING :
2257 player->is_dropping ? ACTION_DROPPING :
2258 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2260 if (player->is_waiting)
2261 move_dir = player->dir_waiting;
2263 InitPlayerGfxAnimation(player, action, move_dir);
2265 /* ----------------------------------------------------------------------- */
2266 /* draw things in the field the player is leaving, if needed */
2267 /* ----------------------------------------------------------------------- */
2269 if (player->is_moving)
2271 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2273 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2275 if (last_element == EL_DYNAMITE_ACTIVE ||
2276 last_element == EL_EM_DYNAMITE_ACTIVE ||
2277 last_element == EL_SP_DISK_RED_ACTIVE)
2278 DrawDynamite(last_jx, last_jy);
2280 DrawLevelFieldThruMask(last_jx, last_jy);
2282 else if (last_element == EL_DYNAMITE_ACTIVE ||
2283 last_element == EL_EM_DYNAMITE_ACTIVE ||
2284 last_element == EL_SP_DISK_RED_ACTIVE)
2285 DrawDynamite(last_jx, last_jy);
2287 /* !!! this is not enough to prevent flickering of players which are
2288 moving next to each others without a free tile between them -- this
2289 can only be solved by drawing all players layer by layer (first the
2290 background, then the foreground etc.) !!! => TODO */
2291 else if (!IS_PLAYER(last_jx, last_jy))
2292 DrawLevelField(last_jx, last_jy);
2295 DrawLevelField(last_jx, last_jy);
2298 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2299 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2302 if (!IN_SCR_FIELD(sx, sy))
2305 if (setup.direct_draw)
2306 SetDrawtoField(DRAW_BUFFERED);
2308 /* ----------------------------------------------------------------------- */
2309 /* draw things behind the player, if needed */
2310 /* ----------------------------------------------------------------------- */
2313 DrawLevelElement(jx, jy, Back[jx][jy]);
2314 else if (IS_ACTIVE_BOMB(element))
2315 DrawLevelElement(jx, jy, EL_EMPTY);
2318 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2320 int old_element = GfxElement[jx][jy];
2321 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2322 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2324 if (GFX_CRUMBLED(old_element))
2325 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2327 DrawGraphic(sx, sy, old_graphic, frame);
2329 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2330 player_is_opaque = TRUE;
2334 GfxElement[jx][jy] = EL_UNDEFINED;
2336 /* make sure that pushed elements are drawn with correct frame rate */
2338 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2340 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2341 GfxFrame[jx][jy] = player->StepFrame;
2343 if (player->is_pushing && player->is_moving)
2344 GfxFrame[jx][jy] = player->StepFrame;
2347 DrawLevelField(jx, jy);
2351 /* ----------------------------------------------------------------------- */
2352 /* draw player himself */
2353 /* ----------------------------------------------------------------------- */
2355 graphic = getPlayerGraphic(player, move_dir);
2357 /* in the case of changed player action or direction, prevent the current
2358 animation frame from being restarted for identical animations */
2359 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2360 player->Frame = last_player_frame;
2362 frame = getGraphicAnimationFrame(graphic, player->Frame);
2366 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2367 sxx = player->GfxPos;
2369 syy = player->GfxPos;
2372 if (!setup.soft_scrolling && ScreenMovPos)
2375 if (player_is_opaque)
2376 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2378 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2380 if (SHIELD_ON(player))
2382 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2383 IMG_SHIELD_NORMAL_ACTIVE);
2384 int frame = getGraphicAnimationFrame(graphic, -1);
2386 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2389 /* ----------------------------------------------------------------------- */
2390 /* draw things the player is pushing, if needed */
2391 /* ----------------------------------------------------------------------- */
2394 printf("::: %d, %d [%d, %d] [%d]\n",
2395 player->is_pushing, player_is_moving, player->GfxAction,
2396 player->is_moving, player_is_moving);
2400 if (player->is_pushing && player->is_moving)
2402 int px = SCREENX(jx), py = SCREENY(jy);
2403 int pxx = (TILEX - ABS(sxx)) * dx;
2404 int pyy = (TILEY - ABS(syy)) * dy;
2405 int gfx_frame = GfxFrame[jx][jy];
2411 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2413 element = Feld[next_jx][next_jy];
2414 gfx_frame = GfxFrame[next_jx][next_jy];
2417 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2420 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2421 frame = getGraphicAnimationFrame(graphic, sync_frame);
2423 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2426 /* draw background element under pushed element (like the Sokoban field) */
2427 if (Back[next_jx][next_jy])
2428 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2430 /* masked drawing is needed for EMC style (double) movement graphics */
2431 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2435 /* ----------------------------------------------------------------------- */
2436 /* draw things in front of player (active dynamite or dynabombs) */
2437 /* ----------------------------------------------------------------------- */
2439 if (IS_ACTIVE_BOMB(element))
2441 graphic = el2img(element);
2442 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2444 if (game.emulation == EMU_SUPAPLEX)
2445 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2447 DrawGraphicThruMask(sx, sy, graphic, frame);
2450 if (player_is_moving && last_element == EL_EXPLOSION)
2452 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2453 GfxElement[last_jx][last_jy] : EL_EMPTY);
2454 int graphic = el_act2img(element, ACTION_EXPLODING);
2455 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2456 int phase = ExplodePhase[last_jx][last_jy] - 1;
2457 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2460 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2463 /* ----------------------------------------------------------------------- */
2464 /* draw elements the player is just walking/passing through/under */
2465 /* ----------------------------------------------------------------------- */
2467 if (player_is_moving)
2469 /* handle the field the player is leaving ... */
2470 if (IS_ACCESSIBLE_INSIDE(last_element))
2471 DrawLevelField(last_jx, last_jy);
2472 else if (IS_ACCESSIBLE_UNDER(last_element))
2473 DrawLevelFieldThruMask(last_jx, last_jy);
2476 /* do not redraw accessible elements if the player is just pushing them */
2477 if (!player_is_moving || !player->is_pushing)
2479 /* ... and the field the player is entering */
2480 if (IS_ACCESSIBLE_INSIDE(element))
2481 DrawLevelField(jx, jy);
2482 else if (IS_ACCESSIBLE_UNDER(element))
2483 DrawLevelFieldThruMask(jx, jy);
2486 if (setup.direct_draw)
2488 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2489 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2490 int x_size = TILEX * (1 + ABS(jx - last_jx));
2491 int y_size = TILEY * (1 + ABS(jy - last_jy));
2493 BlitBitmap(drawto_field, window,
2494 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2495 SetDrawtoField(DRAW_DIRECT);
2498 MarkTileDirty(sx, sy);
2501 /* ------------------------------------------------------------------------- */
2503 void WaitForEventToContinue()
2505 boolean still_wait = TRUE;
2507 /* simulate releasing mouse button over last gadget, if still pressed */
2509 HandleGadgets(-1, -1, 0);
2511 button_status = MB_RELEASED;
2527 case EVENT_BUTTONPRESS:
2528 case EVENT_KEYPRESS:
2532 case EVENT_KEYRELEASE:
2533 ClearPlayerAction();
2537 HandleOtherEvents(&event);
2541 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2548 /* don't eat all CPU time */
2553 #define MAX_REQUEST_LINES 13
2554 #define MAX_REQUEST_LINE_FONT1_LEN 7
2555 #define MAX_REQUEST_LINE_FONT2_LEN 10
2557 boolean Request(char *text, unsigned int req_state)
2559 int mx, my, ty, result = -1;
2560 unsigned int old_door_state;
2561 int last_game_status = game_status; /* save current game status */
2562 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2563 int font_nr = FONT_TEXT_2;
2564 int max_word_len = 0;
2567 for (text_ptr = text; *text_ptr; text_ptr++)
2569 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2571 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2573 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2575 font_nr = FONT_TEXT_1;
2577 font_nr = FONT_LEVEL_NUMBER;
2584 if (game_status == GAME_MODE_PLAYING &&
2585 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2586 BlitScreenToBitmap_EM(backbuffer);
2588 /* disable deactivated drawing when quick-loading level tape recording */
2589 if (tape.playing && tape.deactivate_display)
2590 TapeDeactivateDisplayOff(TRUE);
2592 SetMouseCursor(CURSOR_DEFAULT);
2594 #if defined(NETWORK_AVALIABLE)
2595 /* pause network game while waiting for request to answer */
2596 if (options.network &&
2597 game_status == GAME_MODE_PLAYING &&
2598 req_state & REQUEST_WAIT_FOR_INPUT)
2599 SendToServer_PausePlaying();
2602 old_door_state = GetDoorState();
2604 /* simulate releasing mouse button over last gadget, if still pressed */
2606 HandleGadgets(-1, -1, 0);
2610 if (old_door_state & DOOR_OPEN_1)
2612 CloseDoor(DOOR_CLOSE_1);
2614 /* save old door content */
2615 BlitBitmap(bitmap_db_door, bitmap_db_door,
2616 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2617 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2621 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2624 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2626 /* clear door drawing field */
2627 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2629 /* force DOOR font inside door area */
2630 game_status = GAME_MODE_PSEUDO_DOOR;
2632 /* write text for request */
2633 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2635 char text_line[max_request_line_len + 1];
2641 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2644 if (!tc || tc == ' ')
2655 strncpy(text_line, text, tl);
2658 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2659 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2660 text_line, font_nr);
2662 text += tl + (tc == ' ' ? 1 : 0);
2665 game_status = last_game_status; /* restore current game status */
2667 if (req_state & REQ_ASK)
2669 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2670 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2672 else if (req_state & REQ_CONFIRM)
2674 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2676 else if (req_state & REQ_PLAYER)
2678 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2679 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2680 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2681 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2684 /* copy request gadgets to door backbuffer */
2685 BlitBitmap(drawto, bitmap_db_door,
2686 DX, DY, DXSIZE, DYSIZE,
2687 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2689 OpenDoor(DOOR_OPEN_1);
2691 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2693 if (game_status == GAME_MODE_PLAYING)
2695 SetPanelBackground();
2696 SetDrawBackgroundMask(REDRAW_DOOR_1);
2700 SetDrawBackgroundMask(REDRAW_FIELD);
2706 if (game_status != GAME_MODE_MAIN)
2709 button_status = MB_RELEASED;
2711 request_gadget_id = -1;
2713 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2725 case EVENT_BUTTONPRESS:
2726 case EVENT_BUTTONRELEASE:
2727 case EVENT_MOTIONNOTIFY:
2729 if (event.type == EVENT_MOTIONNOTIFY)
2731 if (!PointerInWindow(window))
2732 continue; /* window and pointer are on different screens */
2737 motion_status = TRUE;
2738 mx = ((MotionEvent *) &event)->x;
2739 my = ((MotionEvent *) &event)->y;
2743 motion_status = FALSE;
2744 mx = ((ButtonEvent *) &event)->x;
2745 my = ((ButtonEvent *) &event)->y;
2746 if (event.type == EVENT_BUTTONPRESS)
2747 button_status = ((ButtonEvent *) &event)->button;
2749 button_status = MB_RELEASED;
2752 /* this sets 'request_gadget_id' */
2753 HandleGadgets(mx, my, button_status);
2755 switch (request_gadget_id)
2757 case TOOL_CTRL_ID_YES:
2760 case TOOL_CTRL_ID_NO:
2763 case TOOL_CTRL_ID_CONFIRM:
2764 result = TRUE | FALSE;
2767 case TOOL_CTRL_ID_PLAYER_1:
2770 case TOOL_CTRL_ID_PLAYER_2:
2773 case TOOL_CTRL_ID_PLAYER_3:
2776 case TOOL_CTRL_ID_PLAYER_4:
2787 case EVENT_KEYPRESS:
2788 switch (GetEventKey((KeyEvent *)&event, TRUE))
2801 if (req_state & REQ_PLAYER)
2805 case EVENT_KEYRELEASE:
2806 ClearPlayerAction();
2810 HandleOtherEvents(&event);
2814 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2816 int joy = AnyJoystick();
2818 if (joy & JOY_BUTTON_1)
2820 else if (joy & JOY_BUTTON_2)
2826 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2828 HandleGameActions();
2835 if (!PendingEvent()) /* delay only if no pending events */
2844 if (!PendingEvent()) /* delay only if no pending events */
2847 /* don't eat all CPU time */
2854 if (game_status != GAME_MODE_MAIN)
2859 if (!(req_state & REQ_STAY_OPEN))
2861 CloseDoor(DOOR_CLOSE_1);
2863 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2864 (req_state & REQ_REOPEN))
2865 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2870 if (game_status == GAME_MODE_PLAYING)
2872 SetPanelBackground();
2873 SetDrawBackgroundMask(REDRAW_DOOR_1);
2877 SetDrawBackgroundMask(REDRAW_FIELD);
2880 #if defined(NETWORK_AVALIABLE)
2881 /* continue network game after request */
2882 if (options.network &&
2883 game_status == GAME_MODE_PLAYING &&
2884 req_state & REQUEST_WAIT_FOR_INPUT)
2885 SendToServer_ContinuePlaying();
2888 /* restore deactivated drawing when quick-loading level tape recording */
2889 if (tape.playing && tape.deactivate_display)
2890 TapeDeactivateDisplayOn();
2895 unsigned int OpenDoor(unsigned int door_state)
2897 if (door_state & DOOR_COPY_BACK)
2899 if (door_state & DOOR_OPEN_1)
2900 BlitBitmap(bitmap_db_door, bitmap_db_door,
2901 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2902 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2904 if (door_state & DOOR_OPEN_2)
2905 BlitBitmap(bitmap_db_door, bitmap_db_door,
2906 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2907 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2909 door_state &= ~DOOR_COPY_BACK;
2912 return MoveDoor(door_state);
2915 unsigned int CloseDoor(unsigned int door_state)
2917 unsigned int old_door_state = GetDoorState();
2919 if (!(door_state & DOOR_NO_COPY_BACK))
2921 if (old_door_state & DOOR_OPEN_1)
2922 BlitBitmap(backbuffer, bitmap_db_door,
2923 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2925 if (old_door_state & DOOR_OPEN_2)
2926 BlitBitmap(backbuffer, bitmap_db_door,
2927 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2929 door_state &= ~DOOR_NO_COPY_BACK;
2932 return MoveDoor(door_state);
2935 unsigned int GetDoorState()
2937 return MoveDoor(DOOR_GET_STATE);
2940 unsigned int SetDoorState(unsigned int door_state)
2942 return MoveDoor(door_state | DOOR_SET_STATE);
2945 unsigned int MoveDoor(unsigned int door_state)
2947 static int door1 = DOOR_OPEN_1;
2948 static int door2 = DOOR_CLOSE_2;
2949 unsigned long door_delay = 0;
2950 unsigned long door_delay_value;
2953 if (door_1.width < 0 || door_1.width > DXSIZE)
2954 door_1.width = DXSIZE;
2955 if (door_1.height < 0 || door_1.height > DYSIZE)
2956 door_1.height = DYSIZE;
2957 if (door_2.width < 0 || door_2.width > VXSIZE)
2958 door_2.width = VXSIZE;
2959 if (door_2.height < 0 || door_2.height > VYSIZE)
2960 door_2.height = VYSIZE;
2962 if (door_state == DOOR_GET_STATE)
2963 return (door1 | door2);
2965 if (door_state & DOOR_SET_STATE)
2967 if (door_state & DOOR_ACTION_1)
2968 door1 = door_state & DOOR_ACTION_1;
2969 if (door_state & DOOR_ACTION_2)
2970 door2 = door_state & DOOR_ACTION_2;
2972 return (door1 | door2);
2975 if (!(door_state & DOOR_FORCE_REDRAW))
2977 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2978 door_state &= ~DOOR_OPEN_1;
2979 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2980 door_state &= ~DOOR_CLOSE_1;
2981 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2982 door_state &= ~DOOR_OPEN_2;
2983 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2984 door_state &= ~DOOR_CLOSE_2;
2987 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2990 if (setup.quick_doors)
2992 stepsize = 20; /* must be choosen to always draw last frame */
2993 door_delay_value = 0;
2996 if (global.autoplay_leveldir)
2998 door_state |= DOOR_NO_DELAY;
2999 door_state &= ~DOOR_CLOSE_ALL;
3002 if (door_state & DOOR_ACTION)
3004 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3005 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3006 boolean door_1_done = (!handle_door_1);
3007 boolean door_2_done = (!handle_door_2);
3008 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3009 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3010 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3011 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3012 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3013 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3014 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3015 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3016 int door_skip = max_door_size - door_size;
3017 int end = door_size;
3018 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3021 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3023 /* opening door sound has priority over simultaneously closing door */
3024 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3025 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3026 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3027 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3030 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3033 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3034 GC gc = bitmap->stored_clip_gc;
3036 if (door_state & DOOR_ACTION_1)
3038 int a = MIN(x * door_1.step_offset, end);
3039 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3040 int i = p + door_skip;
3042 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3044 BlitBitmap(bitmap_db_door, drawto,
3045 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3046 DXSIZE, DYSIZE, DX, DY);
3050 BlitBitmap(bitmap_db_door, drawto,
3051 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3052 DXSIZE, DYSIZE - p / 2, DX, DY);
3054 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3057 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3059 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3060 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3061 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3062 int dst2_x = DX, dst2_y = DY;
3063 int width = i, height = DYSIZE;
3065 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3066 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3069 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3070 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3073 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3075 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3076 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3077 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3078 int dst2_x = DX, dst2_y = DY;
3079 int width = DXSIZE, height = i;
3081 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3082 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3085 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3086 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3089 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3091 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3093 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3094 BlitBitmapMasked(bitmap, drawto,
3095 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3096 DX + DXSIZE - i, DY + j);
3097 BlitBitmapMasked(bitmap, drawto,
3098 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3099 DX + DXSIZE - i, DY + 140 + j);
3100 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3101 DY - (DOOR_GFX_PAGEY1 + j));
3102 BlitBitmapMasked(bitmap, drawto,
3103 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3105 BlitBitmapMasked(bitmap, drawto,
3106 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3109 BlitBitmapMasked(bitmap, drawto,
3110 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3112 BlitBitmapMasked(bitmap, drawto,
3113 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3115 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3116 BlitBitmapMasked(bitmap, drawto,
3117 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3118 DX + DXSIZE - i, DY + 77 + j);
3119 BlitBitmapMasked(bitmap, drawto,
3120 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3121 DX + DXSIZE - i, DY + 203 + j);
3124 redraw_mask |= REDRAW_DOOR_1;
3125 door_1_done = (a == end);
3128 if (door_state & DOOR_ACTION_2)
3130 int a = MIN(x * door_2.step_offset, door_size);
3131 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3132 int i = p + door_skip;
3134 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3136 BlitBitmap(bitmap_db_door, drawto,
3137 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3138 VXSIZE, VYSIZE, VX, VY);
3140 else if (x <= VYSIZE)
3142 BlitBitmap(bitmap_db_door, drawto,
3143 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3144 VXSIZE, VYSIZE - p / 2, VX, VY);
3146 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3149 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3151 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3152 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3153 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3154 int dst2_x = VX, dst2_y = VY;
3155 int width = i, height = VYSIZE;
3157 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3158 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3161 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3162 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3165 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3167 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3168 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3169 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3170 int dst2_x = VX, dst2_y = VY;
3171 int width = VXSIZE, height = i;
3173 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3174 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3177 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3178 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3181 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3183 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3185 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3186 BlitBitmapMasked(bitmap, drawto,
3187 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3188 VX + VXSIZE - i, VY + j);
3189 SetClipOrigin(bitmap, gc,
3190 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3191 BlitBitmapMasked(bitmap, drawto,
3192 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3195 BlitBitmapMasked(bitmap, drawto,
3196 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3197 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3198 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3199 BlitBitmapMasked(bitmap, drawto,
3200 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3202 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3205 redraw_mask |= REDRAW_DOOR_2;
3206 door_2_done = (a == VXSIZE);
3209 if (!(door_state & DOOR_NO_DELAY))
3213 if (game_status == GAME_MODE_MAIN)
3216 WaitUntilDelayReached(&door_delay, door_delay_value);
3221 if (door_state & DOOR_ACTION_1)
3222 door1 = door_state & DOOR_ACTION_1;
3223 if (door_state & DOOR_ACTION_2)
3224 door2 = door_state & DOOR_ACTION_2;
3226 return (door1 | door2);
3229 void DrawSpecialEditorDoor()
3231 /* draw bigger toolbox window */
3232 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3233 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3235 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3236 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3239 redraw_mask |= REDRAW_ALL;
3242 void UndrawSpecialEditorDoor()
3244 /* draw normal tape recorder window */
3245 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3246 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3249 redraw_mask |= REDRAW_ALL;
3253 /* ---------- new tool button stuff ---------------------------------------- */
3255 /* graphic position values for tool buttons */
3256 #define TOOL_BUTTON_YES_XPOS 2
3257 #define TOOL_BUTTON_YES_YPOS 250
3258 #define TOOL_BUTTON_YES_GFX_YPOS 0
3259 #define TOOL_BUTTON_YES_XSIZE 46
3260 #define TOOL_BUTTON_YES_YSIZE 28
3261 #define TOOL_BUTTON_NO_XPOS 52
3262 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3263 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3264 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3265 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3266 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3267 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3268 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3269 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3270 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3271 #define TOOL_BUTTON_PLAYER_XSIZE 30
3272 #define TOOL_BUTTON_PLAYER_YSIZE 30
3273 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3274 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3275 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3276 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3277 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3278 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3279 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3280 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3281 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3282 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3283 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3284 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3285 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3286 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3287 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3288 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3289 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3290 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3291 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3292 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3301 } toolbutton_info[NUM_TOOL_BUTTONS] =
3304 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3305 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3306 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3311 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3312 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3313 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3318 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3319 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3320 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3321 TOOL_CTRL_ID_CONFIRM,
3325 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3326 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3327 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3328 TOOL_CTRL_ID_PLAYER_1,
3332 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3333 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3334 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3335 TOOL_CTRL_ID_PLAYER_2,
3339 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3340 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3341 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3342 TOOL_CTRL_ID_PLAYER_3,
3346 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3347 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3348 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3349 TOOL_CTRL_ID_PLAYER_4,
3354 void CreateToolButtons()
3358 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3360 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3361 Bitmap *deco_bitmap = None;
3362 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3363 struct GadgetInfo *gi;
3364 unsigned long event_mask;
3365 int gd_xoffset, gd_yoffset;
3366 int gd_x1, gd_x2, gd_y;
3369 event_mask = GD_EVENT_RELEASED;
3371 gd_xoffset = toolbutton_info[i].xpos;
3372 gd_yoffset = toolbutton_info[i].ypos;
3373 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3374 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3375 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3377 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3379 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3381 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3382 &deco_bitmap, &deco_x, &deco_y);
3383 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3384 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3387 gi = CreateGadget(GDI_CUSTOM_ID, id,
3388 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3389 GDI_X, DX + toolbutton_info[i].x,
3390 GDI_Y, DY + toolbutton_info[i].y,
3391 GDI_WIDTH, toolbutton_info[i].width,
3392 GDI_HEIGHT, toolbutton_info[i].height,
3393 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3394 GDI_STATE, GD_BUTTON_UNPRESSED,
3395 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3396 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3397 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3398 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3399 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3400 GDI_DECORATION_SHIFTING, 1, 1,
3401 GDI_DIRECT_DRAW, FALSE,
3402 GDI_EVENT_MASK, event_mask,
3403 GDI_CALLBACK_ACTION, HandleToolButtons,
3407 Error(ERR_EXIT, "cannot create gadget");
3409 tool_gadget[id] = gi;
3413 void FreeToolButtons()
3417 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3418 FreeGadget(tool_gadget[i]);
3421 static void UnmapToolButtons()
3425 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3426 UnmapGadget(tool_gadget[i]);
3429 static void HandleToolButtons(struct GadgetInfo *gi)
3431 request_gadget_id = gi->custom_id;
3434 static struct Mapping_EM_to_RND_object
3437 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3438 boolean is_backside; /* backside of moving element */
3444 em_object_mapping_list[] =
3447 Xblank, TRUE, FALSE,
3451 Yacid_splash_eB, FALSE, FALSE,
3452 EL_ACID_SPLASH_RIGHT, -1, -1
3455 Yacid_splash_wB, FALSE, FALSE,
3456 EL_ACID_SPLASH_LEFT, -1, -1
3459 #ifdef EM_ENGINE_BAD_ROLL
3461 Xstone_force_e, FALSE, FALSE,
3462 EL_ROCK, -1, MV_BIT_RIGHT
3465 Xstone_force_w, FALSE, FALSE,
3466 EL_ROCK, -1, MV_BIT_LEFT
3469 Xnut_force_e, FALSE, FALSE,
3470 EL_NUT, -1, MV_BIT_RIGHT
3473 Xnut_force_w, FALSE, FALSE,
3474 EL_NUT, -1, MV_BIT_LEFT
3477 Xspring_force_e, FALSE, FALSE,
3478 EL_SPRING, -1, MV_BIT_RIGHT
3481 Xspring_force_w, FALSE, FALSE,
3482 EL_SPRING, -1, MV_BIT_LEFT
3485 Xemerald_force_e, FALSE, FALSE,
3486 EL_EMERALD, -1, MV_BIT_RIGHT
3489 Xemerald_force_w, FALSE, FALSE,
3490 EL_EMERALD, -1, MV_BIT_LEFT
3493 Xdiamond_force_e, FALSE, FALSE,
3494 EL_DIAMOND, -1, MV_BIT_RIGHT
3497 Xdiamond_force_w, FALSE, FALSE,
3498 EL_DIAMOND, -1, MV_BIT_LEFT
3501 Xbomb_force_e, FALSE, FALSE,
3502 EL_BOMB, -1, MV_BIT_RIGHT
3505 Xbomb_force_w, FALSE, FALSE,
3506 EL_BOMB, -1, MV_BIT_LEFT
3508 #endif /* EM_ENGINE_BAD_ROLL */
3511 Xstone, TRUE, FALSE,
3515 Xstone_pause, FALSE, FALSE,
3519 Xstone_fall, FALSE, FALSE,
3523 Ystone_s, FALSE, FALSE,
3524 EL_ROCK, ACTION_FALLING, -1
3527 Ystone_sB, FALSE, TRUE,
3528 EL_ROCK, ACTION_FALLING, -1
3531 Ystone_e, FALSE, FALSE,
3532 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3535 Ystone_eB, FALSE, TRUE,
3536 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3539 Ystone_w, FALSE, FALSE,
3540 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3543 Ystone_wB, FALSE, TRUE,
3544 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3551 Xnut_pause, FALSE, FALSE,
3555 Xnut_fall, FALSE, FALSE,
3559 Ynut_s, FALSE, FALSE,
3560 EL_NUT, ACTION_FALLING, -1
3563 Ynut_sB, FALSE, TRUE,
3564 EL_NUT, ACTION_FALLING, -1
3567 Ynut_e, FALSE, FALSE,
3568 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3571 Ynut_eB, FALSE, TRUE,
3572 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3575 Ynut_w, FALSE, FALSE,
3576 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3579 Ynut_wB, FALSE, TRUE,
3580 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3583 Xbug_n, TRUE, FALSE,
3587 Xbug_e, TRUE, FALSE,
3588 EL_BUG_RIGHT, -1, -1
3591 Xbug_s, TRUE, FALSE,
3595 Xbug_w, TRUE, FALSE,
3599 Xbug_gon, FALSE, FALSE,
3603 Xbug_goe, FALSE, FALSE,
3604 EL_BUG_RIGHT, -1, -1
3607 Xbug_gos, FALSE, FALSE,
3611 Xbug_gow, FALSE, FALSE,
3615 Ybug_n, FALSE, FALSE,
3616 EL_BUG, ACTION_MOVING, MV_BIT_UP
3619 Ybug_nB, FALSE, TRUE,
3620 EL_BUG, ACTION_MOVING, MV_BIT_UP
3623 Ybug_e, FALSE, FALSE,
3624 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3627 Ybug_eB, FALSE, TRUE,
3628 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3631 Ybug_s, FALSE, FALSE,
3632 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3635 Ybug_sB, FALSE, TRUE,
3636 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3639 Ybug_w, FALSE, FALSE,
3640 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3643 Ybug_wB, FALSE, TRUE,
3644 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3647 Ybug_w_n, FALSE, FALSE,
3648 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3651 Ybug_n_e, FALSE, FALSE,
3652 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3655 Ybug_e_s, FALSE, FALSE,
3656 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3659 Ybug_s_w, FALSE, FALSE,
3660 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3663 Ybug_e_n, FALSE, FALSE,
3664 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3667 Ybug_s_e, FALSE, FALSE,
3668 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3671 Ybug_w_s, FALSE, FALSE,
3672 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3675 Ybug_n_w, FALSE, FALSE,
3676 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3679 Ybug_stone, FALSE, FALSE,
3680 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3683 Ybug_spring, FALSE, FALSE,
3684 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3687 Xtank_n, TRUE, FALSE,
3688 EL_SPACESHIP_UP, -1, -1
3691 Xtank_e, TRUE, FALSE,
3692 EL_SPACESHIP_RIGHT, -1, -1
3695 Xtank_s, TRUE, FALSE,
3696 EL_SPACESHIP_DOWN, -1, -1
3699 Xtank_w, TRUE, FALSE,
3700 EL_SPACESHIP_LEFT, -1, -1
3703 Xtank_gon, FALSE, FALSE,
3704 EL_SPACESHIP_UP, -1, -1
3707 Xtank_goe, FALSE, FALSE,
3708 EL_SPACESHIP_RIGHT, -1, -1
3711 Xtank_gos, FALSE, FALSE,
3712 EL_SPACESHIP_DOWN, -1, -1
3715 Xtank_gow, FALSE, FALSE,
3716 EL_SPACESHIP_LEFT, -1, -1
3719 Ytank_n, FALSE, FALSE,
3720 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3723 Ytank_nB, FALSE, TRUE,
3724 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3727 Ytank_e, FALSE, FALSE,
3728 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3731 Ytank_eB, FALSE, TRUE,
3732 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3735 Ytank_s, FALSE, FALSE,
3736 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3739 Ytank_sB, FALSE, TRUE,
3740 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3743 Ytank_w, FALSE, FALSE,
3744 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3747 Ytank_wB, FALSE, TRUE,
3748 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3751 Ytank_w_n, FALSE, FALSE,
3752 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3755 Ytank_n_e, FALSE, FALSE,
3756 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3759 Ytank_e_s, FALSE, FALSE,
3760 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3763 Ytank_s_w, FALSE, FALSE,
3764 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3767 Ytank_e_n, FALSE, FALSE,
3768 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3771 Ytank_s_e, FALSE, FALSE,
3772 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3775 Ytank_w_s, FALSE, FALSE,
3776 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3779 Ytank_n_w, FALSE, FALSE,
3780 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3783 Ytank_stone, FALSE, FALSE,
3784 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3787 Ytank_spring, FALSE, FALSE,
3788 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3791 Xandroid, TRUE, FALSE,
3792 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3795 Xandroid_1_n, FALSE, FALSE,
3796 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3799 Xandroid_2_n, FALSE, FALSE,
3800 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3803 Xandroid_1_e, FALSE, FALSE,
3804 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3807 Xandroid_2_e, FALSE, FALSE,
3808 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3811 Xandroid_1_w, FALSE, FALSE,
3812 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3815 Xandroid_2_w, FALSE, FALSE,
3816 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3819 Xandroid_1_s, FALSE, FALSE,
3820 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3823 Xandroid_2_s, FALSE, FALSE,
3824 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3827 Yandroid_n, FALSE, FALSE,
3828 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3831 Yandroid_nB, FALSE, TRUE,
3832 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3835 Yandroid_ne, FALSE, FALSE,
3836 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3839 Yandroid_neB, FALSE, TRUE,
3840 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3843 Yandroid_e, FALSE, FALSE,
3844 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3847 Yandroid_eB, FALSE, TRUE,
3848 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3851 Yandroid_se, FALSE, FALSE,
3852 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3855 Yandroid_seB, FALSE, TRUE,
3856 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3859 Yandroid_s, FALSE, FALSE,
3860 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3863 Yandroid_sB, FALSE, TRUE,
3864 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3867 Yandroid_sw, FALSE, FALSE,
3868 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3871 Yandroid_swB, FALSE, TRUE,
3872 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3875 Yandroid_w, FALSE, FALSE,
3876 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3879 Yandroid_wB, FALSE, TRUE,
3880 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3883 Yandroid_nw, FALSE, FALSE,
3884 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3887 Yandroid_nwB, FALSE, TRUE,
3888 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3891 Xspring, TRUE, FALSE,
3895 Xspring_pause, FALSE, FALSE,
3899 Xspring_e, FALSE, FALSE,
3903 Xspring_w, FALSE, FALSE,
3907 Xspring_fall, FALSE, FALSE,
3911 Yspring_s, FALSE, FALSE,
3912 EL_SPRING, ACTION_FALLING, -1
3915 Yspring_sB, FALSE, TRUE,
3916 EL_SPRING, ACTION_FALLING, -1
3919 Yspring_e, FALSE, FALSE,
3920 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3923 Yspring_eB, FALSE, TRUE,
3924 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3927 Yspring_w, FALSE, FALSE,
3928 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3931 Yspring_wB, FALSE, TRUE,
3932 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3935 Yspring_kill_e, FALSE, FALSE,
3936 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3939 Yspring_kill_eB, FALSE, TRUE,
3940 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3943 Yspring_kill_w, FALSE, FALSE,
3944 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3947 Yspring_kill_wB, FALSE, TRUE,
3948 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3951 Xeater_n, TRUE, FALSE,
3952 EL_YAMYAM_UP, -1, -1
3955 Xeater_e, TRUE, FALSE,
3956 EL_YAMYAM_RIGHT, -1, -1
3959 Xeater_w, TRUE, FALSE,
3960 EL_YAMYAM_LEFT, -1, -1
3963 Xeater_s, TRUE, FALSE,
3964 EL_YAMYAM_DOWN, -1, -1
3967 Yeater_n, FALSE, FALSE,
3968 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3971 Yeater_nB, FALSE, TRUE,
3972 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3975 Yeater_e, FALSE, FALSE,
3976 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3979 Yeater_eB, FALSE, TRUE,
3980 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3983 Yeater_s, FALSE, FALSE,
3984 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3987 Yeater_sB, FALSE, TRUE,
3988 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3991 Yeater_w, FALSE, FALSE,
3992 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3995 Yeater_wB, FALSE, TRUE,
3996 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3999 Yeater_stone, FALSE, FALSE,
4000 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4003 Yeater_spring, FALSE, FALSE,
4004 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4007 Xalien, TRUE, FALSE,
4011 Xalien_pause, FALSE, FALSE,
4015 Yalien_n, FALSE, FALSE,
4016 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4019 Yalien_nB, FALSE, TRUE,
4020 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4023 Yalien_e, FALSE, FALSE,
4024 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4027 Yalien_eB, FALSE, TRUE,
4028 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4031 Yalien_s, FALSE, FALSE,
4032 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4035 Yalien_sB, FALSE, TRUE,
4036 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4039 Yalien_w, FALSE, FALSE,
4040 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4043 Yalien_wB, FALSE, TRUE,
4044 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4047 Yalien_stone, FALSE, FALSE,
4048 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4051 Yalien_spring, FALSE, FALSE,
4052 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4055 Xemerald, TRUE, FALSE,
4059 Xemerald_pause, FALSE, FALSE,
4063 Xemerald_fall, FALSE, FALSE,
4067 Xemerald_shine, FALSE, FALSE,
4068 EL_EMERALD, ACTION_TWINKLING, -1
4071 Yemerald_s, FALSE, FALSE,
4072 EL_EMERALD, ACTION_FALLING, -1
4075 Yemerald_sB, FALSE, TRUE,
4076 EL_EMERALD, ACTION_FALLING, -1
4079 Yemerald_e, FALSE, FALSE,
4080 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4083 Yemerald_eB, FALSE, TRUE,
4084 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4087 Yemerald_w, FALSE, FALSE,
4088 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4091 Yemerald_wB, FALSE, TRUE,
4092 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4095 Yemerald_eat, FALSE, FALSE,
4096 EL_EMERALD, ACTION_COLLECTING, -1
4099 Yemerald_stone, FALSE, FALSE,
4100 EL_NUT, ACTION_BREAKING, -1
4103 Xdiamond, TRUE, FALSE,
4107 Xdiamond_pause, FALSE, FALSE,
4111 Xdiamond_fall, FALSE, FALSE,
4115 Xdiamond_shine, FALSE, FALSE,
4116 EL_DIAMOND, ACTION_TWINKLING, -1
4119 Ydiamond_s, FALSE, FALSE,
4120 EL_DIAMOND, ACTION_FALLING, -1
4123 Ydiamond_sB, FALSE, TRUE,
4124 EL_DIAMOND, ACTION_FALLING, -1
4127 Ydiamond_e, FALSE, FALSE,
4128 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4131 Ydiamond_eB, FALSE, TRUE,
4132 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4135 Ydiamond_w, FALSE, FALSE,
4136 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4139 Ydiamond_wB, FALSE, TRUE,
4140 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4143 Ydiamond_eat, FALSE, FALSE,
4144 EL_DIAMOND, ACTION_COLLECTING, -1
4147 Ydiamond_stone, FALSE, FALSE,
4148 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4151 Xdrip_fall, TRUE, FALSE,
4152 EL_AMOEBA_DROP, -1, -1
4155 Xdrip_stretch, FALSE, FALSE,
4156 EL_AMOEBA_DROP, ACTION_FALLING, -1
4159 Xdrip_stretchB, FALSE, TRUE,
4160 EL_AMOEBA_DROP, ACTION_FALLING, -1
4163 Xdrip_eat, FALSE, FALSE,
4164 EL_AMOEBA_DROP, ACTION_GROWING, -1
4167 Ydrip_s1, FALSE, FALSE,
4168 EL_AMOEBA_DROP, ACTION_FALLING, -1
4171 Ydrip_s1B, FALSE, TRUE,
4172 EL_AMOEBA_DROP, ACTION_FALLING, -1
4175 Ydrip_s2, FALSE, FALSE,
4176 EL_AMOEBA_DROP, ACTION_FALLING, -1
4179 Ydrip_s2B, FALSE, TRUE,
4180 EL_AMOEBA_DROP, ACTION_FALLING, -1
4187 Xbomb_pause, FALSE, FALSE,
4191 Xbomb_fall, FALSE, FALSE,
4195 Ybomb_s, FALSE, FALSE,
4196 EL_BOMB, ACTION_FALLING, -1
4199 Ybomb_sB, FALSE, TRUE,
4200 EL_BOMB, ACTION_FALLING, -1
4203 Ybomb_e, FALSE, FALSE,
4204 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4207 Ybomb_eB, FALSE, TRUE,
4208 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4211 Ybomb_w, FALSE, FALSE,
4212 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4215 Ybomb_wB, FALSE, TRUE,
4216 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4219 Ybomb_eat, FALSE, FALSE,
4220 EL_BOMB, ACTION_ACTIVATING, -1
4223 Xballoon, TRUE, FALSE,
4227 Yballoon_n, FALSE, FALSE,
4228 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4231 Yballoon_nB, FALSE, TRUE,
4232 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4235 Yballoon_e, FALSE, FALSE,
4236 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4239 Yballoon_eB, FALSE, TRUE,
4240 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4243 Yballoon_s, FALSE, FALSE,
4244 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4247 Yballoon_sB, FALSE, TRUE,
4248 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4251 Yballoon_w, FALSE, FALSE,
4252 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4255 Yballoon_wB, FALSE, TRUE,
4256 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4259 Xgrass, TRUE, FALSE,
4260 EL_EMC_GRASS, -1, -1
4263 Ygrass_nB, FALSE, FALSE,
4264 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4267 Ygrass_eB, FALSE, FALSE,
4268 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4271 Ygrass_sB, FALSE, FALSE,
4272 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4275 Ygrass_wB, FALSE, FALSE,
4276 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4283 Ydirt_nB, FALSE, FALSE,
4284 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4287 Ydirt_eB, FALSE, FALSE,
4288 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4291 Ydirt_sB, FALSE, FALSE,
4292 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4295 Ydirt_wB, FALSE, FALSE,
4296 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4299 Xacid_ne, TRUE, FALSE,
4300 EL_ACID_POOL_TOPRIGHT, -1, -1
4303 Xacid_se, TRUE, FALSE,
4304 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4307 Xacid_s, TRUE, FALSE,
4308 EL_ACID_POOL_BOTTOM, -1, -1
4311 Xacid_sw, TRUE, FALSE,
4312 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4315 Xacid_nw, TRUE, FALSE,
4316 EL_ACID_POOL_TOPLEFT, -1, -1
4319 Xacid_1, TRUE, FALSE,
4323 Xacid_2, FALSE, FALSE,
4327 Xacid_3, FALSE, FALSE,
4331 Xacid_4, FALSE, FALSE,
4335 Xacid_5, FALSE, FALSE,
4339 Xacid_6, FALSE, FALSE,
4343 Xacid_7, FALSE, FALSE,
4347 Xacid_8, FALSE, FALSE,
4351 Xball_1, TRUE, FALSE,
4352 EL_EMC_MAGIC_BALL, -1, -1
4355 Xball_1B, FALSE, FALSE,
4356 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4359 Xball_2, FALSE, FALSE,
4360 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4363 Xball_2B, FALSE, FALSE,
4364 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4367 Yball_eat, FALSE, FALSE,
4368 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4371 Ykey_1_eat, FALSE, FALSE,
4372 EL_EM_KEY_1, ACTION_COLLECTING, -1
4375 Ykey_2_eat, FALSE, FALSE,
4376 EL_EM_KEY_2, ACTION_COLLECTING, -1
4379 Ykey_3_eat, FALSE, FALSE,
4380 EL_EM_KEY_3, ACTION_COLLECTING, -1
4383 Ykey_4_eat, FALSE, FALSE,
4384 EL_EM_KEY_4, ACTION_COLLECTING, -1
4387 Ykey_5_eat, FALSE, FALSE,
4388 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4391 Ykey_6_eat, FALSE, FALSE,
4392 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4395 Ykey_7_eat, FALSE, FALSE,
4396 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4399 Ykey_8_eat, FALSE, FALSE,
4400 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4403 Ylenses_eat, FALSE, FALSE,
4404 EL_EMC_LENSES, ACTION_COLLECTING, -1
4407 Ymagnify_eat, FALSE, FALSE,
4408 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4411 Ygrass_eat, FALSE, FALSE,
4412 EL_EMC_GRASS, ACTION_SNAPPING, -1
4415 Ydirt_eat, FALSE, FALSE,
4416 EL_SAND, ACTION_SNAPPING, -1
4419 Xgrow_ns, TRUE, FALSE,
4420 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4423 Ygrow_ns_eat, FALSE, FALSE,
4424 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4427 Xgrow_ew, TRUE, FALSE,
4428 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4431 Ygrow_ew_eat, FALSE, FALSE,
4432 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4435 Xwonderwall, TRUE, FALSE,
4436 EL_MAGIC_WALL, -1, -1
4439 XwonderwallB, FALSE, FALSE,
4440 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4443 Xamoeba_1, TRUE, FALSE,
4444 EL_AMOEBA_DRY, ACTION_OTHER, -1
4447 Xamoeba_2, FALSE, FALSE,
4448 EL_AMOEBA_DRY, ACTION_OTHER, -1
4451 Xamoeba_3, FALSE, FALSE,
4452 EL_AMOEBA_DRY, ACTION_OTHER, -1
4455 Xamoeba_4, FALSE, FALSE,
4456 EL_AMOEBA_DRY, ACTION_OTHER, -1
4459 Xamoeba_5, TRUE, FALSE,
4460 EL_AMOEBA_WET, ACTION_OTHER, -1
4463 Xamoeba_6, FALSE, FALSE,
4464 EL_AMOEBA_WET, ACTION_OTHER, -1
4467 Xamoeba_7, FALSE, FALSE,
4468 EL_AMOEBA_WET, ACTION_OTHER, -1
4471 Xamoeba_8, FALSE, FALSE,
4472 EL_AMOEBA_WET, ACTION_OTHER, -1
4475 Xdoor_1, TRUE, FALSE,
4476 EL_EM_GATE_1, -1, -1
4479 Xdoor_2, TRUE, FALSE,
4480 EL_EM_GATE_2, -1, -1
4483 Xdoor_3, TRUE, FALSE,
4484 EL_EM_GATE_3, -1, -1
4487 Xdoor_4, TRUE, FALSE,
4488 EL_EM_GATE_4, -1, -1
4491 Xdoor_5, TRUE, FALSE,
4492 EL_EMC_GATE_5, -1, -1
4495 Xdoor_6, TRUE, FALSE,
4496 EL_EMC_GATE_6, -1, -1
4499 Xdoor_7, TRUE, FALSE,
4500 EL_EMC_GATE_7, -1, -1
4503 Xdoor_8, TRUE, FALSE,
4504 EL_EMC_GATE_8, -1, -1
4507 Xkey_1, TRUE, FALSE,
4511 Xkey_2, TRUE, FALSE,
4515 Xkey_3, TRUE, FALSE,
4519 Xkey_4, TRUE, FALSE,
4523 Xkey_5, TRUE, FALSE,
4524 EL_EMC_KEY_5, -1, -1
4527 Xkey_6, TRUE, FALSE,
4528 EL_EMC_KEY_6, -1, -1
4531 Xkey_7, TRUE, FALSE,
4532 EL_EMC_KEY_7, -1, -1
4535 Xkey_8, TRUE, FALSE,
4536 EL_EMC_KEY_8, -1, -1
4539 Xwind_n, TRUE, FALSE,
4540 EL_BALLOON_SWITCH_UP, -1, -1
4543 Xwind_e, TRUE, FALSE,
4544 EL_BALLOON_SWITCH_RIGHT, -1, -1
4547 Xwind_s, TRUE, FALSE,
4548 EL_BALLOON_SWITCH_DOWN, -1, -1
4551 Xwind_w, TRUE, FALSE,
4552 EL_BALLOON_SWITCH_LEFT, -1, -1
4555 Xwind_nesw, TRUE, FALSE,
4556 EL_BALLOON_SWITCH_ANY, -1, -1
4559 Xwind_stop, TRUE, FALSE,
4560 EL_BALLOON_SWITCH_NONE, -1, -1
4564 EL_EM_EXIT_CLOSED, -1, -1
4567 Xexit_1, TRUE, FALSE,
4568 EL_EM_EXIT_OPEN, -1, -1
4571 Xexit_2, FALSE, FALSE,
4572 EL_EM_EXIT_OPEN, -1, -1
4575 Xexit_3, FALSE, FALSE,
4576 EL_EM_EXIT_OPEN, -1, -1
4579 Xdynamite, TRUE, FALSE,
4580 EL_EM_DYNAMITE, -1, -1
4583 Ydynamite_eat, FALSE, FALSE,
4584 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4587 Xdynamite_1, TRUE, FALSE,
4588 EL_EM_DYNAMITE_ACTIVE, -1, -1
4591 Xdynamite_2, FALSE, FALSE,
4592 EL_EM_DYNAMITE_ACTIVE, -1, -1
4595 Xdynamite_3, FALSE, FALSE,
4596 EL_EM_DYNAMITE_ACTIVE, -1, -1
4599 Xdynamite_4, FALSE, FALSE,
4600 EL_EM_DYNAMITE_ACTIVE, -1, -1
4603 Xbumper, TRUE, FALSE,
4604 EL_EMC_SPRING_BUMPER, -1, -1
4607 XbumperB, FALSE, FALSE,
4608 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4611 Xwheel, TRUE, FALSE,
4612 EL_ROBOT_WHEEL, -1, -1
4615 XwheelB, FALSE, FALSE,
4616 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4619 Xswitch, TRUE, FALSE,
4620 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4623 XswitchB, FALSE, FALSE,
4624 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4628 EL_QUICKSAND_EMPTY, -1, -1
4631 Xsand_stone, TRUE, FALSE,
4632 EL_QUICKSAND_FULL, -1, -1
4635 Xsand_stonein_1, FALSE, TRUE,
4636 EL_ROCK, ACTION_FILLING, -1
4639 Xsand_stonein_2, FALSE, TRUE,
4640 EL_ROCK, ACTION_FILLING, -1
4643 Xsand_stonein_3, FALSE, TRUE,
4644 EL_ROCK, ACTION_FILLING, -1
4647 Xsand_stonein_4, FALSE, TRUE,
4648 EL_ROCK, ACTION_FILLING, -1
4651 Xsand_stonesand_1, FALSE, FALSE,
4652 EL_QUICKSAND_FULL, -1, -1
4655 Xsand_stonesand_2, FALSE, FALSE,
4656 EL_QUICKSAND_FULL, -1, -1
4659 Xsand_stonesand_3, FALSE, FALSE,
4660 EL_QUICKSAND_FULL, -1, -1
4663 Xsand_stonesand_4, FALSE, FALSE,
4664 EL_QUICKSAND_FULL, -1, -1
4667 Xsand_stoneout_1, FALSE, FALSE,
4668 EL_ROCK, ACTION_EMPTYING, -1
4671 Xsand_stoneout_2, FALSE, FALSE,
4672 EL_ROCK, ACTION_EMPTYING, -1
4675 Xsand_sandstone_1, FALSE, FALSE,
4676 EL_QUICKSAND_FULL, -1, -1
4679 Xsand_sandstone_2, FALSE, FALSE,
4680 EL_QUICKSAND_FULL, -1, -1
4683 Xsand_sandstone_3, FALSE, FALSE,
4684 EL_QUICKSAND_FULL, -1, -1
4687 Xsand_sandstone_4, FALSE, FALSE,
4688 EL_QUICKSAND_FULL, -1, -1
4691 Xplant, TRUE, FALSE,
4692 EL_EMC_PLANT, -1, -1
4695 Yplant, FALSE, FALSE,
4696 EL_EMC_PLANT, -1, -1
4699 Xlenses, TRUE, FALSE,
4700 EL_EMC_LENSES, -1, -1
4703 Xmagnify, TRUE, FALSE,
4704 EL_EMC_MAGNIFIER, -1, -1
4707 Xdripper, TRUE, FALSE,
4708 EL_EMC_DRIPPER, -1, -1
4711 XdripperB, FALSE, FALSE,
4712 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4715 Xfake_blank, TRUE, FALSE,
4716 EL_INVISIBLE_WALL, -1, -1
4719 Xfake_blankB, FALSE, FALSE,
4720 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4723 Xfake_grass, TRUE, FALSE,
4724 EL_EMC_FAKE_GRASS, -1, -1
4727 Xfake_grassB, FALSE, FALSE,
4728 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4731 Xfake_door_1, TRUE, FALSE,
4732 EL_EM_GATE_1_GRAY, -1, -1
4735 Xfake_door_2, TRUE, FALSE,
4736 EL_EM_GATE_2_GRAY, -1, -1
4739 Xfake_door_3, TRUE, FALSE,
4740 EL_EM_GATE_3_GRAY, -1, -1
4743 Xfake_door_4, TRUE, FALSE,
4744 EL_EM_GATE_4_GRAY, -1, -1
4747 Xfake_door_5, TRUE, FALSE,
4748 EL_EMC_GATE_5_GRAY, -1, -1
4751 Xfake_door_6, TRUE, FALSE,
4752 EL_EMC_GATE_6_GRAY, -1, -1
4755 Xfake_door_7, TRUE, FALSE,
4756 EL_EMC_GATE_7_GRAY, -1, -1
4759 Xfake_door_8, TRUE, FALSE,
4760 EL_EMC_GATE_8_GRAY, -1, -1
4763 Xfake_acid_1, TRUE, FALSE,
4764 EL_EMC_FAKE_ACID, -1, -1
4767 Xfake_acid_2, FALSE, FALSE,
4768 EL_EMC_FAKE_ACID, -1, -1
4771 Xfake_acid_3, FALSE, FALSE,
4772 EL_EMC_FAKE_ACID, -1, -1
4775 Xfake_acid_4, FALSE, FALSE,
4776 EL_EMC_FAKE_ACID, -1, -1
4779 Xfake_acid_5, FALSE, FALSE,
4780 EL_EMC_FAKE_ACID, -1, -1
4783 Xfake_acid_6, FALSE, FALSE,
4784 EL_EMC_FAKE_ACID, -1, -1
4787 Xfake_acid_7, FALSE, FALSE,
4788 EL_EMC_FAKE_ACID, -1, -1
4791 Xfake_acid_8, FALSE, FALSE,
4792 EL_EMC_FAKE_ACID, -1, -1
4795 Xsteel_1, TRUE, FALSE,
4796 EL_STEELWALL, -1, -1
4799 Xsteel_2, TRUE, FALSE,
4800 EL_EMC_STEELWALL_2, -1, -1
4803 Xsteel_3, TRUE, FALSE,
4804 EL_EMC_STEELWALL_3, -1, -1
4807 Xsteel_4, TRUE, FALSE,
4808 EL_EMC_STEELWALL_4, -1, -1
4811 Xwall_1, TRUE, FALSE,
4815 Xwall_2, TRUE, FALSE,
4816 EL_EMC_WALL_14, -1, -1
4819 Xwall_3, TRUE, FALSE,
4820 EL_EMC_WALL_15, -1, -1
4823 Xwall_4, TRUE, FALSE,
4824 EL_EMC_WALL_16, -1, -1
4827 Xround_wall_1, TRUE, FALSE,
4828 EL_WALL_SLIPPERY, -1, -1
4831 Xround_wall_2, TRUE, FALSE,
4832 EL_EMC_WALL_SLIPPERY_2, -1, -1
4835 Xround_wall_3, TRUE, FALSE,
4836 EL_EMC_WALL_SLIPPERY_3, -1, -1
4839 Xround_wall_4, TRUE, FALSE,
4840 EL_EMC_WALL_SLIPPERY_4, -1, -1
4843 Xdecor_1, TRUE, FALSE,
4844 EL_EMC_WALL_8, -1, -1
4847 Xdecor_2, TRUE, FALSE,
4848 EL_EMC_WALL_6, -1, -1
4851 Xdecor_3, TRUE, FALSE,
4852 EL_EMC_WALL_4, -1, -1
4855 Xdecor_4, TRUE, FALSE,
4856 EL_EMC_WALL_7, -1, -1
4859 Xdecor_5, TRUE, FALSE,
4860 EL_EMC_WALL_5, -1, -1
4863 Xdecor_6, TRUE, FALSE,
4864 EL_EMC_WALL_9, -1, -1
4867 Xdecor_7, TRUE, FALSE,
4868 EL_EMC_WALL_10, -1, -1
4871 Xdecor_8, TRUE, FALSE,
4872 EL_EMC_WALL_1, -1, -1
4875 Xdecor_9, TRUE, FALSE,
4876 EL_EMC_WALL_2, -1, -1
4879 Xdecor_10, TRUE, FALSE,
4880 EL_EMC_WALL_3, -1, -1
4883 Xdecor_11, TRUE, FALSE,
4884 EL_EMC_WALL_11, -1, -1
4887 Xdecor_12, TRUE, FALSE,
4888 EL_EMC_WALL_12, -1, -1
4891 Xalpha_0, TRUE, FALSE,
4892 EL_CHAR('0'), -1, -1
4895 Xalpha_1, TRUE, FALSE,
4896 EL_CHAR('1'), -1, -1
4899 Xalpha_2, TRUE, FALSE,
4900 EL_CHAR('2'), -1, -1
4903 Xalpha_3, TRUE, FALSE,
4904 EL_CHAR('3'), -1, -1
4907 Xalpha_4, TRUE, FALSE,
4908 EL_CHAR('4'), -1, -1
4911 Xalpha_5, TRUE, FALSE,
4912 EL_CHAR('5'), -1, -1
4915 Xalpha_6, TRUE, FALSE,
4916 EL_CHAR('6'), -1, -1
4919 Xalpha_7, TRUE, FALSE,
4920 EL_CHAR('7'), -1, -1
4923 Xalpha_8, TRUE, FALSE,
4924 EL_CHAR('8'), -1, -1
4927 Xalpha_9, TRUE, FALSE,
4928 EL_CHAR('9'), -1, -1
4931 Xalpha_excla, TRUE, FALSE,
4932 EL_CHAR('!'), -1, -1
4935 Xalpha_quote, TRUE, FALSE,
4936 EL_CHAR('"'), -1, -1
4939 Xalpha_comma, TRUE, FALSE,
4940 EL_CHAR(','), -1, -1
4943 Xalpha_minus, TRUE, FALSE,
4944 EL_CHAR('-'), -1, -1
4947 Xalpha_perio, TRUE, FALSE,
4948 EL_CHAR('.'), -1, -1
4951 Xalpha_colon, TRUE, FALSE,
4952 EL_CHAR(':'), -1, -1
4955 Xalpha_quest, TRUE, FALSE,
4956 EL_CHAR('?'), -1, -1
4959 Xalpha_a, TRUE, FALSE,
4960 EL_CHAR('A'), -1, -1
4963 Xalpha_b, TRUE, FALSE,
4964 EL_CHAR('B'), -1, -1
4967 Xalpha_c, TRUE, FALSE,
4968 EL_CHAR('C'), -1, -1
4971 Xalpha_d, TRUE, FALSE,
4972 EL_CHAR('D'), -1, -1
4975 Xalpha_e, TRUE, FALSE,
4976 EL_CHAR('E'), -1, -1
4979 Xalpha_f, TRUE, FALSE,
4980 EL_CHAR('F'), -1, -1
4983 Xalpha_g, TRUE, FALSE,
4984 EL_CHAR('G'), -1, -1
4987 Xalpha_h, TRUE, FALSE,
4988 EL_CHAR('H'), -1, -1
4991 Xalpha_i, TRUE, FALSE,
4992 EL_CHAR('I'), -1, -1
4995 Xalpha_j, TRUE, FALSE,
4996 EL_CHAR('J'), -1, -1
4999 Xalpha_k, TRUE, FALSE,
5000 EL_CHAR('K'), -1, -1
5003 Xalpha_l, TRUE, FALSE,
5004 EL_CHAR('L'), -1, -1
5007 Xalpha_m, TRUE, FALSE,
5008 EL_CHAR('M'), -1, -1
5011 Xalpha_n, TRUE, FALSE,
5012 EL_CHAR('N'), -1, -1
5015 Xalpha_o, TRUE, FALSE,
5016 EL_CHAR('O'), -1, -1
5019 Xalpha_p, TRUE, FALSE,
5020 EL_CHAR('P'), -1, -1
5023 Xalpha_q, TRUE, FALSE,
5024 EL_CHAR('Q'), -1, -1
5027 Xalpha_r, TRUE, FALSE,
5028 EL_CHAR('R'), -1, -1
5031 Xalpha_s, TRUE, FALSE,
5032 EL_CHAR('S'), -1, -1
5035 Xalpha_t, TRUE, FALSE,
5036 EL_CHAR('T'), -1, -1
5039 Xalpha_u, TRUE, FALSE,
5040 EL_CHAR('U'), -1, -1
5043 Xalpha_v, TRUE, FALSE,
5044 EL_CHAR('V'), -1, -1
5047 Xalpha_w, TRUE, FALSE,
5048 EL_CHAR('W'), -1, -1
5051 Xalpha_x, TRUE, FALSE,
5052 EL_CHAR('X'), -1, -1
5055 Xalpha_y, TRUE, FALSE,
5056 EL_CHAR('Y'), -1, -1
5059 Xalpha_z, TRUE, FALSE,
5060 EL_CHAR('Z'), -1, -1
5063 Xalpha_arrow_e, TRUE, FALSE,
5064 EL_CHAR('>'), -1, -1
5067 Xalpha_arrow_w, TRUE, FALSE,
5068 EL_CHAR('<'), -1, -1
5071 Xalpha_copyr, TRUE, FALSE,
5072 EL_CHAR('©'), -1, -1
5076 Xboom_bug, FALSE, FALSE,
5077 EL_BUG, ACTION_EXPLODING, -1
5080 Xboom_bomb, FALSE, FALSE,
5081 EL_BOMB, ACTION_EXPLODING, -1
5084 Xboom_android, FALSE, FALSE,
5085 EL_EMC_ANDROID, ACTION_OTHER, -1
5088 Xboom_1, FALSE, FALSE,
5089 EL_DEFAULT, ACTION_EXPLODING, -1
5092 Xboom_2, FALSE, FALSE,
5093 EL_DEFAULT, ACTION_EXPLODING, -1
5096 Znormal, FALSE, FALSE,
5100 Zdynamite, FALSE, FALSE,
5104 Zplayer, FALSE, FALSE,
5108 ZBORDER, FALSE, FALSE,
5118 static struct Mapping_EM_to_RND_player
5127 em_player_mapping_list[] =
5131 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5135 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5139 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5143 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5147 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5151 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5155 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5159 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5163 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5167 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5171 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5175 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5179 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5183 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5187 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5191 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5195 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5199 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5203 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5207 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5211 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5215 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5219 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5223 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5227 EL_PLAYER_1, ACTION_DEFAULT, -1,
5231 EL_PLAYER_2, ACTION_DEFAULT, -1,
5235 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5239 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5243 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5247 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5251 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5255 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5259 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5263 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5267 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5271 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5275 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5279 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5283 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5287 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5291 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5295 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5299 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5303 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5307 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5311 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5315 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5319 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5323 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5327 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5331 EL_PLAYER_3, ACTION_DEFAULT, -1,
5335 EL_PLAYER_4, ACTION_DEFAULT, -1,
5344 int map_element_RND_to_EM(int element_rnd)
5346 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5347 static boolean mapping_initialized = FALSE;
5349 if (!mapping_initialized)
5353 /* return "Xalpha_quest" for all undefined elements in mapping array */
5354 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5355 mapping_RND_to_EM[i] = Xalpha_quest;
5357 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5358 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5359 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5360 em_object_mapping_list[i].element_em;
5362 mapping_initialized = TRUE;
5365 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5366 return mapping_RND_to_EM[element_rnd];
5368 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5373 int map_element_EM_to_RND(int element_em)
5375 static unsigned short mapping_EM_to_RND[TILE_MAX];
5376 static boolean mapping_initialized = FALSE;
5378 if (!mapping_initialized)
5382 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5383 for (i = 0; i < TILE_MAX; i++)
5384 mapping_EM_to_RND[i] = EL_UNKNOWN;
5386 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5387 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5388 em_object_mapping_list[i].element_rnd;
5390 mapping_initialized = TRUE;
5393 if (element_em >= 0 && element_em < TILE_MAX)
5394 return mapping_EM_to_RND[element_em];
5396 Error(ERR_WARN, "invalid EM level element %d", element_em);
5401 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5403 struct LevelInfo_EM *level_em = level->native_em_level;
5404 struct LEVEL *lev = level_em->lev;
5407 for (i = 0; i < TILE_MAX; i++)
5408 lev->android_array[i] = Xblank;
5410 for (i = 0; i < level->num_android_clone_elements; i++)
5412 int element_rnd = level->android_clone_element[i];
5413 int element_em = map_element_RND_to_EM(element_rnd);
5415 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5416 if (em_object_mapping_list[j].element_rnd == element_rnd)
5417 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5421 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5423 struct LevelInfo_EM *level_em = level->native_em_level;
5424 struct LEVEL *lev = level_em->lev;
5427 level->num_android_clone_elements = 0;
5429 for (i = 0; i < TILE_MAX; i++)
5431 int element_em = lev->android_array[i];
5433 boolean element_found = FALSE;
5435 if (element_em == Xblank)
5438 element_rnd = map_element_EM_to_RND(element_em);
5440 for (j = 0; j < level->num_android_clone_elements; j++)
5441 if (level->android_clone_element[j] == element_rnd)
5442 element_found = TRUE;
5446 level->android_clone_element[level->num_android_clone_elements++] =
5449 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5454 if (level->num_android_clone_elements == 0)
5456 level->num_android_clone_elements = 1;
5457 level->android_clone_element[0] = EL_EMPTY;
5461 int map_direction_RND_to_EM(int direction)
5463 return (direction == MV_UP ? 0 :
5464 direction == MV_RIGHT ? 1 :
5465 direction == MV_DOWN ? 2 :
5466 direction == MV_LEFT ? 3 :
5470 int map_direction_EM_to_RND(int direction)
5472 return (direction == 0 ? MV_UP :
5473 direction == 1 ? MV_RIGHT :
5474 direction == 2 ? MV_DOWN :
5475 direction == 3 ? MV_LEFT :
5479 int get_next_element(int element)
5483 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5484 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5485 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5486 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5487 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5488 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5489 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5490 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5491 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5492 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5493 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5495 default: return element;
5500 int el_act_dir2img(int element, int action, int direction)
5502 element = GFX_ELEMENT(element);
5504 if (direction == MV_NONE)
5505 return element_info[element].graphic[action];
5507 direction = MV_DIR_TO_BIT(direction);
5509 return element_info[element].direction_graphic[action][direction];
5512 int el_act_dir2img(int element, int action, int direction)
5514 element = GFX_ELEMENT(element);
5515 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5517 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5518 return element_info[element].direction_graphic[action][direction];
5523 static int el_act_dir2crm(int element, int action, int direction)
5525 element = GFX_ELEMENT(element);
5527 if (direction == MV_NONE)
5528 return element_info[element].crumbled[action];
5530 direction = MV_DIR_TO_BIT(direction);
5532 return element_info[element].direction_crumbled[action][direction];
5535 static int el_act_dir2crm(int element, int action, int direction)
5537 element = GFX_ELEMENT(element);
5538 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5540 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5541 return element_info[element].direction_crumbled[action][direction];
5545 int el_act2img(int element, int action)
5547 element = GFX_ELEMENT(element);
5549 return element_info[element].graphic[action];
5552 int el_act2crm(int element, int action)
5554 element = GFX_ELEMENT(element);
5556 return element_info[element].crumbled[action];
5559 int el_dir2img(int element, int direction)
5561 element = GFX_ELEMENT(element);
5563 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5566 int el2baseimg(int element)
5568 return element_info[element].graphic[ACTION_DEFAULT];
5571 int el2img(int element)
5573 element = GFX_ELEMENT(element);
5575 return element_info[element].graphic[ACTION_DEFAULT];
5578 int el2edimg(int element)
5580 element = GFX_ELEMENT(element);
5582 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5585 int el2preimg(int element)
5587 element = GFX_ELEMENT(element);
5589 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5592 int font2baseimg(int font_nr)
5594 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5597 int getBeltNrFromBeltElement(int element)
5599 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5600 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5601 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5604 int getBeltNrFromBeltActiveElement(int element)
5606 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5607 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5608 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5611 int getBeltNrFromBeltSwitchElement(int element)
5613 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5614 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5615 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5618 int getBeltDirNrFromBeltElement(int element)
5620 static int belt_base_element[4] =
5622 EL_CONVEYOR_BELT_1_LEFT,
5623 EL_CONVEYOR_BELT_2_LEFT,
5624 EL_CONVEYOR_BELT_3_LEFT,
5625 EL_CONVEYOR_BELT_4_LEFT
5628 int belt_nr = getBeltNrFromBeltElement(element);
5629 int belt_dir_nr = element - belt_base_element[belt_nr];
5631 return (belt_dir_nr % 3);
5634 int getBeltDirNrFromBeltSwitchElement(int element)
5636 static int belt_base_element[4] =
5638 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5639 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5640 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5641 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5644 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5645 int belt_dir_nr = element - belt_base_element[belt_nr];
5647 return (belt_dir_nr % 3);
5650 int getBeltDirFromBeltElement(int element)
5652 static int belt_move_dir[3] =
5659 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5661 return belt_move_dir[belt_dir_nr];
5664 int getBeltDirFromBeltSwitchElement(int element)
5666 static int belt_move_dir[3] =
5673 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5675 return belt_move_dir[belt_dir_nr];
5678 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5680 static int belt_base_element[4] =
5682 EL_CONVEYOR_BELT_1_LEFT,
5683 EL_CONVEYOR_BELT_2_LEFT,
5684 EL_CONVEYOR_BELT_3_LEFT,
5685 EL_CONVEYOR_BELT_4_LEFT
5687 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5689 return belt_base_element[belt_nr] + belt_dir_nr;
5692 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5694 static int belt_base_element[4] =
5696 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5697 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5698 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5699 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5701 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5703 return belt_base_element[belt_nr] + belt_dir_nr;
5706 int getNumActivePlayers_EM()
5708 int num_players = 0;
5714 for (i = 0; i < MAX_PLAYERS; i++)
5715 if (tape.player_participates[i])
5721 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5723 int game_frame_delay_value;
5725 game_frame_delay_value =
5726 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5727 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5730 if (tape.playing && tape.warp_forward && !tape.pausing)
5731 game_frame_delay_value = 0;
5733 return game_frame_delay_value;
5736 unsigned int InitRND(long seed)
5738 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5739 return InitEngineRandom_EM(seed);
5741 return InitEngineRandom_RND(seed);
5745 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5746 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5749 void ResetGfxAnimation_EM(int x, int y, int tile)
5754 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5755 Bitmap **src_bitmap, int *src_x, int *src_y,
5758 int element = object_mapping[tile].element_rnd;
5759 int action = object_mapping[tile].action;
5760 int direction = object_mapping[tile].direction;
5761 boolean is_backside = object_mapping[tile].is_backside;
5762 boolean action_removing = (action == ACTION_DIGGING ||
5763 action == ACTION_SNAPPING ||
5764 action == ACTION_COLLECTING);
5765 int effective_element = (frame_em > 0 ? element :
5766 is_backside ? EL_EMPTY :
5767 action_removing ? EL_EMPTY :
5769 int graphic = (direction == MV_NONE ?
5770 el_act2img(effective_element, action) :
5771 el_act_dir2img(effective_element, action, direction));
5772 struct GraphicInfo *g = &graphic_info[graphic];
5775 if (graphic_info[graphic].anim_global_sync)
5776 sync_frame = FrameCounter;
5778 sync_frame = 7 - frame_em;
5780 SetRandomAnimationValue(x, y);
5782 int frame = getAnimationFrame(g->anim_frames,
5785 g->anim_start_frame,
5788 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5791 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
5792 Bitmap **src_bitmap, int *src_x, int *src_y)
5794 int element = player_mapping[player_nr][anim].element_rnd;
5795 int action = player_mapping[player_nr][anim].action;
5796 int direction = player_mapping[player_nr][anim].direction;
5797 int graphic = (direction == MV_NONE ?
5798 el_act2img(element, action) :
5799 el_act_dir2img(element, action, direction));
5800 struct GraphicInfo *g = &graphic_info[graphic];
5803 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
5805 stored_player[player_nr].StepFrame = 7 - frame_em;
5807 sync_frame = stored_player[player_nr].Frame;
5810 printf("::: %d: %d, %d [%d]\n",
5812 stored_player[player_nr].Frame,
5813 stored_player[player_nr].StepFrame,
5817 int frame = getAnimationFrame(g->anim_frames,
5820 g->anim_start_frame,
5823 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5826 void InitGraphicInfo_EM(void)
5829 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5830 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5835 int num_em_gfx_errors = 0;
5837 if (graphic_info_em_object[0][0].bitmap == NULL)
5839 /* EM graphics not yet initialized in em_open_all() */
5844 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5847 /* always start with reliable default values */
5848 for (i = 0; i < TILE_MAX; i++)
5850 object_mapping[i].element_rnd = EL_UNKNOWN;
5851 object_mapping[i].is_backside = FALSE;
5852 object_mapping[i].action = ACTION_DEFAULT;
5853 object_mapping[i].direction = MV_NONE;
5856 /* always start with reliable default values */
5857 for (p = 0; p < MAX_PLAYERS; p++)
5859 for (i = 0; i < SPR_MAX; i++)
5861 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5862 player_mapping[p][i].action = ACTION_DEFAULT;
5863 player_mapping[p][i].direction = MV_NONE;
5867 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5869 int e = em_object_mapping_list[i].element_em;
5871 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5872 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5874 if (em_object_mapping_list[i].action != -1)
5875 object_mapping[e].action = em_object_mapping_list[i].action;
5877 if (em_object_mapping_list[i].direction != -1)
5878 object_mapping[e].direction =
5879 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5882 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5884 int a = em_player_mapping_list[i].action_em;
5885 int p = em_player_mapping_list[i].player_nr;
5887 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5889 if (em_player_mapping_list[i].action != -1)
5890 player_mapping[p][a].action = em_player_mapping_list[i].action;
5892 if (em_player_mapping_list[i].direction != -1)
5893 player_mapping[p][a].direction =
5894 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5897 for (i = 0; i < TILE_MAX; i++)
5899 int element = object_mapping[i].element_rnd;
5900 int action = object_mapping[i].action;
5901 int direction = object_mapping[i].direction;
5902 boolean is_backside = object_mapping[i].is_backside;
5903 boolean action_removing = (action == ACTION_DIGGING ||
5904 action == ACTION_SNAPPING ||
5905 action == ACTION_COLLECTING);
5906 boolean action_exploding = ((action == ACTION_EXPLODING ||
5907 action == ACTION_SMASHED_BY_ROCK ||
5908 action == ACTION_SMASHED_BY_SPRING) &&
5909 element != EL_DIAMOND);
5910 boolean action_active = (action == ACTION_ACTIVE);
5911 boolean action_other = (action == ACTION_OTHER);
5913 for (j = 0; j < 8; j++)
5915 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5916 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5918 i == Xdrip_stretch ? element :
5919 i == Xdrip_stretchB ? element :
5920 i == Ydrip_s1 ? element :
5921 i == Ydrip_s1B ? element :
5922 i == Xball_1B ? element :
5923 i == Xball_2 ? element :
5924 i == Xball_2B ? element :
5925 i == Yball_eat ? element :
5926 i == Ykey_1_eat ? element :
5927 i == Ykey_2_eat ? element :
5928 i == Ykey_3_eat ? element :
5929 i == Ykey_4_eat ? element :
5930 i == Ykey_5_eat ? element :
5931 i == Ykey_6_eat ? element :
5932 i == Ykey_7_eat ? element :
5933 i == Ykey_8_eat ? element :
5934 i == Ylenses_eat ? element :
5935 i == Ymagnify_eat ? element :
5936 i == Ygrass_eat ? element :
5937 i == Ydirt_eat ? element :
5938 i == Yemerald_stone ? EL_EMERALD :
5939 i == Ydiamond_stone ? EL_ROCK :
5940 i == Xsand_stonein_1 ? element :
5941 i == Xsand_stonein_2 ? element :
5942 i == Xsand_stonein_3 ? element :
5943 i == Xsand_stonein_4 ? element :
5944 is_backside ? EL_EMPTY :
5945 action_removing ? EL_EMPTY :
5947 int effective_action = (j < 7 ? action :
5948 i == Xdrip_stretch ? action :
5949 i == Xdrip_stretchB ? action :
5950 i == Ydrip_s1 ? action :
5951 i == Ydrip_s1B ? action :
5952 i == Xball_1B ? action :
5953 i == Xball_2 ? action :
5954 i == Xball_2B ? action :
5955 i == Yball_eat ? action :
5956 i == Ykey_1_eat ? action :
5957 i == Ykey_2_eat ? action :
5958 i == Ykey_3_eat ? action :
5959 i == Ykey_4_eat ? action :
5960 i == Ykey_5_eat ? action :
5961 i == Ykey_6_eat ? action :
5962 i == Ykey_7_eat ? action :
5963 i == Ykey_8_eat ? action :
5964 i == Ylenses_eat ? action :
5965 i == Ymagnify_eat ? action :
5966 i == Ygrass_eat ? action :
5967 i == Ydirt_eat ? action :
5968 i == Xsand_stonein_1 ? action :
5969 i == Xsand_stonein_2 ? action :
5970 i == Xsand_stonein_3 ? action :
5971 i == Xsand_stonein_4 ? action :
5972 i == Xsand_stoneout_1 ? action :
5973 i == Xsand_stoneout_2 ? action :
5974 i == Xboom_android ? ACTION_EXPLODING :
5975 action_exploding ? ACTION_EXPLODING :
5976 action_active ? action :
5977 action_other ? action :
5979 int graphic = (el_act_dir2img(effective_element, effective_action,
5981 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5983 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5984 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5985 boolean has_action_graphics = (graphic != base_graphic);
5986 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5987 struct GraphicInfo *g = &graphic_info[graphic];
5988 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5991 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5992 boolean special_animation = (action != ACTION_DEFAULT &&
5993 g->anim_frames == 3 &&
5994 g->anim_delay == 2 &&
5995 g->anim_mode & ANIM_LINEAR);
5996 int sync_frame = (i == Xdrip_stretch ? 7 :
5997 i == Xdrip_stretchB ? 7 :
5998 i == Ydrip_s2 ? j + 8 :
5999 i == Ydrip_s2B ? j + 8 :
6008 i == Xfake_acid_1 ? 0 :
6009 i == Xfake_acid_2 ? 10 :
6010 i == Xfake_acid_3 ? 20 :
6011 i == Xfake_acid_4 ? 30 :
6012 i == Xfake_acid_5 ? 40 :
6013 i == Xfake_acid_6 ? 50 :
6014 i == Xfake_acid_7 ? 60 :
6015 i == Xfake_acid_8 ? 70 :
6017 i == Xball_2B ? j + 8 :
6018 i == Yball_eat ? j + 1 :
6019 i == Ykey_1_eat ? j + 1 :
6020 i == Ykey_2_eat ? j + 1 :
6021 i == Ykey_3_eat ? j + 1 :
6022 i == Ykey_4_eat ? j + 1 :
6023 i == Ykey_5_eat ? j + 1 :
6024 i == Ykey_6_eat ? j + 1 :
6025 i == Ykey_7_eat ? j + 1 :
6026 i == Ykey_8_eat ? j + 1 :
6027 i == Ylenses_eat ? j + 1 :
6028 i == Ymagnify_eat ? j + 1 :
6029 i == Ygrass_eat ? j + 1 :
6030 i == Ydirt_eat ? j + 1 :
6031 i == Xamoeba_1 ? 0 :
6032 i == Xamoeba_2 ? 1 :
6033 i == Xamoeba_3 ? 2 :
6034 i == Xamoeba_4 ? 3 :
6035 i == Xamoeba_5 ? 0 :
6036 i == Xamoeba_6 ? 1 :
6037 i == Xamoeba_7 ? 2 :
6038 i == Xamoeba_8 ? 3 :
6039 i == Xexit_2 ? j + 8 :
6040 i == Xexit_3 ? j + 16 :
6041 i == Xdynamite_1 ? 0 :
6042 i == Xdynamite_2 ? 8 :
6043 i == Xdynamite_3 ? 16 :
6044 i == Xdynamite_4 ? 24 :
6045 i == Xsand_stonein_1 ? j + 1 :
6046 i == Xsand_stonein_2 ? j + 9 :
6047 i == Xsand_stonein_3 ? j + 17 :
6048 i == Xsand_stonein_4 ? j + 25 :
6049 i == Xsand_stoneout_1 && j == 0 ? 0 :
6050 i == Xsand_stoneout_1 && j == 1 ? 0 :
6051 i == Xsand_stoneout_1 && j == 2 ? 1 :
6052 i == Xsand_stoneout_1 && j == 3 ? 2 :
6053 i == Xsand_stoneout_1 && j == 4 ? 2 :
6054 i == Xsand_stoneout_1 && j == 5 ? 3 :
6055 i == Xsand_stoneout_1 && j == 6 ? 4 :
6056 i == Xsand_stoneout_1 && j == 7 ? 4 :
6057 i == Xsand_stoneout_2 && j == 0 ? 5 :
6058 i == Xsand_stoneout_2 && j == 1 ? 6 :
6059 i == Xsand_stoneout_2 && j == 2 ? 7 :
6060 i == Xsand_stoneout_2 && j == 3 ? 8 :
6061 i == Xsand_stoneout_2 && j == 4 ? 9 :
6062 i == Xsand_stoneout_2 && j == 5 ? 11 :
6063 i == Xsand_stoneout_2 && j == 6 ? 13 :
6064 i == Xsand_stoneout_2 && j == 7 ? 15 :
6065 i == Xboom_bug && j == 1 ? 2 :
6066 i == Xboom_bug && j == 2 ? 2 :
6067 i == Xboom_bug && j == 3 ? 4 :
6068 i == Xboom_bug && j == 4 ? 4 :
6069 i == Xboom_bug && j == 5 ? 2 :
6070 i == Xboom_bug && j == 6 ? 2 :
6071 i == Xboom_bug && j == 7 ? 0 :
6072 i == Xboom_bomb && j == 1 ? 2 :
6073 i == Xboom_bomb && j == 2 ? 2 :
6074 i == Xboom_bomb && j == 3 ? 4 :
6075 i == Xboom_bomb && j == 4 ? 4 :
6076 i == Xboom_bomb && j == 5 ? 2 :
6077 i == Xboom_bomb && j == 6 ? 2 :
6078 i == Xboom_bomb && j == 7 ? 0 :
6079 i == Xboom_android && j == 7 ? 6 :
6080 i == Xboom_1 && j == 1 ? 2 :
6081 i == Xboom_1 && j == 2 ? 2 :
6082 i == Xboom_1 && j == 3 ? 4 :
6083 i == Xboom_1 && j == 4 ? 4 :
6084 i == Xboom_1 && j == 5 ? 6 :
6085 i == Xboom_1 && j == 6 ? 6 :
6086 i == Xboom_1 && j == 7 ? 8 :
6087 i == Xboom_2 && j == 0 ? 8 :
6088 i == Xboom_2 && j == 1 ? 8 :
6089 i == Xboom_2 && j == 2 ? 10 :
6090 i == Xboom_2 && j == 3 ? 10 :
6091 i == Xboom_2 && j == 4 ? 10 :
6092 i == Xboom_2 && j == 5 ? 12 :
6093 i == Xboom_2 && j == 6 ? 12 :
6094 i == Xboom_2 && j == 7 ? 12 :
6095 special_animation && j == 4 ? 3 :
6096 effective_action != action ? 0 :
6100 Bitmap *debug_bitmap = g_em->bitmap;
6101 int debug_src_x = g_em->src_x;
6102 int debug_src_y = g_em->src_y;
6105 int frame = getAnimationFrame(g->anim_frames,
6108 g->anim_start_frame,
6111 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6112 g->double_movement && is_backside);
6114 g_em->bitmap = src_bitmap;
6115 g_em->src_x = src_x;
6116 g_em->src_y = src_y;
6117 g_em->src_offset_x = 0;
6118 g_em->src_offset_y = 0;
6119 g_em->dst_offset_x = 0;
6120 g_em->dst_offset_y = 0;
6121 g_em->width = TILEX;
6122 g_em->height = TILEY;
6124 g_em->crumbled_bitmap = NULL;
6125 g_em->crumbled_src_x = 0;
6126 g_em->crumbled_src_y = 0;
6127 g_em->crumbled_border_size = 0;
6129 g_em->has_crumbled_graphics = FALSE;
6130 g_em->preserve_background = FALSE;
6133 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6134 printf("::: empty crumbled: %d [%s], %d, %d\n",
6135 effective_element, element_info[effective_element].token_name,
6136 effective_action, direction);
6139 /* if element can be crumbled, but certain action graphics are just empty
6140 space (like snapping sand with the original R'n'D graphics), do not
6141 treat these empty space graphics as crumbled graphics in EMC engine */
6142 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6144 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6146 g_em->has_crumbled_graphics = TRUE;
6147 g_em->crumbled_bitmap = src_bitmap;
6148 g_em->crumbled_src_x = src_x;
6149 g_em->crumbled_src_y = src_y;
6150 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6154 if (element == EL_ROCK &&
6155 effective_action == ACTION_FILLING)
6156 printf("::: has_action_graphics == %d\n", has_action_graphics);
6159 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6160 effective_action == ACTION_MOVING ||
6161 effective_action == ACTION_PUSHING ||
6162 effective_action == ACTION_EATING)) ||
6163 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6164 effective_action == ACTION_EMPTYING)))
6167 (effective_action == ACTION_FALLING ||
6168 effective_action == ACTION_FILLING ||
6169 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6170 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6171 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6172 int num_steps = (i == Ydrip_s1 ? 16 :
6173 i == Ydrip_s1B ? 16 :
6174 i == Ydrip_s2 ? 16 :
6175 i == Ydrip_s2B ? 16 :
6176 i == Xsand_stonein_1 ? 32 :
6177 i == Xsand_stonein_2 ? 32 :
6178 i == Xsand_stonein_3 ? 32 :
6179 i == Xsand_stonein_4 ? 32 :
6180 i == Xsand_stoneout_1 ? 16 :
6181 i == Xsand_stoneout_2 ? 16 : 8);
6182 int cx = ABS(dx) * (TILEX / num_steps);
6183 int cy = ABS(dy) * (TILEY / num_steps);
6184 int step_frame = (i == Ydrip_s2 ? j + 8 :
6185 i == Ydrip_s2B ? j + 8 :
6186 i == Xsand_stonein_2 ? j + 8 :
6187 i == Xsand_stonein_3 ? j + 16 :
6188 i == Xsand_stonein_4 ? j + 24 :
6189 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6190 int step = (is_backside ? step_frame : num_steps - step_frame);
6192 if (is_backside) /* tile where movement starts */
6194 if (dx < 0 || dy < 0)
6196 g_em->src_offset_x = cx * step;
6197 g_em->src_offset_y = cy * step;
6201 g_em->dst_offset_x = cx * step;
6202 g_em->dst_offset_y = cy * step;
6205 else /* tile where movement ends */
6207 if (dx < 0 || dy < 0)
6209 g_em->dst_offset_x = cx * step;
6210 g_em->dst_offset_y = cy * step;
6214 g_em->src_offset_x = cx * step;
6215 g_em->src_offset_y = cy * step;
6219 g_em->width = TILEX - cx * step;
6220 g_em->height = TILEY - cy * step;
6223 /* create unique graphic identifier to decide if tile must be redrawn */
6224 /* bit 31 - 16 (16 bit): EM style graphic
6225 bit 15 - 12 ( 4 bit): EM style frame
6226 bit 11 - 6 ( 6 bit): graphic width
6227 bit 5 - 0 ( 6 bit): graphic height */
6228 g_em->unique_identifier =
6229 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6233 /* skip check for EMC elements not contained in original EMC artwork */
6234 if (element == EL_EMC_FAKE_ACID)
6237 if (g_em->bitmap != debug_bitmap ||
6238 g_em->src_x != debug_src_x ||
6239 g_em->src_y != debug_src_y ||
6240 g_em->src_offset_x != 0 ||
6241 g_em->src_offset_y != 0 ||
6242 g_em->dst_offset_x != 0 ||
6243 g_em->dst_offset_y != 0 ||
6244 g_em->width != TILEX ||
6245 g_em->height != TILEY)
6247 static int last_i = -1;
6255 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6256 i, element, element_info[element].token_name,
6257 element_action_info[effective_action].suffix, direction);
6259 if (element != effective_element)
6260 printf(" [%d ('%s')]",
6262 element_info[effective_element].token_name);
6266 if (g_em->bitmap != debug_bitmap)
6267 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6268 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6270 if (g_em->src_x != debug_src_x ||
6271 g_em->src_y != debug_src_y)
6272 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6273 j, (is_backside ? 'B' : 'F'),
6274 g_em->src_x, g_em->src_y,
6275 g_em->src_x / 32, g_em->src_y / 32,
6276 debug_src_x, debug_src_y,
6277 debug_src_x / 32, debug_src_y / 32);
6279 if (g_em->src_offset_x != 0 ||
6280 g_em->src_offset_y != 0 ||
6281 g_em->dst_offset_x != 0 ||
6282 g_em->dst_offset_y != 0)
6283 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6285 g_em->src_offset_x, g_em->src_offset_y,
6286 g_em->dst_offset_x, g_em->dst_offset_y);
6288 if (g_em->width != TILEX ||
6289 g_em->height != TILEY)
6290 printf(" %d (%d): size %d,%d should be %d,%d\n",
6292 g_em->width, g_em->height, TILEX, TILEY);
6294 num_em_gfx_errors++;
6301 for (i = 0; i < TILE_MAX; i++)
6303 for (j = 0; j < 8; j++)
6305 int element = object_mapping[i].element_rnd;
6306 int action = object_mapping[i].action;
6307 int direction = object_mapping[i].direction;
6308 boolean is_backside = object_mapping[i].is_backside;
6309 int graphic_action = el_act_dir2img(element, action, direction);
6310 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6312 if ((action == ACTION_SMASHED_BY_ROCK ||
6313 action == ACTION_SMASHED_BY_SPRING ||
6314 action == ACTION_EATING) &&
6315 graphic_action == graphic_default)
6317 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6318 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6319 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6320 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6323 /* no separate animation for "smashed by rock" -- use rock instead */
6324 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6325 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6327 g_em->bitmap = g_xx->bitmap;
6328 g_em->src_x = g_xx->src_x;
6329 g_em->src_y = g_xx->src_y;
6330 g_em->src_offset_x = g_xx->src_offset_x;
6331 g_em->src_offset_y = g_xx->src_offset_y;
6332 g_em->dst_offset_x = g_xx->dst_offset_x;
6333 g_em->dst_offset_y = g_xx->dst_offset_y;
6334 g_em->width = g_xx->width;
6335 g_em->height = g_xx->height;
6336 g_em->unique_identifier = g_xx->unique_identifier;
6339 g_em->preserve_background = TRUE;
6344 for (p = 0; p < MAX_PLAYERS; p++)
6346 for (i = 0; i < SPR_MAX; i++)
6348 int element = player_mapping[p][i].element_rnd;
6349 int action = player_mapping[p][i].action;
6350 int direction = player_mapping[p][i].direction;
6352 for (j = 0; j < 8; j++)
6354 int effective_element = element;
6355 int effective_action = action;
6356 int graphic = (direction == MV_NONE ?
6357 el_act2img(effective_element, effective_action) :
6358 el_act_dir2img(effective_element, effective_action,
6360 struct GraphicInfo *g = &graphic_info[graphic];
6361 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6367 Bitmap *debug_bitmap = g_em->bitmap;
6368 int debug_src_x = g_em->src_x;
6369 int debug_src_y = g_em->src_y;
6372 int frame = getAnimationFrame(g->anim_frames,
6375 g->anim_start_frame,
6378 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6380 g_em->bitmap = src_bitmap;
6381 g_em->src_x = src_x;
6382 g_em->src_y = src_y;
6383 g_em->src_offset_x = 0;
6384 g_em->src_offset_y = 0;
6385 g_em->dst_offset_x = 0;
6386 g_em->dst_offset_y = 0;
6387 g_em->width = TILEX;
6388 g_em->height = TILEY;
6392 /* skip check for EMC elements not contained in original EMC artwork */
6393 if (element == EL_PLAYER_3 ||
6394 element == EL_PLAYER_4)
6397 if (g_em->bitmap != debug_bitmap ||
6398 g_em->src_x != debug_src_x ||
6399 g_em->src_y != debug_src_y)
6401 static int last_i = -1;
6409 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6410 p, i, element, element_info[element].token_name,
6411 element_action_info[effective_action].suffix, direction);
6413 if (element != effective_element)
6414 printf(" [%d ('%s')]",
6416 element_info[effective_element].token_name);
6420 if (g_em->bitmap != debug_bitmap)
6421 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6422 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6424 if (g_em->src_x != debug_src_x ||
6425 g_em->src_y != debug_src_y)
6426 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6428 g_em->src_x, g_em->src_y,
6429 g_em->src_x / 32, g_em->src_y / 32,
6430 debug_src_x, debug_src_y,
6431 debug_src_x / 32, debug_src_y / 32);
6433 num_em_gfx_errors++;
6443 printf("::: [%d errors found]\n", num_em_gfx_errors);
6449 void PlayMenuSound()
6451 int sound = menu.sound[game_status];
6453 if (sound == SND_UNDEFINED)
6456 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6457 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6460 if (IS_LOOP_SOUND(sound))
6461 PlaySoundLoop(sound);
6466 void PlayMenuSoundStereo(int sound, int stereo_position)
6468 if (sound == SND_UNDEFINED)
6471 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6472 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6475 if (IS_LOOP_SOUND(sound))
6476 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6478 PlaySoundStereo(sound, stereo_position);
6481 void PlayMenuSoundIfLoop()
6483 int sound = menu.sound[game_status];
6485 if (sound == SND_UNDEFINED)
6488 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6489 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6492 if (IS_LOOP_SOUND(sound))
6493 PlaySoundLoop(sound);
6496 void PlayMenuMusic()
6498 int music = menu.music[game_status];
6500 if (music == MUS_UNDEFINED)
6503 if (!setup.sound_music)
6509 void PlaySoundActivating()
6512 PlaySound(SND_MENU_ITEM_ACTIVATING);
6516 void PlaySoundSelecting()
6519 PlaySound(SND_MENU_ITEM_SELECTING);
6523 void ToggleFullscreenIfNeeded()
6525 boolean change_fullscreen = (setup.fullscreen !=
6526 video.fullscreen_enabled);
6527 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6528 !strEqual(setup.fullscreen_mode,
6529 video.fullscreen_mode_current));
6531 if (!video.fullscreen_available)
6535 if (change_fullscreen || change_fullscreen_mode)
6537 if (setup.fullscreen != video.fullscreen_enabled ||
6538 setup.fullscreen_mode != video.fullscreen_mode_current)
6541 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6543 /* save backbuffer content which gets lost when toggling fullscreen mode */
6544 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6547 if (change_fullscreen_mode)
6549 if (setup.fullscreen && video.fullscreen_enabled)
6552 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6554 /* (this is now set in sdl.c) */
6556 video.fullscreen_mode_current = setup.fullscreen_mode;
6558 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6561 /* toggle fullscreen */
6562 ChangeVideoModeIfNeeded(setup.fullscreen);
6564 setup.fullscreen = video.fullscreen_enabled;
6566 /* restore backbuffer content from temporary backbuffer backup bitmap */
6567 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6569 FreeBitmap(tmp_backbuffer);
6572 /* update visible window/screen */
6573 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6575 redraw_mask = REDRAW_ALL;