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;
1823 int font_nr = FONT_TEXT_2;
1826 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1827 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1828 mode == MICROLABEL_IMPORTED_BY_HEAD)
1829 font_nr = FONT_TEXT_3;
1832 max_len_label_text = getMaxTextLength(pos, font_nr);
1834 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1838 if (pos->chars != -1)
1839 max_len_label_text = pos->chars;
1842 for (i = 0; i < max_len_label_text; i++)
1843 label_text[i] = ' ';
1844 label_text[max_len_label_text] = '\0';
1846 if (strlen(label_text) > 0)
1849 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1851 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1852 int lypos = MICROLABEL2_YPOS;
1854 DrawText(lxpos, lypos, label_text, font_nr);
1859 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1860 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1861 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1862 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1863 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1864 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1865 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1866 max_len_label_text);
1867 label_text[max_len_label_text] = '\0';
1869 if (strlen(label_text) > 0)
1872 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1874 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1875 int lypos = MICROLABEL2_YPOS;
1877 DrawText(lxpos, lypos, label_text, font_nr);
1881 redraw_mask |= REDRAW_MICROLEVEL;
1884 void DrawPreviewLevel(boolean restart)
1886 static unsigned long scroll_delay = 0;
1887 static unsigned long label_delay = 0;
1888 static int from_x, from_y, scroll_direction;
1889 static int label_state, label_counter;
1890 unsigned long scroll_delay_value = preview.step_delay;
1891 boolean show_level_border = (BorderElement != EL_EMPTY);
1892 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1893 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1894 int last_game_status = game_status; /* save current game status */
1896 /* force PREVIEW font on preview level */
1897 game_status = GAME_MODE_PSEUDO_PREVIEW;
1904 if (preview.anim_mode == ANIM_CENTERED)
1906 if (level_xsize > preview.xsize)
1907 from_x = (level_xsize - preview.xsize) / 2;
1908 if (level_ysize > preview.ysize)
1909 from_y = (level_ysize - preview.ysize) / 2;
1912 from_x += preview.xoffset;
1913 from_y += preview.yoffset;
1915 scroll_direction = MV_RIGHT;
1919 DrawPreviewLevelExt(from_x, from_y);
1920 DrawPreviewLevelLabelExt(label_state);
1922 /* initialize delay counters */
1923 DelayReached(&scroll_delay, 0);
1924 DelayReached(&label_delay, 0);
1926 if (leveldir_current->name)
1928 struct TextPosInfo *pos = &menu.main.text.level_info_1;
1929 char label_text[MAX_OUTPUT_LINESIZE + 1];
1930 int font_nr = FONT_TEXT_1;
1932 int max_len_label_text = getMaxTextLength(pos, font_nr);
1934 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1942 if (pos->chars != -1)
1943 max_len_label_text = pos->chars;
1946 strncpy(label_text, leveldir_current->name, max_len_label_text);
1947 label_text[max_len_label_text] = '\0';
1950 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1952 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1953 lypos = SY + MICROLABEL1_YPOS;
1955 DrawText(lxpos, lypos, label_text, font_nr);
1959 game_status = last_game_status; /* restore current game status */
1964 /* scroll preview level, if needed */
1965 if (preview.anim_mode != ANIM_NONE &&
1966 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1967 DelayReached(&scroll_delay, scroll_delay_value))
1969 switch (scroll_direction)
1974 from_x -= preview.step_offset;
1975 from_x = (from_x < 0 ? 0 : from_x);
1978 scroll_direction = MV_UP;
1982 if (from_x < level_xsize - preview.xsize)
1984 from_x += preview.step_offset;
1985 from_x = (from_x > level_xsize - preview.xsize ?
1986 level_xsize - preview.xsize : from_x);
1989 scroll_direction = MV_DOWN;
1995 from_y -= preview.step_offset;
1996 from_y = (from_y < 0 ? 0 : from_y);
1999 scroll_direction = MV_RIGHT;
2003 if (from_y < level_ysize - preview.ysize)
2005 from_y += preview.step_offset;
2006 from_y = (from_y > level_ysize - preview.ysize ?
2007 level_ysize - preview.ysize : from_y);
2010 scroll_direction = MV_LEFT;
2017 DrawPreviewLevelExt(from_x, from_y);
2020 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2021 /* redraw micro level label, if needed */
2022 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2023 !strEqual(level.author, ANONYMOUS_NAME) &&
2024 !strEqual(level.author, leveldir_current->name) &&
2025 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2027 int max_label_counter = 23;
2029 if (leveldir_current->imported_from != NULL &&
2030 strlen(leveldir_current->imported_from) > 0)
2031 max_label_counter += 14;
2032 if (leveldir_current->imported_by != NULL &&
2033 strlen(leveldir_current->imported_by) > 0)
2034 max_label_counter += 14;
2036 label_counter = (label_counter + 1) % max_label_counter;
2037 label_state = (label_counter >= 0 && label_counter <= 7 ?
2038 MICROLABEL_LEVEL_NAME :
2039 label_counter >= 9 && label_counter <= 12 ?
2040 MICROLABEL_LEVEL_AUTHOR_HEAD :
2041 label_counter >= 14 && label_counter <= 21 ?
2042 MICROLABEL_LEVEL_AUTHOR :
2043 label_counter >= 23 && label_counter <= 26 ?
2044 MICROLABEL_IMPORTED_FROM_HEAD :
2045 label_counter >= 28 && label_counter <= 35 ?
2046 MICROLABEL_IMPORTED_FROM :
2047 label_counter >= 37 && label_counter <= 40 ?
2048 MICROLABEL_IMPORTED_BY_HEAD :
2049 label_counter >= 42 && label_counter <= 49 ?
2050 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2052 if (leveldir_current->imported_from == NULL &&
2053 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2054 label_state == MICROLABEL_IMPORTED_FROM))
2055 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2056 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2058 DrawPreviewLevelLabelExt(label_state);
2061 game_status = last_game_status; /* restore current game status */
2064 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2065 int graphic, int sync_frame, int mask_mode)
2067 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2069 if (mask_mode == USE_MASKING)
2070 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2072 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2075 inline void DrawGraphicAnimation(int x, int y, int graphic)
2077 int lx = LEVELX(x), ly = LEVELY(y);
2079 if (!IN_SCR_FIELD(x, y))
2082 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2083 graphic, GfxFrame[lx][ly], NO_MASKING);
2084 MarkTileDirty(x, y);
2087 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2089 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2092 void DrawLevelElementAnimation(int x, int y, int element)
2094 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2096 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2099 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2101 int sx = SCREENX(x), sy = SCREENY(y);
2103 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2106 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2109 DrawGraphicAnimation(sx, sy, graphic);
2112 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2113 DrawLevelFieldCrumbledSand(x, y);
2115 if (GFX_CRUMBLED(Feld[x][y]))
2116 DrawLevelFieldCrumbledSand(x, y);
2120 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2122 int sx = SCREENX(x), sy = SCREENY(y);
2125 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2128 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2130 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2133 DrawGraphicAnimation(sx, sy, graphic);
2135 if (GFX_CRUMBLED(element))
2136 DrawLevelFieldCrumbledSand(x, y);
2139 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2141 if (player->use_murphy)
2143 /* this works only because currently only one player can be "murphy" ... */
2144 static int last_horizontal_dir = MV_LEFT;
2145 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2147 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2148 last_horizontal_dir = move_dir;
2150 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2152 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2154 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2160 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2163 static boolean equalGraphics(int graphic1, int graphic2)
2165 struct GraphicInfo *g1 = &graphic_info[graphic1];
2166 struct GraphicInfo *g2 = &graphic_info[graphic2];
2168 return (g1->bitmap == g2->bitmap &&
2169 g1->src_x == g2->src_x &&
2170 g1->src_y == g2->src_y &&
2171 g1->anim_frames == g2->anim_frames &&
2172 g1->anim_delay == g2->anim_delay &&
2173 g1->anim_mode == g2->anim_mode);
2176 void DrawAllPlayers()
2180 for (i = 0; i < MAX_PLAYERS; i++)
2181 if (stored_player[i].active)
2182 DrawPlayer(&stored_player[i]);
2185 void DrawPlayerField(int x, int y)
2187 if (!IS_PLAYER(x, y))
2190 DrawPlayer(PLAYERINFO(x, y));
2193 void DrawPlayer(struct PlayerInfo *player)
2195 int jx = player->jx;
2196 int jy = player->jy;
2197 int move_dir = player->MovDir;
2198 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2199 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2200 int last_jx = (player->is_moving ? jx - dx : jx);
2201 int last_jy = (player->is_moving ? jy - dy : jy);
2202 int next_jx = jx + dx;
2203 int next_jy = jy + dy;
2204 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2205 boolean player_is_opaque = FALSE;
2206 int sx = SCREENX(jx), sy = SCREENY(jy);
2207 int sxx = 0, syy = 0;
2208 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2210 int action = ACTION_DEFAULT;
2211 int last_player_graphic = getPlayerGraphic(player, move_dir);
2212 int last_player_frame = player->Frame;
2215 /* GfxElement[][] is set to the element the player is digging or collecting;
2216 remove also for off-screen player if the player is not moving anymore */
2217 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2218 GfxElement[jx][jy] = EL_UNDEFINED;
2220 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2224 if (!IN_LEV_FIELD(jx, jy))
2226 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2227 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2228 printf("DrawPlayerField(): This should never happen!\n");
2233 if (element == EL_EXPLOSION)
2236 action = (player->is_pushing ? ACTION_PUSHING :
2237 player->is_digging ? ACTION_DIGGING :
2238 player->is_collecting ? ACTION_COLLECTING :
2239 player->is_moving ? ACTION_MOVING :
2240 player->is_snapping ? ACTION_SNAPPING :
2241 player->is_dropping ? ACTION_DROPPING :
2242 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2244 if (player->is_waiting)
2245 move_dir = player->dir_waiting;
2247 InitPlayerGfxAnimation(player, action, move_dir);
2249 /* ----------------------------------------------------------------------- */
2250 /* draw things in the field the player is leaving, if needed */
2251 /* ----------------------------------------------------------------------- */
2253 if (player->is_moving)
2255 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2257 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2259 if (last_element == EL_DYNAMITE_ACTIVE ||
2260 last_element == EL_EM_DYNAMITE_ACTIVE ||
2261 last_element == EL_SP_DISK_RED_ACTIVE)
2262 DrawDynamite(last_jx, last_jy);
2264 DrawLevelFieldThruMask(last_jx, last_jy);
2266 else if (last_element == EL_DYNAMITE_ACTIVE ||
2267 last_element == EL_EM_DYNAMITE_ACTIVE ||
2268 last_element == EL_SP_DISK_RED_ACTIVE)
2269 DrawDynamite(last_jx, last_jy);
2271 /* !!! this is not enough to prevent flickering of players which are
2272 moving next to each others without a free tile between them -- this
2273 can only be solved by drawing all players layer by layer (first the
2274 background, then the foreground etc.) !!! => TODO */
2275 else if (!IS_PLAYER(last_jx, last_jy))
2276 DrawLevelField(last_jx, last_jy);
2279 DrawLevelField(last_jx, last_jy);
2282 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2283 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2286 if (!IN_SCR_FIELD(sx, sy))
2289 if (setup.direct_draw)
2290 SetDrawtoField(DRAW_BUFFERED);
2292 /* ----------------------------------------------------------------------- */
2293 /* draw things behind the player, if needed */
2294 /* ----------------------------------------------------------------------- */
2297 DrawLevelElement(jx, jy, Back[jx][jy]);
2298 else if (IS_ACTIVE_BOMB(element))
2299 DrawLevelElement(jx, jy, EL_EMPTY);
2302 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2304 int old_element = GfxElement[jx][jy];
2305 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2306 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2308 if (GFX_CRUMBLED(old_element))
2309 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2311 DrawGraphic(sx, sy, old_graphic, frame);
2313 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2314 player_is_opaque = TRUE;
2318 GfxElement[jx][jy] = EL_UNDEFINED;
2320 /* make sure that pushed elements are drawn with correct frame rate */
2322 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2324 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2325 GfxFrame[jx][jy] = player->StepFrame;
2327 if (player->is_pushing && player->is_moving)
2328 GfxFrame[jx][jy] = player->StepFrame;
2331 DrawLevelField(jx, jy);
2335 /* ----------------------------------------------------------------------- */
2336 /* draw player himself */
2337 /* ----------------------------------------------------------------------- */
2339 graphic = getPlayerGraphic(player, move_dir);
2341 /* in the case of changed player action or direction, prevent the current
2342 animation frame from being restarted for identical animations */
2343 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2344 player->Frame = last_player_frame;
2346 frame = getGraphicAnimationFrame(graphic, player->Frame);
2350 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2351 sxx = player->GfxPos;
2353 syy = player->GfxPos;
2356 if (!setup.soft_scrolling && ScreenMovPos)
2359 if (player_is_opaque)
2360 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2362 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2364 if (SHIELD_ON(player))
2366 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2367 IMG_SHIELD_NORMAL_ACTIVE);
2368 int frame = getGraphicAnimationFrame(graphic, -1);
2370 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2373 /* ----------------------------------------------------------------------- */
2374 /* draw things the player is pushing, if needed */
2375 /* ----------------------------------------------------------------------- */
2378 printf("::: %d, %d [%d, %d] [%d]\n",
2379 player->is_pushing, player_is_moving, player->GfxAction,
2380 player->is_moving, player_is_moving);
2384 if (player->is_pushing && player->is_moving)
2386 int px = SCREENX(jx), py = SCREENY(jy);
2387 int pxx = (TILEX - ABS(sxx)) * dx;
2388 int pyy = (TILEY - ABS(syy)) * dy;
2389 int gfx_frame = GfxFrame[jx][jy];
2395 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2397 element = Feld[next_jx][next_jy];
2398 gfx_frame = GfxFrame[next_jx][next_jy];
2401 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2404 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2405 frame = getGraphicAnimationFrame(graphic, sync_frame);
2407 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2410 /* draw background element under pushed element (like the Sokoban field) */
2411 if (Back[next_jx][next_jy])
2412 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2414 /* masked drawing is needed for EMC style (double) movement graphics */
2415 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2419 /* ----------------------------------------------------------------------- */
2420 /* draw things in front of player (active dynamite or dynabombs) */
2421 /* ----------------------------------------------------------------------- */
2423 if (IS_ACTIVE_BOMB(element))
2425 graphic = el2img(element);
2426 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2428 if (game.emulation == EMU_SUPAPLEX)
2429 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2431 DrawGraphicThruMask(sx, sy, graphic, frame);
2434 if (player_is_moving && last_element == EL_EXPLOSION)
2436 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2437 GfxElement[last_jx][last_jy] : EL_EMPTY);
2438 int graphic = el_act2img(element, ACTION_EXPLODING);
2439 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2440 int phase = ExplodePhase[last_jx][last_jy] - 1;
2441 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2444 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2447 /* ----------------------------------------------------------------------- */
2448 /* draw elements the player is just walking/passing through/under */
2449 /* ----------------------------------------------------------------------- */
2451 if (player_is_moving)
2453 /* handle the field the player is leaving ... */
2454 if (IS_ACCESSIBLE_INSIDE(last_element))
2455 DrawLevelField(last_jx, last_jy);
2456 else if (IS_ACCESSIBLE_UNDER(last_element))
2457 DrawLevelFieldThruMask(last_jx, last_jy);
2460 /* do not redraw accessible elements if the player is just pushing them */
2461 if (!player_is_moving || !player->is_pushing)
2463 /* ... and the field the player is entering */
2464 if (IS_ACCESSIBLE_INSIDE(element))
2465 DrawLevelField(jx, jy);
2466 else if (IS_ACCESSIBLE_UNDER(element))
2467 DrawLevelFieldThruMask(jx, jy);
2470 if (setup.direct_draw)
2472 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2473 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2474 int x_size = TILEX * (1 + ABS(jx - last_jx));
2475 int y_size = TILEY * (1 + ABS(jy - last_jy));
2477 BlitBitmap(drawto_field, window,
2478 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2479 SetDrawtoField(DRAW_DIRECT);
2482 MarkTileDirty(sx, sy);
2485 /* ------------------------------------------------------------------------- */
2487 void WaitForEventToContinue()
2489 boolean still_wait = TRUE;
2491 /* simulate releasing mouse button over last gadget, if still pressed */
2493 HandleGadgets(-1, -1, 0);
2495 button_status = MB_RELEASED;
2511 case EVENT_BUTTONPRESS:
2512 case EVENT_KEYPRESS:
2516 case EVENT_KEYRELEASE:
2517 ClearPlayerAction();
2521 HandleOtherEvents(&event);
2525 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2532 /* don't eat all CPU time */
2537 #define MAX_REQUEST_LINES 13
2538 #define MAX_REQUEST_LINE_FONT1_LEN 7
2539 #define MAX_REQUEST_LINE_FONT2_LEN 10
2541 boolean Request(char *text, unsigned int req_state)
2543 int mx, my, ty, result = -1;
2544 unsigned int old_door_state;
2545 int last_game_status = game_status; /* save current game status */
2546 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2547 int font_nr = FONT_TEXT_2;
2548 int max_word_len = 0;
2551 for (text_ptr = text; *text_ptr; text_ptr++)
2553 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2555 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2557 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2559 font_nr = FONT_TEXT_1;
2561 font_nr = FONT_LEVEL_NUMBER;
2568 if (game_status == GAME_MODE_PLAYING &&
2569 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2570 BlitScreenToBitmap_EM(backbuffer);
2572 /* disable deactivated drawing when quick-loading level tape recording */
2573 if (tape.playing && tape.deactivate_display)
2574 TapeDeactivateDisplayOff(TRUE);
2576 SetMouseCursor(CURSOR_DEFAULT);
2578 #if defined(NETWORK_AVALIABLE)
2579 /* pause network game while waiting for request to answer */
2580 if (options.network &&
2581 game_status == GAME_MODE_PLAYING &&
2582 req_state & REQUEST_WAIT_FOR_INPUT)
2583 SendToServer_PausePlaying();
2586 old_door_state = GetDoorState();
2588 /* simulate releasing mouse button over last gadget, if still pressed */
2590 HandleGadgets(-1, -1, 0);
2594 if (old_door_state & DOOR_OPEN_1)
2596 CloseDoor(DOOR_CLOSE_1);
2598 /* save old door content */
2599 BlitBitmap(bitmap_db_door, bitmap_db_door,
2600 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2601 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2605 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2608 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2610 /* clear door drawing field */
2611 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2613 /* force DOOR font on preview level */
2614 game_status = GAME_MODE_PSEUDO_DOOR;
2616 /* write text for request */
2617 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2619 char text_line[max_request_line_len + 1];
2625 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2628 if (!tc || tc == ' ')
2639 strncpy(text_line, text, tl);
2642 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2643 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2644 text_line, font_nr);
2646 text += tl + (tc == ' ' ? 1 : 0);
2649 game_status = last_game_status; /* restore current game status */
2651 if (req_state & REQ_ASK)
2653 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2654 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2656 else if (req_state & REQ_CONFIRM)
2658 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2660 else if (req_state & REQ_PLAYER)
2662 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2663 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2664 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2665 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2668 /* copy request gadgets to door backbuffer */
2669 BlitBitmap(drawto, bitmap_db_door,
2670 DX, DY, DXSIZE, DYSIZE,
2671 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2673 OpenDoor(DOOR_OPEN_1);
2675 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2677 if (game_status == GAME_MODE_PLAYING)
2679 SetPanelBackground();
2680 SetDrawBackgroundMask(REDRAW_DOOR_1);
2684 SetDrawBackgroundMask(REDRAW_FIELD);
2690 if (game_status != GAME_MODE_MAIN)
2693 button_status = MB_RELEASED;
2695 request_gadget_id = -1;
2697 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2709 case EVENT_BUTTONPRESS:
2710 case EVENT_BUTTONRELEASE:
2711 case EVENT_MOTIONNOTIFY:
2713 if (event.type == EVENT_MOTIONNOTIFY)
2715 if (!PointerInWindow(window))
2716 continue; /* window and pointer are on different screens */
2721 motion_status = TRUE;
2722 mx = ((MotionEvent *) &event)->x;
2723 my = ((MotionEvent *) &event)->y;
2727 motion_status = FALSE;
2728 mx = ((ButtonEvent *) &event)->x;
2729 my = ((ButtonEvent *) &event)->y;
2730 if (event.type == EVENT_BUTTONPRESS)
2731 button_status = ((ButtonEvent *) &event)->button;
2733 button_status = MB_RELEASED;
2736 /* this sets 'request_gadget_id' */
2737 HandleGadgets(mx, my, button_status);
2739 switch (request_gadget_id)
2741 case TOOL_CTRL_ID_YES:
2744 case TOOL_CTRL_ID_NO:
2747 case TOOL_CTRL_ID_CONFIRM:
2748 result = TRUE | FALSE;
2751 case TOOL_CTRL_ID_PLAYER_1:
2754 case TOOL_CTRL_ID_PLAYER_2:
2757 case TOOL_CTRL_ID_PLAYER_3:
2760 case TOOL_CTRL_ID_PLAYER_4:
2771 case EVENT_KEYPRESS:
2772 switch (GetEventKey((KeyEvent *)&event, TRUE))
2785 if (req_state & REQ_PLAYER)
2789 case EVENT_KEYRELEASE:
2790 ClearPlayerAction();
2794 HandleOtherEvents(&event);
2798 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2800 int joy = AnyJoystick();
2802 if (joy & JOY_BUTTON_1)
2804 else if (joy & JOY_BUTTON_2)
2810 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2812 HandleGameActions();
2819 if (!PendingEvent()) /* delay only if no pending events */
2828 if (!PendingEvent()) /* delay only if no pending events */
2831 /* don't eat all CPU time */
2838 if (game_status != GAME_MODE_MAIN)
2843 if (!(req_state & REQ_STAY_OPEN))
2845 CloseDoor(DOOR_CLOSE_1);
2847 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2848 (req_state & REQ_REOPEN))
2849 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2854 if (game_status == GAME_MODE_PLAYING)
2856 SetPanelBackground();
2857 SetDrawBackgroundMask(REDRAW_DOOR_1);
2861 SetDrawBackgroundMask(REDRAW_FIELD);
2864 #if defined(NETWORK_AVALIABLE)
2865 /* continue network game after request */
2866 if (options.network &&
2867 game_status == GAME_MODE_PLAYING &&
2868 req_state & REQUEST_WAIT_FOR_INPUT)
2869 SendToServer_ContinuePlaying();
2872 /* restore deactivated drawing when quick-loading level tape recording */
2873 if (tape.playing && tape.deactivate_display)
2874 TapeDeactivateDisplayOn();
2879 unsigned int OpenDoor(unsigned int door_state)
2881 if (door_state & DOOR_COPY_BACK)
2883 if (door_state & DOOR_OPEN_1)
2884 BlitBitmap(bitmap_db_door, bitmap_db_door,
2885 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2886 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2888 if (door_state & DOOR_OPEN_2)
2889 BlitBitmap(bitmap_db_door, bitmap_db_door,
2890 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2891 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2893 door_state &= ~DOOR_COPY_BACK;
2896 return MoveDoor(door_state);
2899 unsigned int CloseDoor(unsigned int door_state)
2901 unsigned int old_door_state = GetDoorState();
2903 if (!(door_state & DOOR_NO_COPY_BACK))
2905 if (old_door_state & DOOR_OPEN_1)
2906 BlitBitmap(backbuffer, bitmap_db_door,
2907 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2909 if (old_door_state & DOOR_OPEN_2)
2910 BlitBitmap(backbuffer, bitmap_db_door,
2911 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2913 door_state &= ~DOOR_NO_COPY_BACK;
2916 return MoveDoor(door_state);
2919 unsigned int GetDoorState()
2921 return MoveDoor(DOOR_GET_STATE);
2924 unsigned int SetDoorState(unsigned int door_state)
2926 return MoveDoor(door_state | DOOR_SET_STATE);
2929 unsigned int MoveDoor(unsigned int door_state)
2931 static int door1 = DOOR_OPEN_1;
2932 static int door2 = DOOR_CLOSE_2;
2933 unsigned long door_delay = 0;
2934 unsigned long door_delay_value;
2937 if (door_1.width < 0 || door_1.width > DXSIZE)
2938 door_1.width = DXSIZE;
2939 if (door_1.height < 0 || door_1.height > DYSIZE)
2940 door_1.height = DYSIZE;
2941 if (door_2.width < 0 || door_2.width > VXSIZE)
2942 door_2.width = VXSIZE;
2943 if (door_2.height < 0 || door_2.height > VYSIZE)
2944 door_2.height = VYSIZE;
2946 if (door_state == DOOR_GET_STATE)
2947 return (door1 | door2);
2949 if (door_state & DOOR_SET_STATE)
2951 if (door_state & DOOR_ACTION_1)
2952 door1 = door_state & DOOR_ACTION_1;
2953 if (door_state & DOOR_ACTION_2)
2954 door2 = door_state & DOOR_ACTION_2;
2956 return (door1 | door2);
2959 if (!(door_state & DOOR_FORCE_REDRAW))
2961 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2962 door_state &= ~DOOR_OPEN_1;
2963 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2964 door_state &= ~DOOR_CLOSE_1;
2965 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2966 door_state &= ~DOOR_OPEN_2;
2967 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2968 door_state &= ~DOOR_CLOSE_2;
2971 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2974 if (setup.quick_doors)
2976 stepsize = 20; /* must be choosen to always draw last frame */
2977 door_delay_value = 0;
2980 if (global.autoplay_leveldir)
2982 door_state |= DOOR_NO_DELAY;
2983 door_state &= ~DOOR_CLOSE_ALL;
2986 if (door_state & DOOR_ACTION)
2988 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2989 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2990 boolean door_1_done = (!handle_door_1);
2991 boolean door_2_done = (!handle_door_2);
2992 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2993 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2994 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2995 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2996 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2997 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2998 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2999 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3000 int door_skip = max_door_size - door_size;
3001 int end = door_size;
3002 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3005 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3007 /* opening door sound has priority over simultaneously closing door */
3008 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3009 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3010 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3011 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3014 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3017 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3018 GC gc = bitmap->stored_clip_gc;
3020 if (door_state & DOOR_ACTION_1)
3022 int a = MIN(x * door_1.step_offset, end);
3023 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3024 int i = p + door_skip;
3026 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3028 BlitBitmap(bitmap_db_door, drawto,
3029 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3030 DXSIZE, DYSIZE, DX, DY);
3034 BlitBitmap(bitmap_db_door, drawto,
3035 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3036 DXSIZE, DYSIZE - p / 2, DX, DY);
3038 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3041 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3043 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3044 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3045 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3046 int dst2_x = DX, dst2_y = DY;
3047 int width = i, height = DYSIZE;
3049 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3050 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3053 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3054 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3057 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3059 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3060 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3061 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3062 int dst2_x = DX, dst2_y = DY;
3063 int width = DXSIZE, height = i;
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 (x <= DXSIZE) /* ANIM_DEFAULT */
3075 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3077 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3078 BlitBitmapMasked(bitmap, drawto,
3079 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3080 DX + DXSIZE - i, DY + j);
3081 BlitBitmapMasked(bitmap, drawto,
3082 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3083 DX + DXSIZE - i, DY + 140 + j);
3084 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3085 DY - (DOOR_GFX_PAGEY1 + j));
3086 BlitBitmapMasked(bitmap, drawto,
3087 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3089 BlitBitmapMasked(bitmap, drawto,
3090 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3093 BlitBitmapMasked(bitmap, drawto,
3094 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3096 BlitBitmapMasked(bitmap, drawto,
3097 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3099 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3100 BlitBitmapMasked(bitmap, drawto,
3101 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3102 DX + DXSIZE - i, DY + 77 + j);
3103 BlitBitmapMasked(bitmap, drawto,
3104 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3105 DX + DXSIZE - i, DY + 203 + j);
3108 redraw_mask |= REDRAW_DOOR_1;
3109 door_1_done = (a == end);
3112 if (door_state & DOOR_ACTION_2)
3114 int a = MIN(x * door_2.step_offset, door_size);
3115 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3116 int i = p + door_skip;
3118 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3120 BlitBitmap(bitmap_db_door, drawto,
3121 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3122 VXSIZE, VYSIZE, VX, VY);
3124 else if (x <= VYSIZE)
3126 BlitBitmap(bitmap_db_door, drawto,
3127 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3128 VXSIZE, VYSIZE - p / 2, VX, VY);
3130 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3133 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3135 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3136 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3137 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3138 int dst2_x = VX, dst2_y = VY;
3139 int width = i, height = VYSIZE;
3141 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3142 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3145 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3146 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3149 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3151 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3152 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3153 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3154 int dst2_x = VX, dst2_y = VY;
3155 int width = VXSIZE, height = i;
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 (x <= VXSIZE) /* ANIM_DEFAULT */
3167 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3169 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3170 BlitBitmapMasked(bitmap, drawto,
3171 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3172 VX + VXSIZE - i, VY + j);
3173 SetClipOrigin(bitmap, gc,
3174 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3175 BlitBitmapMasked(bitmap, drawto,
3176 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3179 BlitBitmapMasked(bitmap, drawto,
3180 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3181 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3182 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3183 BlitBitmapMasked(bitmap, drawto,
3184 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3186 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3189 redraw_mask |= REDRAW_DOOR_2;
3190 door_2_done = (a == VXSIZE);
3193 if (!(door_state & DOOR_NO_DELAY))
3197 if (game_status == GAME_MODE_MAIN)
3200 WaitUntilDelayReached(&door_delay, door_delay_value);
3205 if (door_state & DOOR_ACTION_1)
3206 door1 = door_state & DOOR_ACTION_1;
3207 if (door_state & DOOR_ACTION_2)
3208 door2 = door_state & DOOR_ACTION_2;
3210 return (door1 | door2);
3213 void DrawSpecialEditorDoor()
3215 /* draw bigger toolbox window */
3216 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3217 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3219 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3220 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3223 redraw_mask |= REDRAW_ALL;
3226 void UndrawSpecialEditorDoor()
3228 /* draw normal tape recorder window */
3229 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3230 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3233 redraw_mask |= REDRAW_ALL;
3237 /* ---------- new tool button stuff ---------------------------------------- */
3239 /* graphic position values for tool buttons */
3240 #define TOOL_BUTTON_YES_XPOS 2
3241 #define TOOL_BUTTON_YES_YPOS 250
3242 #define TOOL_BUTTON_YES_GFX_YPOS 0
3243 #define TOOL_BUTTON_YES_XSIZE 46
3244 #define TOOL_BUTTON_YES_YSIZE 28
3245 #define TOOL_BUTTON_NO_XPOS 52
3246 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3247 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3248 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3249 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3250 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3251 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3252 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3253 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3254 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3255 #define TOOL_BUTTON_PLAYER_XSIZE 30
3256 #define TOOL_BUTTON_PLAYER_YSIZE 30
3257 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3258 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3259 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3260 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3261 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3262 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3263 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3264 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3265 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3266 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3267 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3268 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3269 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3270 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3271 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3272 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3273 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3274 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3275 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3276 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3285 } toolbutton_info[NUM_TOOL_BUTTONS] =
3288 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3289 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3290 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3295 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3296 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3297 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3302 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3303 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3304 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3305 TOOL_CTRL_ID_CONFIRM,
3309 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3310 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3311 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3312 TOOL_CTRL_ID_PLAYER_1,
3316 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3317 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3318 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3319 TOOL_CTRL_ID_PLAYER_2,
3323 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3324 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3325 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3326 TOOL_CTRL_ID_PLAYER_3,
3330 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3331 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3332 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3333 TOOL_CTRL_ID_PLAYER_4,
3338 void CreateToolButtons()
3342 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3344 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3345 Bitmap *deco_bitmap = None;
3346 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3347 struct GadgetInfo *gi;
3348 unsigned long event_mask;
3349 int gd_xoffset, gd_yoffset;
3350 int gd_x1, gd_x2, gd_y;
3353 event_mask = GD_EVENT_RELEASED;
3355 gd_xoffset = toolbutton_info[i].xpos;
3356 gd_yoffset = toolbutton_info[i].ypos;
3357 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3358 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3359 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3361 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3363 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3365 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3366 &deco_bitmap, &deco_x, &deco_y);
3367 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3368 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3371 gi = CreateGadget(GDI_CUSTOM_ID, id,
3372 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3373 GDI_X, DX + toolbutton_info[i].x,
3374 GDI_Y, DY + toolbutton_info[i].y,
3375 GDI_WIDTH, toolbutton_info[i].width,
3376 GDI_HEIGHT, toolbutton_info[i].height,
3377 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3378 GDI_STATE, GD_BUTTON_UNPRESSED,
3379 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3380 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3381 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3382 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3383 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3384 GDI_DECORATION_SHIFTING, 1, 1,
3385 GDI_DIRECT_DRAW, FALSE,
3386 GDI_EVENT_MASK, event_mask,
3387 GDI_CALLBACK_ACTION, HandleToolButtons,
3391 Error(ERR_EXIT, "cannot create gadget");
3393 tool_gadget[id] = gi;
3397 void FreeToolButtons()
3401 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3402 FreeGadget(tool_gadget[i]);
3405 static void UnmapToolButtons()
3409 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3410 UnmapGadget(tool_gadget[i]);
3413 static void HandleToolButtons(struct GadgetInfo *gi)
3415 request_gadget_id = gi->custom_id;
3418 static struct Mapping_EM_to_RND_object
3421 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3422 boolean is_backside; /* backside of moving element */
3428 em_object_mapping_list[] =
3431 Xblank, TRUE, FALSE,
3435 Yacid_splash_eB, FALSE, FALSE,
3436 EL_ACID_SPLASH_RIGHT, -1, -1
3439 Yacid_splash_wB, FALSE, FALSE,
3440 EL_ACID_SPLASH_LEFT, -1, -1
3443 #ifdef EM_ENGINE_BAD_ROLL
3445 Xstone_force_e, FALSE, FALSE,
3446 EL_ROCK, -1, MV_BIT_RIGHT
3449 Xstone_force_w, FALSE, FALSE,
3450 EL_ROCK, -1, MV_BIT_LEFT
3453 Xnut_force_e, FALSE, FALSE,
3454 EL_NUT, -1, MV_BIT_RIGHT
3457 Xnut_force_w, FALSE, FALSE,
3458 EL_NUT, -1, MV_BIT_LEFT
3461 Xspring_force_e, FALSE, FALSE,
3462 EL_SPRING, -1, MV_BIT_RIGHT
3465 Xspring_force_w, FALSE, FALSE,
3466 EL_SPRING, -1, MV_BIT_LEFT
3469 Xemerald_force_e, FALSE, FALSE,
3470 EL_EMERALD, -1, MV_BIT_RIGHT
3473 Xemerald_force_w, FALSE, FALSE,
3474 EL_EMERALD, -1, MV_BIT_LEFT
3477 Xdiamond_force_e, FALSE, FALSE,
3478 EL_DIAMOND, -1, MV_BIT_RIGHT
3481 Xdiamond_force_w, FALSE, FALSE,
3482 EL_DIAMOND, -1, MV_BIT_LEFT
3485 Xbomb_force_e, FALSE, FALSE,
3486 EL_BOMB, -1, MV_BIT_RIGHT
3489 Xbomb_force_w, FALSE, FALSE,
3490 EL_BOMB, -1, MV_BIT_LEFT
3492 #endif /* EM_ENGINE_BAD_ROLL */
3495 Xstone, TRUE, FALSE,
3499 Xstone_pause, FALSE, FALSE,
3503 Xstone_fall, FALSE, FALSE,
3507 Ystone_s, FALSE, FALSE,
3508 EL_ROCK, ACTION_FALLING, -1
3511 Ystone_sB, FALSE, TRUE,
3512 EL_ROCK, ACTION_FALLING, -1
3515 Ystone_e, FALSE, FALSE,
3516 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3519 Ystone_eB, FALSE, TRUE,
3520 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3523 Ystone_w, FALSE, FALSE,
3524 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3527 Ystone_wB, FALSE, TRUE,
3528 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3535 Xnut_pause, FALSE, FALSE,
3539 Xnut_fall, FALSE, FALSE,
3543 Ynut_s, FALSE, FALSE,
3544 EL_NUT, ACTION_FALLING, -1
3547 Ynut_sB, FALSE, TRUE,
3548 EL_NUT, ACTION_FALLING, -1
3551 Ynut_e, FALSE, FALSE,
3552 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3555 Ynut_eB, FALSE, TRUE,
3556 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3559 Ynut_w, FALSE, FALSE,
3560 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3563 Ynut_wB, FALSE, TRUE,
3564 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3567 Xbug_n, TRUE, FALSE,
3571 Xbug_e, TRUE, FALSE,
3572 EL_BUG_RIGHT, -1, -1
3575 Xbug_s, TRUE, FALSE,
3579 Xbug_w, TRUE, FALSE,
3583 Xbug_gon, FALSE, FALSE,
3587 Xbug_goe, FALSE, FALSE,
3588 EL_BUG_RIGHT, -1, -1
3591 Xbug_gos, FALSE, FALSE,
3595 Xbug_gow, FALSE, FALSE,
3599 Ybug_n, FALSE, FALSE,
3600 EL_BUG, ACTION_MOVING, MV_BIT_UP
3603 Ybug_nB, FALSE, TRUE,
3604 EL_BUG, ACTION_MOVING, MV_BIT_UP
3607 Ybug_e, FALSE, FALSE,
3608 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3611 Ybug_eB, FALSE, TRUE,
3612 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3615 Ybug_s, FALSE, FALSE,
3616 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3619 Ybug_sB, FALSE, TRUE,
3620 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3623 Ybug_w, FALSE, FALSE,
3624 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3627 Ybug_wB, FALSE, TRUE,
3628 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3631 Ybug_w_n, FALSE, FALSE,
3632 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3635 Ybug_n_e, FALSE, FALSE,
3636 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3639 Ybug_e_s, FALSE, FALSE,
3640 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3643 Ybug_s_w, FALSE, FALSE,
3644 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3647 Ybug_e_n, FALSE, FALSE,
3648 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3651 Ybug_s_e, FALSE, FALSE,
3652 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3655 Ybug_w_s, FALSE, FALSE,
3656 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3659 Ybug_n_w, FALSE, FALSE,
3660 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3663 Ybug_stone, FALSE, FALSE,
3664 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3667 Ybug_spring, FALSE, FALSE,
3668 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3671 Xtank_n, TRUE, FALSE,
3672 EL_SPACESHIP_UP, -1, -1
3675 Xtank_e, TRUE, FALSE,
3676 EL_SPACESHIP_RIGHT, -1, -1
3679 Xtank_s, TRUE, FALSE,
3680 EL_SPACESHIP_DOWN, -1, -1
3683 Xtank_w, TRUE, FALSE,
3684 EL_SPACESHIP_LEFT, -1, -1
3687 Xtank_gon, FALSE, FALSE,
3688 EL_SPACESHIP_UP, -1, -1
3691 Xtank_goe, FALSE, FALSE,
3692 EL_SPACESHIP_RIGHT, -1, -1
3695 Xtank_gos, FALSE, FALSE,
3696 EL_SPACESHIP_DOWN, -1, -1
3699 Xtank_gow, FALSE, FALSE,
3700 EL_SPACESHIP_LEFT, -1, -1
3703 Ytank_n, FALSE, FALSE,
3704 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3707 Ytank_nB, FALSE, TRUE,
3708 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3711 Ytank_e, FALSE, FALSE,
3712 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3715 Ytank_eB, FALSE, TRUE,
3716 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3719 Ytank_s, FALSE, FALSE,
3720 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3723 Ytank_sB, FALSE, TRUE,
3724 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3727 Ytank_w, FALSE, FALSE,
3728 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3731 Ytank_wB, FALSE, TRUE,
3732 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3735 Ytank_w_n, FALSE, FALSE,
3736 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3739 Ytank_n_e, FALSE, FALSE,
3740 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3743 Ytank_e_s, FALSE, FALSE,
3744 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3747 Ytank_s_w, FALSE, FALSE,
3748 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3751 Ytank_e_n, FALSE, FALSE,
3752 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3755 Ytank_s_e, FALSE, FALSE,
3756 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3759 Ytank_w_s, FALSE, FALSE,
3760 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3763 Ytank_n_w, FALSE, FALSE,
3764 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3767 Ytank_stone, FALSE, FALSE,
3768 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3771 Ytank_spring, FALSE, FALSE,
3772 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3775 Xandroid, TRUE, FALSE,
3776 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3779 Xandroid_1_n, FALSE, FALSE,
3780 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3783 Xandroid_2_n, FALSE, FALSE,
3784 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3787 Xandroid_1_e, FALSE, FALSE,
3788 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3791 Xandroid_2_e, FALSE, FALSE,
3792 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3795 Xandroid_1_w, FALSE, FALSE,
3796 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3799 Xandroid_2_w, FALSE, FALSE,
3800 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3803 Xandroid_1_s, FALSE, FALSE,
3804 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3807 Xandroid_2_s, FALSE, FALSE,
3808 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3811 Yandroid_n, FALSE, FALSE,
3812 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3815 Yandroid_nB, FALSE, TRUE,
3816 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3819 Yandroid_ne, FALSE, FALSE,
3820 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3823 Yandroid_neB, FALSE, TRUE,
3824 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3827 Yandroid_e, FALSE, FALSE,
3828 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3831 Yandroid_eB, FALSE, TRUE,
3832 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3835 Yandroid_se, FALSE, FALSE,
3836 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3839 Yandroid_seB, FALSE, TRUE,
3840 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3843 Yandroid_s, FALSE, FALSE,
3844 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3847 Yandroid_sB, FALSE, TRUE,
3848 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3851 Yandroid_sw, FALSE, FALSE,
3852 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3855 Yandroid_swB, FALSE, TRUE,
3856 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3859 Yandroid_w, FALSE, FALSE,
3860 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3863 Yandroid_wB, FALSE, TRUE,
3864 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3867 Yandroid_nw, FALSE, FALSE,
3868 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3871 Yandroid_nwB, FALSE, TRUE,
3872 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3875 Xspring, TRUE, FALSE,
3879 Xspring_pause, FALSE, FALSE,
3883 Xspring_e, FALSE, FALSE,
3887 Xspring_w, FALSE, FALSE,
3891 Xspring_fall, FALSE, FALSE,
3895 Yspring_s, FALSE, FALSE,
3896 EL_SPRING, ACTION_FALLING, -1
3899 Yspring_sB, FALSE, TRUE,
3900 EL_SPRING, ACTION_FALLING, -1
3903 Yspring_e, FALSE, FALSE,
3904 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3907 Yspring_eB, FALSE, TRUE,
3908 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3911 Yspring_w, FALSE, FALSE,
3912 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3915 Yspring_wB, FALSE, TRUE,
3916 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3919 Yspring_kill_e, FALSE, FALSE,
3920 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3923 Yspring_kill_eB, FALSE, TRUE,
3924 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3927 Yspring_kill_w, FALSE, FALSE,
3928 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3931 Yspring_kill_wB, FALSE, TRUE,
3932 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3935 Xeater_n, TRUE, FALSE,
3936 EL_YAMYAM_UP, -1, -1
3939 Xeater_e, TRUE, FALSE,
3940 EL_YAMYAM_RIGHT, -1, -1
3943 Xeater_w, TRUE, FALSE,
3944 EL_YAMYAM_LEFT, -1, -1
3947 Xeater_s, TRUE, FALSE,
3948 EL_YAMYAM_DOWN, -1, -1
3951 Yeater_n, FALSE, FALSE,
3952 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3955 Yeater_nB, FALSE, TRUE,
3956 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3959 Yeater_e, FALSE, FALSE,
3960 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3963 Yeater_eB, FALSE, TRUE,
3964 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3967 Yeater_s, FALSE, FALSE,
3968 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3971 Yeater_sB, FALSE, TRUE,
3972 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3975 Yeater_w, FALSE, FALSE,
3976 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3979 Yeater_wB, FALSE, TRUE,
3980 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3983 Yeater_stone, FALSE, FALSE,
3984 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3987 Yeater_spring, FALSE, FALSE,
3988 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3991 Xalien, TRUE, FALSE,
3995 Xalien_pause, FALSE, FALSE,
3999 Yalien_n, FALSE, FALSE,
4000 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4003 Yalien_nB, FALSE, TRUE,
4004 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4007 Yalien_e, FALSE, FALSE,
4008 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4011 Yalien_eB, FALSE, TRUE,
4012 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4015 Yalien_s, FALSE, FALSE,
4016 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4019 Yalien_sB, FALSE, TRUE,
4020 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4023 Yalien_w, FALSE, FALSE,
4024 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4027 Yalien_wB, FALSE, TRUE,
4028 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4031 Yalien_stone, FALSE, FALSE,
4032 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4035 Yalien_spring, FALSE, FALSE,
4036 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4039 Xemerald, TRUE, FALSE,
4043 Xemerald_pause, FALSE, FALSE,
4047 Xemerald_fall, FALSE, FALSE,
4051 Xemerald_shine, FALSE, FALSE,
4052 EL_EMERALD, ACTION_TWINKLING, -1
4055 Yemerald_s, FALSE, FALSE,
4056 EL_EMERALD, ACTION_FALLING, -1
4059 Yemerald_sB, FALSE, TRUE,
4060 EL_EMERALD, ACTION_FALLING, -1
4063 Yemerald_e, FALSE, FALSE,
4064 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4067 Yemerald_eB, FALSE, TRUE,
4068 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4071 Yemerald_w, FALSE, FALSE,
4072 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4075 Yemerald_wB, FALSE, TRUE,
4076 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4079 Yemerald_eat, FALSE, FALSE,
4080 EL_EMERALD, ACTION_COLLECTING, -1
4083 Yemerald_stone, FALSE, FALSE,
4084 EL_NUT, ACTION_BREAKING, -1
4087 Xdiamond, TRUE, FALSE,
4091 Xdiamond_pause, FALSE, FALSE,
4095 Xdiamond_fall, FALSE, FALSE,
4099 Xdiamond_shine, FALSE, FALSE,
4100 EL_DIAMOND, ACTION_TWINKLING, -1
4103 Ydiamond_s, FALSE, FALSE,
4104 EL_DIAMOND, ACTION_FALLING, -1
4107 Ydiamond_sB, FALSE, TRUE,
4108 EL_DIAMOND, ACTION_FALLING, -1
4111 Ydiamond_e, FALSE, FALSE,
4112 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4115 Ydiamond_eB, FALSE, TRUE,
4116 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4119 Ydiamond_w, FALSE, FALSE,
4120 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4123 Ydiamond_wB, FALSE, TRUE,
4124 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4127 Ydiamond_eat, FALSE, FALSE,
4128 EL_DIAMOND, ACTION_COLLECTING, -1
4131 Ydiamond_stone, FALSE, FALSE,
4132 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4135 Xdrip_fall, TRUE, FALSE,
4136 EL_AMOEBA_DROP, -1, -1
4139 Xdrip_stretch, FALSE, FALSE,
4140 EL_AMOEBA_DROP, ACTION_FALLING, -1
4143 Xdrip_stretchB, FALSE, TRUE,
4144 EL_AMOEBA_DROP, ACTION_FALLING, -1
4147 Xdrip_eat, FALSE, FALSE,
4148 EL_AMOEBA_DROP, ACTION_GROWING, -1
4151 Ydrip_s1, FALSE, FALSE,
4152 EL_AMOEBA_DROP, ACTION_FALLING, -1
4155 Ydrip_s1B, FALSE, TRUE,
4156 EL_AMOEBA_DROP, ACTION_FALLING, -1
4159 Ydrip_s2, FALSE, FALSE,
4160 EL_AMOEBA_DROP, ACTION_FALLING, -1
4163 Ydrip_s2B, FALSE, TRUE,
4164 EL_AMOEBA_DROP, ACTION_FALLING, -1
4171 Xbomb_pause, FALSE, FALSE,
4175 Xbomb_fall, FALSE, FALSE,
4179 Ybomb_s, FALSE, FALSE,
4180 EL_BOMB, ACTION_FALLING, -1
4183 Ybomb_sB, FALSE, TRUE,
4184 EL_BOMB, ACTION_FALLING, -1
4187 Ybomb_e, FALSE, FALSE,
4188 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4191 Ybomb_eB, FALSE, TRUE,
4192 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4195 Ybomb_w, FALSE, FALSE,
4196 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4199 Ybomb_wB, FALSE, TRUE,
4200 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4203 Ybomb_eat, FALSE, FALSE,
4204 EL_BOMB, ACTION_ACTIVATING, -1
4207 Xballoon, TRUE, FALSE,
4211 Yballoon_n, FALSE, FALSE,
4212 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4215 Yballoon_nB, FALSE, TRUE,
4216 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4219 Yballoon_e, FALSE, FALSE,
4220 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4223 Yballoon_eB, FALSE, TRUE,
4224 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4227 Yballoon_s, FALSE, FALSE,
4228 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4231 Yballoon_sB, FALSE, TRUE,
4232 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4235 Yballoon_w, FALSE, FALSE,
4236 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4239 Yballoon_wB, FALSE, TRUE,
4240 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4243 Xgrass, TRUE, FALSE,
4244 EL_EMC_GRASS, -1, -1
4247 Ygrass_nB, FALSE, FALSE,
4248 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4251 Ygrass_eB, FALSE, FALSE,
4252 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4255 Ygrass_sB, FALSE, FALSE,
4256 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4259 Ygrass_wB, FALSE, FALSE,
4260 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4267 Ydirt_nB, FALSE, FALSE,
4268 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4271 Ydirt_eB, FALSE, FALSE,
4272 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4275 Ydirt_sB, FALSE, FALSE,
4276 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4279 Ydirt_wB, FALSE, FALSE,
4280 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4283 Xacid_ne, TRUE, FALSE,
4284 EL_ACID_POOL_TOPRIGHT, -1, -1
4287 Xacid_se, TRUE, FALSE,
4288 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4291 Xacid_s, TRUE, FALSE,
4292 EL_ACID_POOL_BOTTOM, -1, -1
4295 Xacid_sw, TRUE, FALSE,
4296 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4299 Xacid_nw, TRUE, FALSE,
4300 EL_ACID_POOL_TOPLEFT, -1, -1
4303 Xacid_1, TRUE, FALSE,
4307 Xacid_2, FALSE, FALSE,
4311 Xacid_3, FALSE, FALSE,
4315 Xacid_4, FALSE, FALSE,
4319 Xacid_5, FALSE, FALSE,
4323 Xacid_6, FALSE, FALSE,
4327 Xacid_7, FALSE, FALSE,
4331 Xacid_8, FALSE, FALSE,
4335 Xball_1, TRUE, FALSE,
4336 EL_EMC_MAGIC_BALL, -1, -1
4339 Xball_1B, FALSE, FALSE,
4340 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4343 Xball_2, FALSE, FALSE,
4344 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4347 Xball_2B, FALSE, FALSE,
4348 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4351 Yball_eat, FALSE, FALSE,
4352 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4355 Ykey_1_eat, FALSE, FALSE,
4356 EL_EM_KEY_1, ACTION_COLLECTING, -1
4359 Ykey_2_eat, FALSE, FALSE,
4360 EL_EM_KEY_2, ACTION_COLLECTING, -1
4363 Ykey_3_eat, FALSE, FALSE,
4364 EL_EM_KEY_3, ACTION_COLLECTING, -1
4367 Ykey_4_eat, FALSE, FALSE,
4368 EL_EM_KEY_4, ACTION_COLLECTING, -1
4371 Ykey_5_eat, FALSE, FALSE,
4372 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4375 Ykey_6_eat, FALSE, FALSE,
4376 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4379 Ykey_7_eat, FALSE, FALSE,
4380 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4383 Ykey_8_eat, FALSE, FALSE,
4384 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4387 Ylenses_eat, FALSE, FALSE,
4388 EL_EMC_LENSES, ACTION_COLLECTING, -1
4391 Ymagnify_eat, FALSE, FALSE,
4392 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4395 Ygrass_eat, FALSE, FALSE,
4396 EL_EMC_GRASS, ACTION_SNAPPING, -1
4399 Ydirt_eat, FALSE, FALSE,
4400 EL_SAND, ACTION_SNAPPING, -1
4403 Xgrow_ns, TRUE, FALSE,
4404 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4407 Ygrow_ns_eat, FALSE, FALSE,
4408 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4411 Xgrow_ew, TRUE, FALSE,
4412 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4415 Ygrow_ew_eat, FALSE, FALSE,
4416 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4419 Xwonderwall, TRUE, FALSE,
4420 EL_MAGIC_WALL, -1, -1
4423 XwonderwallB, FALSE, FALSE,
4424 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4427 Xamoeba_1, TRUE, FALSE,
4428 EL_AMOEBA_DRY, ACTION_OTHER, -1
4431 Xamoeba_2, FALSE, FALSE,
4432 EL_AMOEBA_DRY, ACTION_OTHER, -1
4435 Xamoeba_3, FALSE, FALSE,
4436 EL_AMOEBA_DRY, ACTION_OTHER, -1
4439 Xamoeba_4, FALSE, FALSE,
4440 EL_AMOEBA_DRY, ACTION_OTHER, -1
4443 Xamoeba_5, TRUE, FALSE,
4444 EL_AMOEBA_WET, ACTION_OTHER, -1
4447 Xamoeba_6, FALSE, FALSE,
4448 EL_AMOEBA_WET, ACTION_OTHER, -1
4451 Xamoeba_7, FALSE, FALSE,
4452 EL_AMOEBA_WET, ACTION_OTHER, -1
4455 Xamoeba_8, FALSE, FALSE,
4456 EL_AMOEBA_WET, ACTION_OTHER, -1
4459 Xdoor_1, TRUE, FALSE,
4460 EL_EM_GATE_1, -1, -1
4463 Xdoor_2, TRUE, FALSE,
4464 EL_EM_GATE_2, -1, -1
4467 Xdoor_3, TRUE, FALSE,
4468 EL_EM_GATE_3, -1, -1
4471 Xdoor_4, TRUE, FALSE,
4472 EL_EM_GATE_4, -1, -1
4475 Xdoor_5, TRUE, FALSE,
4476 EL_EMC_GATE_5, -1, -1
4479 Xdoor_6, TRUE, FALSE,
4480 EL_EMC_GATE_6, -1, -1
4483 Xdoor_7, TRUE, FALSE,
4484 EL_EMC_GATE_7, -1, -1
4487 Xdoor_8, TRUE, FALSE,
4488 EL_EMC_GATE_8, -1, -1
4491 Xkey_1, TRUE, FALSE,
4495 Xkey_2, TRUE, FALSE,
4499 Xkey_3, TRUE, FALSE,
4503 Xkey_4, TRUE, FALSE,
4507 Xkey_5, TRUE, FALSE,
4508 EL_EMC_KEY_5, -1, -1
4511 Xkey_6, TRUE, FALSE,
4512 EL_EMC_KEY_6, -1, -1
4515 Xkey_7, TRUE, FALSE,
4516 EL_EMC_KEY_7, -1, -1
4519 Xkey_8, TRUE, FALSE,
4520 EL_EMC_KEY_8, -1, -1
4523 Xwind_n, TRUE, FALSE,
4524 EL_BALLOON_SWITCH_UP, -1, -1
4527 Xwind_e, TRUE, FALSE,
4528 EL_BALLOON_SWITCH_RIGHT, -1, -1
4531 Xwind_s, TRUE, FALSE,
4532 EL_BALLOON_SWITCH_DOWN, -1, -1
4535 Xwind_w, TRUE, FALSE,
4536 EL_BALLOON_SWITCH_LEFT, -1, -1
4539 Xwind_nesw, TRUE, FALSE,
4540 EL_BALLOON_SWITCH_ANY, -1, -1
4543 Xwind_stop, TRUE, FALSE,
4544 EL_BALLOON_SWITCH_NONE, -1, -1
4548 EL_EM_EXIT_CLOSED, -1, -1
4551 Xexit_1, TRUE, FALSE,
4552 EL_EM_EXIT_OPEN, -1, -1
4555 Xexit_2, FALSE, FALSE,
4556 EL_EM_EXIT_OPEN, -1, -1
4559 Xexit_3, FALSE, FALSE,
4560 EL_EM_EXIT_OPEN, -1, -1
4563 Xdynamite, TRUE, FALSE,
4564 EL_EM_DYNAMITE, -1, -1
4567 Ydynamite_eat, FALSE, FALSE,
4568 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4571 Xdynamite_1, TRUE, FALSE,
4572 EL_EM_DYNAMITE_ACTIVE, -1, -1
4575 Xdynamite_2, FALSE, FALSE,
4576 EL_EM_DYNAMITE_ACTIVE, -1, -1
4579 Xdynamite_3, FALSE, FALSE,
4580 EL_EM_DYNAMITE_ACTIVE, -1, -1
4583 Xdynamite_4, FALSE, FALSE,
4584 EL_EM_DYNAMITE_ACTIVE, -1, -1
4587 Xbumper, TRUE, FALSE,
4588 EL_EMC_SPRING_BUMPER, -1, -1
4591 XbumperB, FALSE, FALSE,
4592 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4595 Xwheel, TRUE, FALSE,
4596 EL_ROBOT_WHEEL, -1, -1
4599 XwheelB, FALSE, FALSE,
4600 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4603 Xswitch, TRUE, FALSE,
4604 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4607 XswitchB, FALSE, FALSE,
4608 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4612 EL_QUICKSAND_EMPTY, -1, -1
4615 Xsand_stone, TRUE, FALSE,
4616 EL_QUICKSAND_FULL, -1, -1
4619 Xsand_stonein_1, FALSE, TRUE,
4620 EL_ROCK, ACTION_FILLING, -1
4623 Xsand_stonein_2, FALSE, TRUE,
4624 EL_ROCK, ACTION_FILLING, -1
4627 Xsand_stonein_3, FALSE, TRUE,
4628 EL_ROCK, ACTION_FILLING, -1
4631 Xsand_stonein_4, FALSE, TRUE,
4632 EL_ROCK, ACTION_FILLING, -1
4635 Xsand_stonesand_1, FALSE, FALSE,
4636 EL_QUICKSAND_FULL, -1, -1
4639 Xsand_stonesand_2, FALSE, FALSE,
4640 EL_QUICKSAND_FULL, -1, -1
4643 Xsand_stonesand_3, FALSE, FALSE,
4644 EL_QUICKSAND_FULL, -1, -1
4647 Xsand_stonesand_4, FALSE, FALSE,
4648 EL_QUICKSAND_FULL, -1, -1
4651 Xsand_stoneout_1, FALSE, FALSE,
4652 EL_ROCK, ACTION_EMPTYING, -1
4655 Xsand_stoneout_2, FALSE, FALSE,
4656 EL_ROCK, ACTION_EMPTYING, -1
4659 Xsand_sandstone_1, FALSE, FALSE,
4660 EL_QUICKSAND_FULL, -1, -1
4663 Xsand_sandstone_2, FALSE, FALSE,
4664 EL_QUICKSAND_FULL, -1, -1
4667 Xsand_sandstone_3, FALSE, FALSE,
4668 EL_QUICKSAND_FULL, -1, -1
4671 Xsand_sandstone_4, FALSE, FALSE,
4672 EL_QUICKSAND_FULL, -1, -1
4675 Xplant, TRUE, FALSE,
4676 EL_EMC_PLANT, -1, -1
4679 Yplant, FALSE, FALSE,
4680 EL_EMC_PLANT, -1, -1
4683 Xlenses, TRUE, FALSE,
4684 EL_EMC_LENSES, -1, -1
4687 Xmagnify, TRUE, FALSE,
4688 EL_EMC_MAGNIFIER, -1, -1
4691 Xdripper, TRUE, FALSE,
4692 EL_EMC_DRIPPER, -1, -1
4695 XdripperB, FALSE, FALSE,
4696 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4699 Xfake_blank, TRUE, FALSE,
4700 EL_INVISIBLE_WALL, -1, -1
4703 Xfake_blankB, FALSE, FALSE,
4704 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4707 Xfake_grass, TRUE, FALSE,
4708 EL_EMC_FAKE_GRASS, -1, -1
4711 Xfake_grassB, FALSE, FALSE,
4712 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4715 Xfake_door_1, TRUE, FALSE,
4716 EL_EM_GATE_1_GRAY, -1, -1
4719 Xfake_door_2, TRUE, FALSE,
4720 EL_EM_GATE_2_GRAY, -1, -1
4723 Xfake_door_3, TRUE, FALSE,
4724 EL_EM_GATE_3_GRAY, -1, -1
4727 Xfake_door_4, TRUE, FALSE,
4728 EL_EM_GATE_4_GRAY, -1, -1
4731 Xfake_door_5, TRUE, FALSE,
4732 EL_EMC_GATE_5_GRAY, -1, -1
4735 Xfake_door_6, TRUE, FALSE,
4736 EL_EMC_GATE_6_GRAY, -1, -1
4739 Xfake_door_7, TRUE, FALSE,
4740 EL_EMC_GATE_7_GRAY, -1, -1
4743 Xfake_door_8, TRUE, FALSE,
4744 EL_EMC_GATE_8_GRAY, -1, -1
4747 Xfake_acid_1, TRUE, FALSE,
4748 EL_EMC_FAKE_ACID, -1, -1
4751 Xfake_acid_2, FALSE, FALSE,
4752 EL_EMC_FAKE_ACID, -1, -1
4755 Xfake_acid_3, FALSE, FALSE,
4756 EL_EMC_FAKE_ACID, -1, -1
4759 Xfake_acid_4, FALSE, FALSE,
4760 EL_EMC_FAKE_ACID, -1, -1
4763 Xfake_acid_5, FALSE, FALSE,
4764 EL_EMC_FAKE_ACID, -1, -1
4767 Xfake_acid_6, FALSE, FALSE,
4768 EL_EMC_FAKE_ACID, -1, -1
4771 Xfake_acid_7, FALSE, FALSE,
4772 EL_EMC_FAKE_ACID, -1, -1
4775 Xfake_acid_8, FALSE, FALSE,
4776 EL_EMC_FAKE_ACID, -1, -1
4779 Xsteel_1, TRUE, FALSE,
4780 EL_STEELWALL, -1, -1
4783 Xsteel_2, TRUE, FALSE,
4784 EL_EMC_STEELWALL_2, -1, -1
4787 Xsteel_3, TRUE, FALSE,
4788 EL_EMC_STEELWALL_3, -1, -1
4791 Xsteel_4, TRUE, FALSE,
4792 EL_EMC_STEELWALL_4, -1, -1
4795 Xwall_1, TRUE, FALSE,
4799 Xwall_2, TRUE, FALSE,
4800 EL_EMC_WALL_14, -1, -1
4803 Xwall_3, TRUE, FALSE,
4804 EL_EMC_WALL_15, -1, -1
4807 Xwall_4, TRUE, FALSE,
4808 EL_EMC_WALL_16, -1, -1
4811 Xround_wall_1, TRUE, FALSE,
4812 EL_WALL_SLIPPERY, -1, -1
4815 Xround_wall_2, TRUE, FALSE,
4816 EL_EMC_WALL_SLIPPERY_2, -1, -1
4819 Xround_wall_3, TRUE, FALSE,
4820 EL_EMC_WALL_SLIPPERY_3, -1, -1
4823 Xround_wall_4, TRUE, FALSE,
4824 EL_EMC_WALL_SLIPPERY_4, -1, -1
4827 Xdecor_1, TRUE, FALSE,
4828 EL_EMC_WALL_8, -1, -1
4831 Xdecor_2, TRUE, FALSE,
4832 EL_EMC_WALL_6, -1, -1
4835 Xdecor_3, TRUE, FALSE,
4836 EL_EMC_WALL_4, -1, -1
4839 Xdecor_4, TRUE, FALSE,
4840 EL_EMC_WALL_7, -1, -1
4843 Xdecor_5, TRUE, FALSE,
4844 EL_EMC_WALL_5, -1, -1
4847 Xdecor_6, TRUE, FALSE,
4848 EL_EMC_WALL_9, -1, -1
4851 Xdecor_7, TRUE, FALSE,
4852 EL_EMC_WALL_10, -1, -1
4855 Xdecor_8, TRUE, FALSE,
4856 EL_EMC_WALL_1, -1, -1
4859 Xdecor_9, TRUE, FALSE,
4860 EL_EMC_WALL_2, -1, -1
4863 Xdecor_10, TRUE, FALSE,
4864 EL_EMC_WALL_3, -1, -1
4867 Xdecor_11, TRUE, FALSE,
4868 EL_EMC_WALL_11, -1, -1
4871 Xdecor_12, TRUE, FALSE,
4872 EL_EMC_WALL_12, -1, -1
4875 Xalpha_0, TRUE, FALSE,
4876 EL_CHAR('0'), -1, -1
4879 Xalpha_1, TRUE, FALSE,
4880 EL_CHAR('1'), -1, -1
4883 Xalpha_2, TRUE, FALSE,
4884 EL_CHAR('2'), -1, -1
4887 Xalpha_3, TRUE, FALSE,
4888 EL_CHAR('3'), -1, -1
4891 Xalpha_4, TRUE, FALSE,
4892 EL_CHAR('4'), -1, -1
4895 Xalpha_5, TRUE, FALSE,
4896 EL_CHAR('5'), -1, -1
4899 Xalpha_6, TRUE, FALSE,
4900 EL_CHAR('6'), -1, -1
4903 Xalpha_7, TRUE, FALSE,
4904 EL_CHAR('7'), -1, -1
4907 Xalpha_8, TRUE, FALSE,
4908 EL_CHAR('8'), -1, -1
4911 Xalpha_9, TRUE, FALSE,
4912 EL_CHAR('9'), -1, -1
4915 Xalpha_excla, TRUE, FALSE,
4916 EL_CHAR('!'), -1, -1
4919 Xalpha_quote, TRUE, FALSE,
4920 EL_CHAR('"'), -1, -1
4923 Xalpha_comma, TRUE, FALSE,
4924 EL_CHAR(','), -1, -1
4927 Xalpha_minus, TRUE, FALSE,
4928 EL_CHAR('-'), -1, -1
4931 Xalpha_perio, TRUE, FALSE,
4932 EL_CHAR('.'), -1, -1
4935 Xalpha_colon, TRUE, FALSE,
4936 EL_CHAR(':'), -1, -1
4939 Xalpha_quest, TRUE, FALSE,
4940 EL_CHAR('?'), -1, -1
4943 Xalpha_a, TRUE, FALSE,
4944 EL_CHAR('A'), -1, -1
4947 Xalpha_b, TRUE, FALSE,
4948 EL_CHAR('B'), -1, -1
4951 Xalpha_c, TRUE, FALSE,
4952 EL_CHAR('C'), -1, -1
4955 Xalpha_d, TRUE, FALSE,
4956 EL_CHAR('D'), -1, -1
4959 Xalpha_e, TRUE, FALSE,
4960 EL_CHAR('E'), -1, -1
4963 Xalpha_f, TRUE, FALSE,
4964 EL_CHAR('F'), -1, -1
4967 Xalpha_g, TRUE, FALSE,
4968 EL_CHAR('G'), -1, -1
4971 Xalpha_h, TRUE, FALSE,
4972 EL_CHAR('H'), -1, -1
4975 Xalpha_i, TRUE, FALSE,
4976 EL_CHAR('I'), -1, -1
4979 Xalpha_j, TRUE, FALSE,
4980 EL_CHAR('J'), -1, -1
4983 Xalpha_k, TRUE, FALSE,
4984 EL_CHAR('K'), -1, -1
4987 Xalpha_l, TRUE, FALSE,
4988 EL_CHAR('L'), -1, -1
4991 Xalpha_m, TRUE, FALSE,
4992 EL_CHAR('M'), -1, -1
4995 Xalpha_n, TRUE, FALSE,
4996 EL_CHAR('N'), -1, -1
4999 Xalpha_o, TRUE, FALSE,
5000 EL_CHAR('O'), -1, -1
5003 Xalpha_p, TRUE, FALSE,
5004 EL_CHAR('P'), -1, -1
5007 Xalpha_q, TRUE, FALSE,
5008 EL_CHAR('Q'), -1, -1
5011 Xalpha_r, TRUE, FALSE,
5012 EL_CHAR('R'), -1, -1
5015 Xalpha_s, TRUE, FALSE,
5016 EL_CHAR('S'), -1, -1
5019 Xalpha_t, TRUE, FALSE,
5020 EL_CHAR('T'), -1, -1
5023 Xalpha_u, TRUE, FALSE,
5024 EL_CHAR('U'), -1, -1
5027 Xalpha_v, TRUE, FALSE,
5028 EL_CHAR('V'), -1, -1
5031 Xalpha_w, TRUE, FALSE,
5032 EL_CHAR('W'), -1, -1
5035 Xalpha_x, TRUE, FALSE,
5036 EL_CHAR('X'), -1, -1
5039 Xalpha_y, TRUE, FALSE,
5040 EL_CHAR('Y'), -1, -1
5043 Xalpha_z, TRUE, FALSE,
5044 EL_CHAR('Z'), -1, -1
5047 Xalpha_arrow_e, TRUE, FALSE,
5048 EL_CHAR('>'), -1, -1
5051 Xalpha_arrow_w, TRUE, FALSE,
5052 EL_CHAR('<'), -1, -1
5055 Xalpha_copyr, TRUE, FALSE,
5056 EL_CHAR('©'), -1, -1
5060 Xboom_bug, FALSE, FALSE,
5061 EL_BUG, ACTION_EXPLODING, -1
5064 Xboom_bomb, FALSE, FALSE,
5065 EL_BOMB, ACTION_EXPLODING, -1
5068 Xboom_android, FALSE, FALSE,
5069 EL_EMC_ANDROID, ACTION_OTHER, -1
5072 Xboom_1, FALSE, FALSE,
5073 EL_DEFAULT, ACTION_EXPLODING, -1
5076 Xboom_2, FALSE, FALSE,
5077 EL_DEFAULT, ACTION_EXPLODING, -1
5080 Znormal, FALSE, FALSE,
5084 Zdynamite, FALSE, FALSE,
5088 Zplayer, FALSE, FALSE,
5092 ZBORDER, FALSE, FALSE,
5102 static struct Mapping_EM_to_RND_player
5111 em_player_mapping_list[] =
5115 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5119 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5123 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5127 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5131 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5135 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5139 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5143 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5147 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5151 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5155 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5159 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5163 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5167 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5171 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5175 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5179 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5183 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5187 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5191 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5195 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5199 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5203 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5207 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5211 EL_PLAYER_1, ACTION_DEFAULT, -1,
5215 EL_PLAYER_2, ACTION_DEFAULT, -1,
5219 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5223 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5227 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5231 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5235 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5239 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5243 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5247 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5251 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5255 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5259 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5263 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5267 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5271 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5275 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5279 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5283 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5287 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5291 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5295 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5299 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5303 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5307 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5311 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5315 EL_PLAYER_3, ACTION_DEFAULT, -1,
5319 EL_PLAYER_4, ACTION_DEFAULT, -1,
5328 int map_element_RND_to_EM(int element_rnd)
5330 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5331 static boolean mapping_initialized = FALSE;
5333 if (!mapping_initialized)
5337 /* return "Xalpha_quest" for all undefined elements in mapping array */
5338 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5339 mapping_RND_to_EM[i] = Xalpha_quest;
5341 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5342 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5343 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5344 em_object_mapping_list[i].element_em;
5346 mapping_initialized = TRUE;
5349 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5350 return mapping_RND_to_EM[element_rnd];
5352 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5357 int map_element_EM_to_RND(int element_em)
5359 static unsigned short mapping_EM_to_RND[TILE_MAX];
5360 static boolean mapping_initialized = FALSE;
5362 if (!mapping_initialized)
5366 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5367 for (i = 0; i < TILE_MAX; i++)
5368 mapping_EM_to_RND[i] = EL_UNKNOWN;
5370 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5371 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5372 em_object_mapping_list[i].element_rnd;
5374 mapping_initialized = TRUE;
5377 if (element_em >= 0 && element_em < TILE_MAX)
5378 return mapping_EM_to_RND[element_em];
5380 Error(ERR_WARN, "invalid EM level element %d", element_em);
5385 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5387 struct LevelInfo_EM *level_em = level->native_em_level;
5388 struct LEVEL *lev = level_em->lev;
5391 for (i = 0; i < TILE_MAX; i++)
5392 lev->android_array[i] = Xblank;
5394 for (i = 0; i < level->num_android_clone_elements; i++)
5396 int element_rnd = level->android_clone_element[i];
5397 int element_em = map_element_RND_to_EM(element_rnd);
5399 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5400 if (em_object_mapping_list[j].element_rnd == element_rnd)
5401 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5405 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5407 struct LevelInfo_EM *level_em = level->native_em_level;
5408 struct LEVEL *lev = level_em->lev;
5411 level->num_android_clone_elements = 0;
5413 for (i = 0; i < TILE_MAX; i++)
5415 int element_em = lev->android_array[i];
5417 boolean element_found = FALSE;
5419 if (element_em == Xblank)
5422 element_rnd = map_element_EM_to_RND(element_em);
5424 for (j = 0; j < level->num_android_clone_elements; j++)
5425 if (level->android_clone_element[j] == element_rnd)
5426 element_found = TRUE;
5430 level->android_clone_element[level->num_android_clone_elements++] =
5433 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5438 if (level->num_android_clone_elements == 0)
5440 level->num_android_clone_elements = 1;
5441 level->android_clone_element[0] = EL_EMPTY;
5445 int map_direction_RND_to_EM(int direction)
5447 return (direction == MV_UP ? 0 :
5448 direction == MV_RIGHT ? 1 :
5449 direction == MV_DOWN ? 2 :
5450 direction == MV_LEFT ? 3 :
5454 int map_direction_EM_to_RND(int direction)
5456 return (direction == 0 ? MV_UP :
5457 direction == 1 ? MV_RIGHT :
5458 direction == 2 ? MV_DOWN :
5459 direction == 3 ? MV_LEFT :
5463 int get_next_element(int element)
5467 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5468 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5469 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5470 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5471 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5472 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5473 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5474 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5475 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5476 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5477 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5479 default: return element;
5484 int el_act_dir2img(int element, int action, int direction)
5486 element = GFX_ELEMENT(element);
5488 if (direction == MV_NONE)
5489 return element_info[element].graphic[action];
5491 direction = MV_DIR_TO_BIT(direction);
5493 return element_info[element].direction_graphic[action][direction];
5496 int el_act_dir2img(int element, int action, int direction)
5498 element = GFX_ELEMENT(element);
5499 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5501 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5502 return element_info[element].direction_graphic[action][direction];
5507 static int el_act_dir2crm(int element, int action, int direction)
5509 element = GFX_ELEMENT(element);
5511 if (direction == MV_NONE)
5512 return element_info[element].crumbled[action];
5514 direction = MV_DIR_TO_BIT(direction);
5516 return element_info[element].direction_crumbled[action][direction];
5519 static int el_act_dir2crm(int element, int action, int direction)
5521 element = GFX_ELEMENT(element);
5522 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5524 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5525 return element_info[element].direction_crumbled[action][direction];
5529 int el_act2img(int element, int action)
5531 element = GFX_ELEMENT(element);
5533 return element_info[element].graphic[action];
5536 int el_act2crm(int element, int action)
5538 element = GFX_ELEMENT(element);
5540 return element_info[element].crumbled[action];
5543 int el_dir2img(int element, int direction)
5545 element = GFX_ELEMENT(element);
5547 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5550 int el2baseimg(int element)
5552 return element_info[element].graphic[ACTION_DEFAULT];
5555 int el2img(int element)
5557 element = GFX_ELEMENT(element);
5559 return element_info[element].graphic[ACTION_DEFAULT];
5562 int el2edimg(int element)
5564 element = GFX_ELEMENT(element);
5566 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5569 int el2preimg(int element)
5571 element = GFX_ELEMENT(element);
5573 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5576 int font2baseimg(int font_nr)
5578 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5581 int getBeltNrFromBeltElement(int element)
5583 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5584 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5585 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5588 int getBeltNrFromBeltActiveElement(int element)
5590 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5591 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5592 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5595 int getBeltNrFromBeltSwitchElement(int element)
5597 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5598 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5599 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5602 int getBeltDirNrFromBeltElement(int element)
5604 static int belt_base_element[4] =
5606 EL_CONVEYOR_BELT_1_LEFT,
5607 EL_CONVEYOR_BELT_2_LEFT,
5608 EL_CONVEYOR_BELT_3_LEFT,
5609 EL_CONVEYOR_BELT_4_LEFT
5612 int belt_nr = getBeltNrFromBeltElement(element);
5613 int belt_dir_nr = element - belt_base_element[belt_nr];
5615 return (belt_dir_nr % 3);
5618 int getBeltDirNrFromBeltSwitchElement(int element)
5620 static int belt_base_element[4] =
5622 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5623 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5624 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5625 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5628 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5629 int belt_dir_nr = element - belt_base_element[belt_nr];
5631 return (belt_dir_nr % 3);
5634 int getBeltDirFromBeltElement(int element)
5636 static int belt_move_dir[3] =
5643 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5645 return belt_move_dir[belt_dir_nr];
5648 int getBeltDirFromBeltSwitchElement(int element)
5650 static int belt_move_dir[3] =
5657 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5659 return belt_move_dir[belt_dir_nr];
5662 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5664 static int belt_base_element[4] =
5666 EL_CONVEYOR_BELT_1_LEFT,
5667 EL_CONVEYOR_BELT_2_LEFT,
5668 EL_CONVEYOR_BELT_3_LEFT,
5669 EL_CONVEYOR_BELT_4_LEFT
5671 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5673 return belt_base_element[belt_nr] + belt_dir_nr;
5676 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5678 static int belt_base_element[4] =
5680 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5681 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5682 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5683 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5685 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5687 return belt_base_element[belt_nr] + belt_dir_nr;
5690 int getNumActivePlayers_EM()
5692 int num_players = 0;
5698 for (i = 0; i < MAX_PLAYERS; i++)
5699 if (tape.player_participates[i])
5705 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5707 int game_frame_delay_value;
5709 game_frame_delay_value =
5710 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5711 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5714 if (tape.playing && tape.warp_forward && !tape.pausing)
5715 game_frame_delay_value = 0;
5717 return game_frame_delay_value;
5720 unsigned int InitRND(long seed)
5722 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5723 return InitEngineRandom_EM(seed);
5725 return InitEngineRandom_RND(seed);
5729 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5730 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5733 void ResetGfxAnimation_EM(int x, int y, int tile)
5738 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5739 Bitmap **src_bitmap, int *src_x, int *src_y,
5742 int element = object_mapping[tile].element_rnd;
5743 int action = object_mapping[tile].action;
5744 int direction = object_mapping[tile].direction;
5745 boolean is_backside = object_mapping[tile].is_backside;
5746 boolean action_removing = (action == ACTION_DIGGING ||
5747 action == ACTION_SNAPPING ||
5748 action == ACTION_COLLECTING);
5749 int effective_element = (frame_em > 0 ? element :
5750 is_backside ? EL_EMPTY :
5751 action_removing ? EL_EMPTY :
5753 int graphic = (direction == MV_NONE ?
5754 el_act2img(effective_element, action) :
5755 el_act_dir2img(effective_element, action, direction));
5756 struct GraphicInfo *g = &graphic_info[graphic];
5759 if (graphic_info[graphic].anim_global_sync)
5760 sync_frame = FrameCounter;
5762 sync_frame = 7 - frame_em;
5764 SetRandomAnimationValue(x, y);
5766 int frame = getAnimationFrame(g->anim_frames,
5769 g->anim_start_frame,
5772 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5775 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
5776 Bitmap **src_bitmap, int *src_x, int *src_y)
5778 int element = player_mapping[player_nr][anim].element_rnd;
5779 int action = player_mapping[player_nr][anim].action;
5780 int direction = player_mapping[player_nr][anim].direction;
5781 int graphic = (direction == MV_NONE ?
5782 el_act2img(element, action) :
5783 el_act_dir2img(element, action, direction));
5784 struct GraphicInfo *g = &graphic_info[graphic];
5787 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
5789 stored_player[player_nr].StepFrame = 7 - frame_em;
5791 sync_frame = stored_player[player_nr].Frame;
5794 printf("::: %d: %d, %d [%d]\n",
5796 stored_player[player_nr].Frame,
5797 stored_player[player_nr].StepFrame,
5801 int frame = getAnimationFrame(g->anim_frames,
5804 g->anim_start_frame,
5807 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5810 void InitGraphicInfo_EM(void)
5813 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5814 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5819 int num_em_gfx_errors = 0;
5821 if (graphic_info_em_object[0][0].bitmap == NULL)
5823 /* EM graphics not yet initialized in em_open_all() */
5828 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5831 /* always start with reliable default values */
5832 for (i = 0; i < TILE_MAX; i++)
5834 object_mapping[i].element_rnd = EL_UNKNOWN;
5835 object_mapping[i].is_backside = FALSE;
5836 object_mapping[i].action = ACTION_DEFAULT;
5837 object_mapping[i].direction = MV_NONE;
5840 /* always start with reliable default values */
5841 for (p = 0; p < MAX_PLAYERS; p++)
5843 for (i = 0; i < SPR_MAX; i++)
5845 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5846 player_mapping[p][i].action = ACTION_DEFAULT;
5847 player_mapping[p][i].direction = MV_NONE;
5851 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5853 int e = em_object_mapping_list[i].element_em;
5855 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5856 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5858 if (em_object_mapping_list[i].action != -1)
5859 object_mapping[e].action = em_object_mapping_list[i].action;
5861 if (em_object_mapping_list[i].direction != -1)
5862 object_mapping[e].direction =
5863 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5866 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5868 int a = em_player_mapping_list[i].action_em;
5869 int p = em_player_mapping_list[i].player_nr;
5871 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5873 if (em_player_mapping_list[i].action != -1)
5874 player_mapping[p][a].action = em_player_mapping_list[i].action;
5876 if (em_player_mapping_list[i].direction != -1)
5877 player_mapping[p][a].direction =
5878 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5881 for (i = 0; i < TILE_MAX; i++)
5883 int element = object_mapping[i].element_rnd;
5884 int action = object_mapping[i].action;
5885 int direction = object_mapping[i].direction;
5886 boolean is_backside = object_mapping[i].is_backside;
5887 boolean action_removing = (action == ACTION_DIGGING ||
5888 action == ACTION_SNAPPING ||
5889 action == ACTION_COLLECTING);
5890 boolean action_exploding = ((action == ACTION_EXPLODING ||
5891 action == ACTION_SMASHED_BY_ROCK ||
5892 action == ACTION_SMASHED_BY_SPRING) &&
5893 element != EL_DIAMOND);
5894 boolean action_active = (action == ACTION_ACTIVE);
5895 boolean action_other = (action == ACTION_OTHER);
5897 for (j = 0; j < 8; j++)
5899 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5900 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5902 i == Xdrip_stretch ? element :
5903 i == Xdrip_stretchB ? element :
5904 i == Ydrip_s1 ? element :
5905 i == Ydrip_s1B ? element :
5906 i == Xball_1B ? element :
5907 i == Xball_2 ? element :
5908 i == Xball_2B ? element :
5909 i == Yball_eat ? element :
5910 i == Ykey_1_eat ? element :
5911 i == Ykey_2_eat ? element :
5912 i == Ykey_3_eat ? element :
5913 i == Ykey_4_eat ? element :
5914 i == Ykey_5_eat ? element :
5915 i == Ykey_6_eat ? element :
5916 i == Ykey_7_eat ? element :
5917 i == Ykey_8_eat ? element :
5918 i == Ylenses_eat ? element :
5919 i == Ymagnify_eat ? element :
5920 i == Ygrass_eat ? element :
5921 i == Ydirt_eat ? element :
5922 i == Yemerald_stone ? EL_EMERALD :
5923 i == Ydiamond_stone ? EL_ROCK :
5924 i == Xsand_stonein_1 ? element :
5925 i == Xsand_stonein_2 ? element :
5926 i == Xsand_stonein_3 ? element :
5927 i == Xsand_stonein_4 ? element :
5928 is_backside ? EL_EMPTY :
5929 action_removing ? EL_EMPTY :
5931 int effective_action = (j < 7 ? action :
5932 i == Xdrip_stretch ? action :
5933 i == Xdrip_stretchB ? action :
5934 i == Ydrip_s1 ? action :
5935 i == Ydrip_s1B ? action :
5936 i == Xball_1B ? action :
5937 i == Xball_2 ? action :
5938 i == Xball_2B ? action :
5939 i == Yball_eat ? action :
5940 i == Ykey_1_eat ? action :
5941 i == Ykey_2_eat ? action :
5942 i == Ykey_3_eat ? action :
5943 i == Ykey_4_eat ? action :
5944 i == Ykey_5_eat ? action :
5945 i == Ykey_6_eat ? action :
5946 i == Ykey_7_eat ? action :
5947 i == Ykey_8_eat ? action :
5948 i == Ylenses_eat ? action :
5949 i == Ymagnify_eat ? action :
5950 i == Ygrass_eat ? action :
5951 i == Ydirt_eat ? action :
5952 i == Xsand_stonein_1 ? action :
5953 i == Xsand_stonein_2 ? action :
5954 i == Xsand_stonein_3 ? action :
5955 i == Xsand_stonein_4 ? action :
5956 i == Xsand_stoneout_1 ? action :
5957 i == Xsand_stoneout_2 ? action :
5958 i == Xboom_android ? ACTION_EXPLODING :
5959 action_exploding ? ACTION_EXPLODING :
5960 action_active ? action :
5961 action_other ? action :
5963 int graphic = (el_act_dir2img(effective_element, effective_action,
5965 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5967 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5968 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5969 boolean has_action_graphics = (graphic != base_graphic);
5970 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5971 struct GraphicInfo *g = &graphic_info[graphic];
5972 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5975 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5976 boolean special_animation = (action != ACTION_DEFAULT &&
5977 g->anim_frames == 3 &&
5978 g->anim_delay == 2 &&
5979 g->anim_mode & ANIM_LINEAR);
5980 int sync_frame = (i == Xdrip_stretch ? 7 :
5981 i == Xdrip_stretchB ? 7 :
5982 i == Ydrip_s2 ? j + 8 :
5983 i == Ydrip_s2B ? j + 8 :
5992 i == Xfake_acid_1 ? 0 :
5993 i == Xfake_acid_2 ? 10 :
5994 i == Xfake_acid_3 ? 20 :
5995 i == Xfake_acid_4 ? 30 :
5996 i == Xfake_acid_5 ? 40 :
5997 i == Xfake_acid_6 ? 50 :
5998 i == Xfake_acid_7 ? 60 :
5999 i == Xfake_acid_8 ? 70 :
6001 i == Xball_2B ? j + 8 :
6002 i == Yball_eat ? j + 1 :
6003 i == Ykey_1_eat ? j + 1 :
6004 i == Ykey_2_eat ? j + 1 :
6005 i == Ykey_3_eat ? j + 1 :
6006 i == Ykey_4_eat ? j + 1 :
6007 i == Ykey_5_eat ? j + 1 :
6008 i == Ykey_6_eat ? j + 1 :
6009 i == Ykey_7_eat ? j + 1 :
6010 i == Ykey_8_eat ? j + 1 :
6011 i == Ylenses_eat ? j + 1 :
6012 i == Ymagnify_eat ? j + 1 :
6013 i == Ygrass_eat ? j + 1 :
6014 i == Ydirt_eat ? j + 1 :
6015 i == Xamoeba_1 ? 0 :
6016 i == Xamoeba_2 ? 1 :
6017 i == Xamoeba_3 ? 2 :
6018 i == Xamoeba_4 ? 3 :
6019 i == Xamoeba_5 ? 0 :
6020 i == Xamoeba_6 ? 1 :
6021 i == Xamoeba_7 ? 2 :
6022 i == Xamoeba_8 ? 3 :
6023 i == Xexit_2 ? j + 8 :
6024 i == Xexit_3 ? j + 16 :
6025 i == Xdynamite_1 ? 0 :
6026 i == Xdynamite_2 ? 8 :
6027 i == Xdynamite_3 ? 16 :
6028 i == Xdynamite_4 ? 24 :
6029 i == Xsand_stonein_1 ? j + 1 :
6030 i == Xsand_stonein_2 ? j + 9 :
6031 i == Xsand_stonein_3 ? j + 17 :
6032 i == Xsand_stonein_4 ? j + 25 :
6033 i == Xsand_stoneout_1 && j == 0 ? 0 :
6034 i == Xsand_stoneout_1 && j == 1 ? 0 :
6035 i == Xsand_stoneout_1 && j == 2 ? 1 :
6036 i == Xsand_stoneout_1 && j == 3 ? 2 :
6037 i == Xsand_stoneout_1 && j == 4 ? 2 :
6038 i == Xsand_stoneout_1 && j == 5 ? 3 :
6039 i == Xsand_stoneout_1 && j == 6 ? 4 :
6040 i == Xsand_stoneout_1 && j == 7 ? 4 :
6041 i == Xsand_stoneout_2 && j == 0 ? 5 :
6042 i == Xsand_stoneout_2 && j == 1 ? 6 :
6043 i == Xsand_stoneout_2 && j == 2 ? 7 :
6044 i == Xsand_stoneout_2 && j == 3 ? 8 :
6045 i == Xsand_stoneout_2 && j == 4 ? 9 :
6046 i == Xsand_stoneout_2 && j == 5 ? 11 :
6047 i == Xsand_stoneout_2 && j == 6 ? 13 :
6048 i == Xsand_stoneout_2 && j == 7 ? 15 :
6049 i == Xboom_bug && j == 1 ? 2 :
6050 i == Xboom_bug && j == 2 ? 2 :
6051 i == Xboom_bug && j == 3 ? 4 :
6052 i == Xboom_bug && j == 4 ? 4 :
6053 i == Xboom_bug && j == 5 ? 2 :
6054 i == Xboom_bug && j == 6 ? 2 :
6055 i == Xboom_bug && j == 7 ? 0 :
6056 i == Xboom_bomb && j == 1 ? 2 :
6057 i == Xboom_bomb && j == 2 ? 2 :
6058 i == Xboom_bomb && j == 3 ? 4 :
6059 i == Xboom_bomb && j == 4 ? 4 :
6060 i == Xboom_bomb && j == 5 ? 2 :
6061 i == Xboom_bomb && j == 6 ? 2 :
6062 i == Xboom_bomb && j == 7 ? 0 :
6063 i == Xboom_android && j == 7 ? 6 :
6064 i == Xboom_1 && j == 1 ? 2 :
6065 i == Xboom_1 && j == 2 ? 2 :
6066 i == Xboom_1 && j == 3 ? 4 :
6067 i == Xboom_1 && j == 4 ? 4 :
6068 i == Xboom_1 && j == 5 ? 6 :
6069 i == Xboom_1 && j == 6 ? 6 :
6070 i == Xboom_1 && j == 7 ? 8 :
6071 i == Xboom_2 && j == 0 ? 8 :
6072 i == Xboom_2 && j == 1 ? 8 :
6073 i == Xboom_2 && j == 2 ? 10 :
6074 i == Xboom_2 && j == 3 ? 10 :
6075 i == Xboom_2 && j == 4 ? 10 :
6076 i == Xboom_2 && j == 5 ? 12 :
6077 i == Xboom_2 && j == 6 ? 12 :
6078 i == Xboom_2 && j == 7 ? 12 :
6079 special_animation && j == 4 ? 3 :
6080 effective_action != action ? 0 :
6084 Bitmap *debug_bitmap = g_em->bitmap;
6085 int debug_src_x = g_em->src_x;
6086 int debug_src_y = g_em->src_y;
6089 int frame = getAnimationFrame(g->anim_frames,
6092 g->anim_start_frame,
6095 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6096 g->double_movement && is_backside);
6098 g_em->bitmap = src_bitmap;
6099 g_em->src_x = src_x;
6100 g_em->src_y = src_y;
6101 g_em->src_offset_x = 0;
6102 g_em->src_offset_y = 0;
6103 g_em->dst_offset_x = 0;
6104 g_em->dst_offset_y = 0;
6105 g_em->width = TILEX;
6106 g_em->height = TILEY;
6108 g_em->crumbled_bitmap = NULL;
6109 g_em->crumbled_src_x = 0;
6110 g_em->crumbled_src_y = 0;
6111 g_em->crumbled_border_size = 0;
6113 g_em->has_crumbled_graphics = FALSE;
6114 g_em->preserve_background = FALSE;
6117 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6118 printf("::: empty crumbled: %d [%s], %d, %d\n",
6119 effective_element, element_info[effective_element].token_name,
6120 effective_action, direction);
6123 /* if element can be crumbled, but certain action graphics are just empty
6124 space (like snapping sand with the original R'n'D graphics), do not
6125 treat these empty space graphics as crumbled graphics in EMC engine */
6126 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6128 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6130 g_em->has_crumbled_graphics = TRUE;
6131 g_em->crumbled_bitmap = src_bitmap;
6132 g_em->crumbled_src_x = src_x;
6133 g_em->crumbled_src_y = src_y;
6134 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6138 if (element == EL_ROCK &&
6139 effective_action == ACTION_FILLING)
6140 printf("::: has_action_graphics == %d\n", has_action_graphics);
6143 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6144 effective_action == ACTION_MOVING ||
6145 effective_action == ACTION_PUSHING ||
6146 effective_action == ACTION_EATING)) ||
6147 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6148 effective_action == ACTION_EMPTYING)))
6151 (effective_action == ACTION_FALLING ||
6152 effective_action == ACTION_FILLING ||
6153 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6154 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6155 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6156 int num_steps = (i == Ydrip_s1 ? 16 :
6157 i == Ydrip_s1B ? 16 :
6158 i == Ydrip_s2 ? 16 :
6159 i == Ydrip_s2B ? 16 :
6160 i == Xsand_stonein_1 ? 32 :
6161 i == Xsand_stonein_2 ? 32 :
6162 i == Xsand_stonein_3 ? 32 :
6163 i == Xsand_stonein_4 ? 32 :
6164 i == Xsand_stoneout_1 ? 16 :
6165 i == Xsand_stoneout_2 ? 16 : 8);
6166 int cx = ABS(dx) * (TILEX / num_steps);
6167 int cy = ABS(dy) * (TILEY / num_steps);
6168 int step_frame = (i == Ydrip_s2 ? j + 8 :
6169 i == Ydrip_s2B ? j + 8 :
6170 i == Xsand_stonein_2 ? j + 8 :
6171 i == Xsand_stonein_3 ? j + 16 :
6172 i == Xsand_stonein_4 ? j + 24 :
6173 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6174 int step = (is_backside ? step_frame : num_steps - step_frame);
6176 if (is_backside) /* tile where movement starts */
6178 if (dx < 0 || dy < 0)
6180 g_em->src_offset_x = cx * step;
6181 g_em->src_offset_y = cy * step;
6185 g_em->dst_offset_x = cx * step;
6186 g_em->dst_offset_y = cy * step;
6189 else /* tile where movement ends */
6191 if (dx < 0 || dy < 0)
6193 g_em->dst_offset_x = cx * step;
6194 g_em->dst_offset_y = cy * step;
6198 g_em->src_offset_x = cx * step;
6199 g_em->src_offset_y = cy * step;
6203 g_em->width = TILEX - cx * step;
6204 g_em->height = TILEY - cy * step;
6207 /* create unique graphic identifier to decide if tile must be redrawn */
6208 /* bit 31 - 16 (16 bit): EM style graphic
6209 bit 15 - 12 ( 4 bit): EM style frame
6210 bit 11 - 6 ( 6 bit): graphic width
6211 bit 5 - 0 ( 6 bit): graphic height */
6212 g_em->unique_identifier =
6213 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6217 /* skip check for EMC elements not contained in original EMC artwork */
6218 if (element == EL_EMC_FAKE_ACID)
6221 if (g_em->bitmap != debug_bitmap ||
6222 g_em->src_x != debug_src_x ||
6223 g_em->src_y != debug_src_y ||
6224 g_em->src_offset_x != 0 ||
6225 g_em->src_offset_y != 0 ||
6226 g_em->dst_offset_x != 0 ||
6227 g_em->dst_offset_y != 0 ||
6228 g_em->width != TILEX ||
6229 g_em->height != TILEY)
6231 static int last_i = -1;
6239 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6240 i, element, element_info[element].token_name,
6241 element_action_info[effective_action].suffix, direction);
6243 if (element != effective_element)
6244 printf(" [%d ('%s')]",
6246 element_info[effective_element].token_name);
6250 if (g_em->bitmap != debug_bitmap)
6251 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6252 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6254 if (g_em->src_x != debug_src_x ||
6255 g_em->src_y != debug_src_y)
6256 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6257 j, (is_backside ? 'B' : 'F'),
6258 g_em->src_x, g_em->src_y,
6259 g_em->src_x / 32, g_em->src_y / 32,
6260 debug_src_x, debug_src_y,
6261 debug_src_x / 32, debug_src_y / 32);
6263 if (g_em->src_offset_x != 0 ||
6264 g_em->src_offset_y != 0 ||
6265 g_em->dst_offset_x != 0 ||
6266 g_em->dst_offset_y != 0)
6267 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6269 g_em->src_offset_x, g_em->src_offset_y,
6270 g_em->dst_offset_x, g_em->dst_offset_y);
6272 if (g_em->width != TILEX ||
6273 g_em->height != TILEY)
6274 printf(" %d (%d): size %d,%d should be %d,%d\n",
6276 g_em->width, g_em->height, TILEX, TILEY);
6278 num_em_gfx_errors++;
6285 for (i = 0; i < TILE_MAX; i++)
6287 for (j = 0; j < 8; j++)
6289 int element = object_mapping[i].element_rnd;
6290 int action = object_mapping[i].action;
6291 int direction = object_mapping[i].direction;
6292 boolean is_backside = object_mapping[i].is_backside;
6293 int graphic_action = el_act_dir2img(element, action, direction);
6294 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6296 if ((action == ACTION_SMASHED_BY_ROCK ||
6297 action == ACTION_SMASHED_BY_SPRING ||
6298 action == ACTION_EATING) &&
6299 graphic_action == graphic_default)
6301 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6302 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6303 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6304 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6307 /* no separate animation for "smashed by rock" -- use rock instead */
6308 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6309 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6311 g_em->bitmap = g_xx->bitmap;
6312 g_em->src_x = g_xx->src_x;
6313 g_em->src_y = g_xx->src_y;
6314 g_em->src_offset_x = g_xx->src_offset_x;
6315 g_em->src_offset_y = g_xx->src_offset_y;
6316 g_em->dst_offset_x = g_xx->dst_offset_x;
6317 g_em->dst_offset_y = g_xx->dst_offset_y;
6318 g_em->width = g_xx->width;
6319 g_em->height = g_xx->height;
6320 g_em->unique_identifier = g_xx->unique_identifier;
6323 g_em->preserve_background = TRUE;
6328 for (p = 0; p < MAX_PLAYERS; p++)
6330 for (i = 0; i < SPR_MAX; i++)
6332 int element = player_mapping[p][i].element_rnd;
6333 int action = player_mapping[p][i].action;
6334 int direction = player_mapping[p][i].direction;
6336 for (j = 0; j < 8; j++)
6338 int effective_element = element;
6339 int effective_action = action;
6340 int graphic = (direction == MV_NONE ?
6341 el_act2img(effective_element, effective_action) :
6342 el_act_dir2img(effective_element, effective_action,
6344 struct GraphicInfo *g = &graphic_info[graphic];
6345 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6351 Bitmap *debug_bitmap = g_em->bitmap;
6352 int debug_src_x = g_em->src_x;
6353 int debug_src_y = g_em->src_y;
6356 int frame = getAnimationFrame(g->anim_frames,
6359 g->anim_start_frame,
6362 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6364 g_em->bitmap = src_bitmap;
6365 g_em->src_x = src_x;
6366 g_em->src_y = src_y;
6367 g_em->src_offset_x = 0;
6368 g_em->src_offset_y = 0;
6369 g_em->dst_offset_x = 0;
6370 g_em->dst_offset_y = 0;
6371 g_em->width = TILEX;
6372 g_em->height = TILEY;
6376 /* skip check for EMC elements not contained in original EMC artwork */
6377 if (element == EL_PLAYER_3 ||
6378 element == EL_PLAYER_4)
6381 if (g_em->bitmap != debug_bitmap ||
6382 g_em->src_x != debug_src_x ||
6383 g_em->src_y != debug_src_y)
6385 static int last_i = -1;
6393 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6394 p, i, element, element_info[element].token_name,
6395 element_action_info[effective_action].suffix, direction);
6397 if (element != effective_element)
6398 printf(" [%d ('%s')]",
6400 element_info[effective_element].token_name);
6404 if (g_em->bitmap != debug_bitmap)
6405 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6406 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6408 if (g_em->src_x != debug_src_x ||
6409 g_em->src_y != debug_src_y)
6410 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6412 g_em->src_x, g_em->src_y,
6413 g_em->src_x / 32, g_em->src_y / 32,
6414 debug_src_x, debug_src_y,
6415 debug_src_x / 32, debug_src_y / 32);
6417 num_em_gfx_errors++;
6427 printf("::: [%d errors found]\n", num_em_gfx_errors);
6433 void PlayMenuSound()
6435 int sound = menu.sound[game_status];
6437 if (sound == SND_UNDEFINED)
6440 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6441 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6444 if (IS_LOOP_SOUND(sound))
6445 PlaySoundLoop(sound);
6450 void PlayMenuSoundStereo(int sound, int stereo_position)
6452 if (sound == SND_UNDEFINED)
6455 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6456 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6459 if (IS_LOOP_SOUND(sound))
6460 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6462 PlaySoundStereo(sound, stereo_position);
6465 void PlayMenuSoundIfLoop()
6467 int sound = menu.sound[game_status];
6469 if (sound == SND_UNDEFINED)
6472 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6473 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6476 if (IS_LOOP_SOUND(sound))
6477 PlaySoundLoop(sound);
6480 void PlayMenuMusic()
6482 int music = menu.music[game_status];
6484 if (music == MUS_UNDEFINED)
6487 if (!setup.sound_music)
6493 void PlaySoundActivating()
6496 PlaySound(SND_MENU_ITEM_ACTIVATING);
6500 void PlaySoundSelecting()
6503 PlaySound(SND_MENU_ITEM_SELECTING);
6507 void ToggleFullscreenIfNeeded()
6509 boolean change_fullscreen = (setup.fullscreen !=
6510 video.fullscreen_enabled);
6511 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6512 !strEqual(setup.fullscreen_mode,
6513 video.fullscreen_mode_current));
6515 if (!video.fullscreen_available)
6519 if (change_fullscreen || change_fullscreen_mode)
6521 if (setup.fullscreen != video.fullscreen_enabled ||
6522 setup.fullscreen_mode != video.fullscreen_mode_current)
6525 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6527 /* save backbuffer content which gets lost when toggling fullscreen mode */
6528 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6531 if (change_fullscreen_mode)
6533 if (setup.fullscreen && video.fullscreen_enabled)
6536 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6538 /* (this is now set in sdl.c) */
6540 video.fullscreen_mode_current = setup.fullscreen_mode;
6542 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6545 /* toggle fullscreen */
6546 ChangeVideoModeIfNeeded(setup.fullscreen);
6548 setup.fullscreen = video.fullscreen_enabled;
6550 /* restore backbuffer content from temporary backbuffer backup bitmap */
6551 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6553 FreeBitmap(tmp_backbuffer);
6556 /* update visible window/screen */
6557 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6559 redraw_mask = REDRAW_ALL;