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 SetMainBackgroundImage(int graphic)
605 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
606 graphic_info[graphic].bitmap ?
607 graphic_info[graphic].bitmap :
608 graphic_info[IMG_BACKGROUND].bitmap);
611 void SetDoorBackgroundImage(int graphic)
613 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
614 graphic_info[graphic].bitmap ?
615 graphic_info[graphic].bitmap :
616 graphic_info[IMG_BACKGROUND].bitmap);
619 void SetPanelBackground()
621 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
622 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
624 SetDoorBackgroundBitmap(bitmap_db_panel);
627 void DrawBackground(int x, int y, int width, int height)
629 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
630 /* (when entering hall of fame after playing) */
632 ClearRectangleOnBackground(drawto, x, y, width, height);
634 ClearRectangleOnBackground(backbuffer, x, y, width, height);
637 redraw_mask |= REDRAW_FIELD;
640 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
642 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
644 if (font->bitmap == NULL)
647 DrawBackground(x, y, width, height);
650 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
652 struct GraphicInfo *g = &graphic_info[graphic];
654 if (g->bitmap == NULL)
657 DrawBackground(x, y, width, height);
662 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
663 /* (when entering hall of fame after playing) */
664 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
666 /* !!! maybe this should be done before clearing the background !!! */
667 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
669 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
670 SetDrawtoField(DRAW_BUFFERED);
673 SetDrawtoField(DRAW_BACKBUFFER);
675 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
677 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
678 SetDrawtoField(DRAW_DIRECT);
682 void MarkTileDirty(int x, int y)
684 int xx = redraw_x1 + x;
685 int yy = redraw_y1 + y;
690 redraw[xx][yy] = TRUE;
691 redraw_mask |= REDRAW_TILES;
694 void SetBorderElement()
698 BorderElement = EL_EMPTY;
700 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
702 for (x = 0; x < lev_fieldx; x++)
704 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
705 BorderElement = EL_STEELWALL;
707 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
713 void FloodFillLevel(int from_x, int from_y, int fill_element,
714 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
715 int max_fieldx, int max_fieldy)
719 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
720 static int safety = 0;
722 /* check if starting field still has the desired content */
723 if (field[from_x][from_y] == fill_element)
728 if (safety > max_fieldx * max_fieldy)
729 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
731 old_element = field[from_x][from_y];
732 field[from_x][from_y] = fill_element;
734 for (i = 0; i < 4; i++)
736 x = from_x + check[i][0];
737 y = from_y + check[i][1];
739 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
740 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
746 void SetRandomAnimationValue(int x, int y)
748 gfx.anim_random_frame = GfxRandom[x][y];
751 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
753 /* animation synchronized with global frame counter, not move position */
754 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
755 sync_frame = FrameCounter;
757 return getAnimationFrame(graphic_info[graphic].anim_frames,
758 graphic_info[graphic].anim_delay,
759 graphic_info[graphic].anim_mode,
760 graphic_info[graphic].anim_start_frame,
764 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
765 int *x, int *y, boolean get_backside)
767 struct GraphicInfo *g = &graphic_info[graphic];
768 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
769 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
773 if (g->offset_y == 0) /* frames are ordered horizontally */
775 int max_width = g->anim_frames_per_line * g->width;
776 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
778 *x = pos % max_width;
779 *y = src_y % g->height + pos / max_width * g->height;
781 else if (g->offset_x == 0) /* frames are ordered vertically */
783 int max_height = g->anim_frames_per_line * g->height;
784 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
786 *x = src_x % g->width + pos / max_height * g->width;
787 *y = pos % max_height;
789 else /* frames are ordered diagonally */
791 *x = src_x + frame * g->offset_x;
792 *y = src_y + frame * g->offset_y;
796 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
798 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
801 void DrawGraphic(int x, int y, int graphic, int frame)
804 if (!IN_SCR_FIELD(x, y))
806 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
807 printf("DrawGraphic(): This should never happen!\n");
812 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
816 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
822 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
823 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
826 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
829 if (!IN_SCR_FIELD(x, y))
831 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
832 printf("DrawGraphicThruMask(): This should never happen!\n");
837 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
842 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
848 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
850 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
851 dst_x - src_x, dst_y - src_y);
852 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
855 void DrawMiniGraphic(int x, int y, int graphic)
857 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
858 MarkTileDirty(x / 2, y / 2);
861 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
863 struct GraphicInfo *g = &graphic_info[graphic];
865 int mini_starty = g->bitmap->height * 2 / 3;
868 *x = mini_startx + g->src_x / 2;
869 *y = mini_starty + g->src_y / 2;
872 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
877 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
878 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
881 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
882 int graphic, int frame,
883 int cut_mode, int mask_mode)
888 int width = TILEX, height = TILEY;
891 if (dx || dy) /* shifted graphic */
893 if (x < BX1) /* object enters playfield from the left */
900 else if (x > BX2) /* object enters playfield from the right */
906 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
912 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
914 else if (dx) /* general horizontal movement */
915 MarkTileDirty(x + SIGN(dx), y);
917 if (y < BY1) /* object enters playfield from the top */
919 if (cut_mode==CUT_BELOW) /* object completely above top border */
927 else if (y > BY2) /* object enters playfield from the bottom */
933 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
939 else if (dy > 0 && cut_mode == CUT_ABOVE)
941 if (y == BY2) /* object completely above bottom border */
947 MarkTileDirty(x, y + 1);
948 } /* object leaves playfield to the bottom */
949 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
951 else if (dy) /* general vertical movement */
952 MarkTileDirty(x, y + SIGN(dy));
956 if (!IN_SCR_FIELD(x, y))
958 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
959 printf("DrawGraphicShifted(): This should never happen!\n");
964 if (width > 0 && height > 0)
966 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
971 dst_x = FX + x * TILEX + dx;
972 dst_y = FY + y * TILEY + dy;
974 if (mask_mode == USE_MASKING)
976 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
977 dst_x - src_x, dst_y - src_y);
978 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
982 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
989 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
990 int graphic, int frame,
991 int cut_mode, int mask_mode)
996 int width = TILEX, height = TILEY;
999 int x2 = x + SIGN(dx);
1000 int y2 = y + SIGN(dy);
1001 int anim_frames = graphic_info[graphic].anim_frames;
1002 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1003 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1004 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1006 /* re-calculate animation frame for two-tile movement animation */
1007 frame = getGraphicAnimationFrame(graphic, sync_frame);
1009 /* check if movement start graphic inside screen area and should be drawn */
1010 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1012 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1014 dst_x = FX + x1 * TILEX;
1015 dst_y = FY + y1 * TILEY;
1017 if (mask_mode == USE_MASKING)
1019 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1020 dst_x - src_x, dst_y - src_y);
1021 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1025 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1028 MarkTileDirty(x1, y1);
1031 /* check if movement end graphic inside screen area and should be drawn */
1032 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1034 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1036 dst_x = FX + x2 * TILEX;
1037 dst_y = FY + y2 * TILEY;
1039 if (mask_mode == USE_MASKING)
1041 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1042 dst_x - src_x, dst_y - src_y);
1043 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1047 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1050 MarkTileDirty(x2, y2);
1054 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1055 int graphic, int frame,
1056 int cut_mode, int mask_mode)
1060 DrawGraphic(x, y, graphic, frame);
1065 if (graphic_info[graphic].double_movement) /* EM style movement images */
1066 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1068 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1071 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1072 int frame, int cut_mode)
1074 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1077 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1078 int cut_mode, int mask_mode)
1080 int lx = LEVELX(x), ly = LEVELY(y);
1084 if (IN_LEV_FIELD(lx, ly))
1086 SetRandomAnimationValue(lx, ly);
1088 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1089 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1091 /* do not use double (EM style) movement graphic when not moving */
1092 if (graphic_info[graphic].double_movement && !dx && !dy)
1094 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1095 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1098 else /* border element */
1100 graphic = el2img(element);
1101 frame = getGraphicAnimationFrame(graphic, -1);
1104 if (element == EL_EXPANDABLE_WALL)
1106 boolean left_stopped = FALSE, right_stopped = FALSE;
1108 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1109 left_stopped = TRUE;
1110 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1111 right_stopped = TRUE;
1113 if (left_stopped && right_stopped)
1115 else if (left_stopped)
1117 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1118 frame = graphic_info[graphic].anim_frames - 1;
1120 else if (right_stopped)
1122 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1123 frame = graphic_info[graphic].anim_frames - 1;
1128 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1129 else if (mask_mode == USE_MASKING)
1130 DrawGraphicThruMask(x, y, graphic, frame);
1132 DrawGraphic(x, y, graphic, frame);
1135 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1136 int cut_mode, int mask_mode)
1138 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1139 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1140 cut_mode, mask_mode);
1143 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1146 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1149 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1152 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1155 void DrawLevelElementThruMask(int x, int y, int element)
1157 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1160 void DrawLevelFieldThruMask(int x, int y)
1162 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1165 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1169 int sx = SCREENX(x), sy = SCREENY(y);
1171 int width, height, cx, cy, i;
1172 int crumbled_border_size = graphic_info[graphic].border_size;
1173 static int xy[4][2] =
1181 if (!IN_LEV_FIELD(x, y))
1184 element = TILE_GFX_ELEMENT(x, y);
1186 /* crumble field itself */
1187 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1189 if (!IN_SCR_FIELD(sx, sy))
1192 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1194 for (i = 0; i < 4; i++)
1196 int xx = x + xy[i][0];
1197 int yy = y + xy[i][1];
1199 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1202 /* check if neighbour field is of same type */
1203 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1206 if (i == 1 || i == 2)
1208 width = crumbled_border_size;
1210 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1216 height = crumbled_border_size;
1218 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1221 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1222 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1225 MarkTileDirty(sx, sy);
1227 else /* crumble neighbour fields */
1229 for (i = 0; i < 4; i++)
1231 int xx = x + xy[i][0];
1232 int yy = y + xy[i][1];
1233 int sxx = sx + xy[i][0];
1234 int syy = sy + xy[i][1];
1236 if (!IN_LEV_FIELD(xx, yy) ||
1237 !IN_SCR_FIELD(sxx, syy) ||
1241 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1244 element = TILE_GFX_ELEMENT(xx, yy);
1246 if (!GFX_CRUMBLED(element))
1249 graphic = el_act2crm(element, ACTION_DEFAULT);
1250 crumbled_border_size = graphic_info[graphic].border_size;
1252 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1254 if (i == 1 || i == 2)
1256 width = crumbled_border_size;
1258 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1264 height = crumbled_border_size;
1266 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1269 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1270 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1272 MarkTileDirty(sxx, syy);
1277 void DrawLevelFieldCrumbledSand(int x, int y)
1281 if (!IN_LEV_FIELD(x, y))
1285 /* !!! CHECK THIS !!! */
1288 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1289 GFX_CRUMBLED(GfxElement[x][y]))
1292 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1293 GfxElement[x][y] != EL_UNDEFINED &&
1294 GFX_CRUMBLED(GfxElement[x][y]))
1296 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1303 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1305 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1308 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1311 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1314 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1315 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1316 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1317 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1318 int sx = SCREENX(x), sy = SCREENY(y);
1320 DrawGraphic(sx, sy, graphic1, frame1);
1321 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1324 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1326 int sx = SCREENX(x), sy = SCREENY(y);
1327 static int xy[4][2] =
1336 for (i = 0; i < 4; i++)
1338 int xx = x + xy[i][0];
1339 int yy = y + xy[i][1];
1340 int sxx = sx + xy[i][0];
1341 int syy = sy + xy[i][1];
1343 if (!IN_LEV_FIELD(xx, yy) ||
1344 !IN_SCR_FIELD(sxx, syy) ||
1345 !GFX_CRUMBLED(Feld[xx][yy]) ||
1349 DrawLevelField(xx, yy);
1353 static int getBorderElement(int x, int y)
1357 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1358 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1359 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1360 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1361 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1362 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1363 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1365 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1366 int steel_position = (x == -1 && y == -1 ? 0 :
1367 x == lev_fieldx && y == -1 ? 1 :
1368 x == -1 && y == lev_fieldy ? 2 :
1369 x == lev_fieldx && y == lev_fieldy ? 3 :
1370 x == -1 || x == lev_fieldx ? 4 :
1371 y == -1 || y == lev_fieldy ? 5 : 6);
1373 return border[steel_position][steel_type];
1376 void DrawScreenElement(int x, int y, int element)
1378 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1379 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1382 void DrawLevelElement(int x, int y, int element)
1384 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1385 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1388 void DrawScreenField(int x, int y)
1390 int lx = LEVELX(x), ly = LEVELY(y);
1391 int element, content;
1393 if (!IN_LEV_FIELD(lx, ly))
1395 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1398 element = getBorderElement(lx, ly);
1400 DrawScreenElement(x, y, element);
1404 element = Feld[lx][ly];
1405 content = Store[lx][ly];
1407 if (IS_MOVING(lx, ly))
1409 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1410 boolean cut_mode = NO_CUTTING;
1412 if (element == EL_QUICKSAND_EMPTYING ||
1413 element == EL_QUICKSAND_FAST_EMPTYING ||
1414 element == EL_MAGIC_WALL_EMPTYING ||
1415 element == EL_BD_MAGIC_WALL_EMPTYING ||
1416 element == EL_DC_MAGIC_WALL_EMPTYING ||
1417 element == EL_AMOEBA_DROPPING)
1418 cut_mode = CUT_ABOVE;
1419 else if (element == EL_QUICKSAND_FILLING ||
1420 element == EL_QUICKSAND_FAST_FILLING ||
1421 element == EL_MAGIC_WALL_FILLING ||
1422 element == EL_BD_MAGIC_WALL_FILLING ||
1423 element == EL_DC_MAGIC_WALL_FILLING)
1424 cut_mode = CUT_BELOW;
1426 if (cut_mode == CUT_ABOVE)
1427 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1429 DrawScreenElement(x, y, EL_EMPTY);
1432 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1433 else if (cut_mode == NO_CUTTING)
1434 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1436 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1438 if (content == EL_ACID)
1440 int dir = MovDir[lx][ly];
1441 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1442 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1444 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1447 else if (IS_BLOCKED(lx, ly))
1452 boolean cut_mode = NO_CUTTING;
1453 int element_old, content_old;
1455 Blocked2Moving(lx, ly, &oldx, &oldy);
1458 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1459 MovDir[oldx][oldy] == MV_RIGHT);
1461 element_old = Feld[oldx][oldy];
1462 content_old = Store[oldx][oldy];
1464 if (element_old == EL_QUICKSAND_EMPTYING ||
1465 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1466 element_old == EL_MAGIC_WALL_EMPTYING ||
1467 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1468 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1469 element_old == EL_AMOEBA_DROPPING)
1470 cut_mode = CUT_ABOVE;
1472 DrawScreenElement(x, y, EL_EMPTY);
1475 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1477 else if (cut_mode == NO_CUTTING)
1478 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1481 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1484 else if (IS_DRAWABLE(element))
1485 DrawScreenElement(x, y, element);
1487 DrawScreenElement(x, y, EL_EMPTY);
1490 void DrawLevelField(int x, int y)
1492 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1493 DrawScreenField(SCREENX(x), SCREENY(y));
1494 else if (IS_MOVING(x, y))
1498 Moving2Blocked(x, y, &newx, &newy);
1499 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1500 DrawScreenField(SCREENX(newx), SCREENY(newy));
1502 else if (IS_BLOCKED(x, y))
1506 Blocked2Moving(x, y, &oldx, &oldy);
1507 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1508 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1512 void DrawMiniElement(int x, int y, int element)
1516 graphic = el2edimg(element);
1517 DrawMiniGraphic(x, y, graphic);
1520 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1522 int x = sx + scroll_x, y = sy + scroll_y;
1524 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1525 DrawMiniElement(sx, sy, EL_EMPTY);
1526 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1527 DrawMiniElement(sx, sy, Feld[x][y]);
1529 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1532 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1533 int x, int y, int xsize, int ysize, int font_nr)
1535 int font_width = getFontWidth(font_nr);
1536 int font_height = getFontHeight(font_nr);
1537 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1540 int dst_x = SX + startx + x * font_width;
1541 int dst_y = SY + starty + y * font_height;
1542 int width = graphic_info[graphic].width;
1543 int height = graphic_info[graphic].height;
1544 int inner_width = MAX(width - 2 * font_width, font_width);
1545 int inner_height = MAX(height - 2 * font_height, font_height);
1546 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1547 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1548 boolean draw_masked = graphic_info[graphic].draw_masked;
1550 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1552 if (src_bitmap == NULL || width < font_width || height < font_height)
1554 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1558 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1559 inner_sx + (x - 1) * font_width % inner_width);
1560 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1561 inner_sy + (y - 1) * font_height % inner_height);
1565 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1566 dst_x - src_x, dst_y - src_y);
1567 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1571 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1575 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1577 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1578 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1579 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1580 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1581 boolean no_delay = (tape.warp_forward);
1582 unsigned long anim_delay = 0;
1583 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1584 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1585 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1586 int font_width = getFontWidth(font_nr);
1587 int font_height = getFontHeight(font_nr);
1588 int max_xsize = level.envelope[envelope_nr].xsize;
1589 int max_ysize = level.envelope[envelope_nr].ysize;
1590 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1591 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1592 int xend = max_xsize;
1593 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1594 int xstep = (xstart < xend ? 1 : 0);
1595 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1598 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1600 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1601 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1602 int sx = (SXSIZE - xsize * font_width) / 2;
1603 int sy = (SYSIZE - ysize * font_height) / 2;
1606 SetDrawtoField(DRAW_BUFFERED);
1608 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1610 SetDrawtoField(DRAW_BACKBUFFER);
1612 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1613 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1616 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1617 level.envelope[envelope_nr].text, font_nr, max_xsize,
1618 xsize - 2, ysize - 2, mask_mode,
1619 level.envelope[envelope_nr].autowrap,
1620 level.envelope[envelope_nr].centered);
1622 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1623 level.envelope[envelope_nr].text, font_nr, max_xsize,
1624 xsize - 2, ysize - 2, mask_mode);
1627 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1630 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1634 void ShowEnvelope(int envelope_nr)
1636 int element = EL_ENVELOPE_1 + envelope_nr;
1637 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1638 int sound_opening = element_info[element].sound[ACTION_OPENING];
1639 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1640 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1641 boolean no_delay = (tape.warp_forward);
1642 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1643 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1644 int anim_mode = graphic_info[graphic].anim_mode;
1645 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1646 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1648 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1650 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1652 if (anim_mode == ANIM_DEFAULT)
1653 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1655 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1658 Delay(wait_delay_value);
1660 WaitForEventToContinue();
1662 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1664 if (anim_mode != ANIM_NONE)
1665 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1667 if (anim_mode == ANIM_DEFAULT)
1668 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1670 game.envelope_active = FALSE;
1672 SetDrawtoField(DRAW_BUFFERED);
1674 redraw_mask |= REDRAW_FIELD;
1678 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1683 int width_mult, width_div;
1684 int height_mult, height_div;
1692 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1693 5 - log_2(tilesize));
1694 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1695 int width_mult = offset_calc[offset_calc_pos].width_mult;
1696 int width_div = offset_calc[offset_calc_pos].width_div;
1697 int height_mult = offset_calc[offset_calc_pos].height_mult;
1698 int height_div = offset_calc[offset_calc_pos].height_div;
1699 int mini_startx = src_bitmap->width * width_mult / width_div;
1700 int mini_starty = src_bitmap->height * height_mult / height_div;
1701 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1702 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1704 *bitmap = src_bitmap;
1709 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1713 int graphic = el2preimg(element);
1715 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1716 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1723 SetDrawBackgroundMask(REDRAW_NONE);
1726 for (x = BX1; x <= BX2; x++)
1727 for (y = BY1; y <= BY2; y++)
1728 DrawScreenField(x, y);
1730 redraw_mask |= REDRAW_FIELD;
1733 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1737 for (x = 0; x < size_x; x++)
1738 for (y = 0; y < size_y; y++)
1739 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1741 redraw_mask |= REDRAW_FIELD;
1744 static void DrawPreviewLevelExt(int from_x, int from_y)
1746 boolean show_level_border = (BorderElement != EL_EMPTY);
1747 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1748 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1749 int tile_size = preview.tile_size;
1750 int preview_width = preview.xsize * tile_size;
1751 int preview_height = preview.ysize * tile_size;
1752 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1753 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1754 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1755 int dst_y = SY + preview.y;
1758 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1760 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1761 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1763 for (x = 0; x < real_preview_xsize; x++)
1765 for (y = 0; y < real_preview_ysize; y++)
1767 int lx = from_x + x + (show_level_border ? -1 : 0);
1768 int ly = from_y + y + (show_level_border ? -1 : 0);
1769 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1770 getBorderElement(lx, ly));
1772 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1773 element, tile_size);
1777 redraw_mask |= REDRAW_MICROLEVEL;
1780 #define MICROLABEL_EMPTY 0
1781 #define MICROLABEL_LEVEL_NAME 1
1782 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1783 #define MICROLABEL_LEVEL_AUTHOR 3
1784 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1785 #define MICROLABEL_IMPORTED_FROM 5
1786 #define MICROLABEL_IMPORTED_BY_HEAD 6
1787 #define MICROLABEL_IMPORTED_BY 7
1789 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
1791 int max_text_width = SXSIZE;
1792 int font_width = getFontWidth(font_nr);
1794 if (pos->align == ALIGN_CENTER)
1795 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1796 else if (pos->align == ALIGN_RIGHT)
1797 max_text_width = pos->x;
1799 max_text_width = SXSIZE - pos->x;
1801 return max_text_width / font_width;
1804 static void DrawPreviewLevelLabelExt(int mode)
1806 struct TextPosInfo *pos = &menu.main.text.level_info_2;
1807 char label_text[MAX_OUTPUT_LINESIZE + 1];
1808 int max_len_label_text;
1809 int font_nr = FONT_TEXT_2;
1812 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1813 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1814 mode == MICROLABEL_IMPORTED_BY_HEAD)
1815 font_nr = FONT_TEXT_3;
1818 max_len_label_text = getMaxTextLength(pos, font_nr);
1820 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1824 if (pos->chars != -1)
1825 max_len_label_text = pos->chars;
1828 for (i = 0; i < max_len_label_text; i++)
1829 label_text[i] = ' ';
1830 label_text[max_len_label_text] = '\0';
1832 if (strlen(label_text) > 0)
1835 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1837 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1838 int lypos = MICROLABEL2_YPOS;
1840 DrawText(lxpos, lypos, label_text, font_nr);
1845 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1846 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1847 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1848 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1849 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1850 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1851 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1852 max_len_label_text);
1853 label_text[max_len_label_text] = '\0';
1855 if (strlen(label_text) > 0)
1858 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1860 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1861 int lypos = MICROLABEL2_YPOS;
1863 DrawText(lxpos, lypos, label_text, font_nr);
1867 redraw_mask |= REDRAW_MICROLEVEL;
1870 void DrawPreviewLevel(boolean restart)
1872 static unsigned long scroll_delay = 0;
1873 static unsigned long label_delay = 0;
1874 static int from_x, from_y, scroll_direction;
1875 static int label_state, label_counter;
1876 unsigned long scroll_delay_value = preview.step_delay;
1877 boolean show_level_border = (BorderElement != EL_EMPTY);
1878 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1879 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1880 int last_game_status = game_status; /* save current game status */
1882 /* force PREVIEW font on preview level */
1883 game_status = GAME_MODE_PSEUDO_PREVIEW;
1890 if (preview.anim_mode == ANIM_CENTERED)
1892 if (level_xsize > preview.xsize)
1893 from_x = (level_xsize - preview.xsize) / 2;
1894 if (level_ysize > preview.ysize)
1895 from_y = (level_ysize - preview.ysize) / 2;
1898 from_x += preview.xoffset;
1899 from_y += preview.yoffset;
1901 scroll_direction = MV_RIGHT;
1905 DrawPreviewLevelExt(from_x, from_y);
1906 DrawPreviewLevelLabelExt(label_state);
1908 /* initialize delay counters */
1909 DelayReached(&scroll_delay, 0);
1910 DelayReached(&label_delay, 0);
1912 if (leveldir_current->name)
1914 struct TextPosInfo *pos = &menu.main.text.level_info_1;
1915 char label_text[MAX_OUTPUT_LINESIZE + 1];
1916 int font_nr = FONT_TEXT_1;
1918 int max_len_label_text = getMaxTextLength(pos, font_nr);
1920 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1928 if (pos->chars != -1)
1929 max_len_label_text = pos->chars;
1932 strncpy(label_text, leveldir_current->name, max_len_label_text);
1933 label_text[max_len_label_text] = '\0';
1936 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1938 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1939 lypos = SY + MICROLABEL1_YPOS;
1941 DrawText(lxpos, lypos, label_text, font_nr);
1945 game_status = last_game_status; /* restore current game status */
1950 /* scroll preview level, if needed */
1951 if (preview.anim_mode != ANIM_NONE &&
1952 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1953 DelayReached(&scroll_delay, scroll_delay_value))
1955 switch (scroll_direction)
1960 from_x -= preview.step_offset;
1961 from_x = (from_x < 0 ? 0 : from_x);
1964 scroll_direction = MV_UP;
1968 if (from_x < level_xsize - preview.xsize)
1970 from_x += preview.step_offset;
1971 from_x = (from_x > level_xsize - preview.xsize ?
1972 level_xsize - preview.xsize : from_x);
1975 scroll_direction = MV_DOWN;
1981 from_y -= preview.step_offset;
1982 from_y = (from_y < 0 ? 0 : from_y);
1985 scroll_direction = MV_RIGHT;
1989 if (from_y < level_ysize - preview.ysize)
1991 from_y += preview.step_offset;
1992 from_y = (from_y > level_ysize - preview.ysize ?
1993 level_ysize - preview.ysize : from_y);
1996 scroll_direction = MV_LEFT;
2003 DrawPreviewLevelExt(from_x, from_y);
2006 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2007 /* redraw micro level label, if needed */
2008 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2009 !strEqual(level.author, ANONYMOUS_NAME) &&
2010 !strEqual(level.author, leveldir_current->name) &&
2011 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2013 int max_label_counter = 23;
2015 if (leveldir_current->imported_from != NULL &&
2016 strlen(leveldir_current->imported_from) > 0)
2017 max_label_counter += 14;
2018 if (leveldir_current->imported_by != NULL &&
2019 strlen(leveldir_current->imported_by) > 0)
2020 max_label_counter += 14;
2022 label_counter = (label_counter + 1) % max_label_counter;
2023 label_state = (label_counter >= 0 && label_counter <= 7 ?
2024 MICROLABEL_LEVEL_NAME :
2025 label_counter >= 9 && label_counter <= 12 ?
2026 MICROLABEL_LEVEL_AUTHOR_HEAD :
2027 label_counter >= 14 && label_counter <= 21 ?
2028 MICROLABEL_LEVEL_AUTHOR :
2029 label_counter >= 23 && label_counter <= 26 ?
2030 MICROLABEL_IMPORTED_FROM_HEAD :
2031 label_counter >= 28 && label_counter <= 35 ?
2032 MICROLABEL_IMPORTED_FROM :
2033 label_counter >= 37 && label_counter <= 40 ?
2034 MICROLABEL_IMPORTED_BY_HEAD :
2035 label_counter >= 42 && label_counter <= 49 ?
2036 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2038 if (leveldir_current->imported_from == NULL &&
2039 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2040 label_state == MICROLABEL_IMPORTED_FROM))
2041 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2042 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2044 DrawPreviewLevelLabelExt(label_state);
2047 game_status = last_game_status; /* restore current game status */
2050 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2051 int graphic, int sync_frame, int mask_mode)
2053 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2055 if (mask_mode == USE_MASKING)
2056 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2058 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2061 inline void DrawGraphicAnimation(int x, int y, int graphic)
2063 int lx = LEVELX(x), ly = LEVELY(y);
2065 if (!IN_SCR_FIELD(x, y))
2068 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2069 graphic, GfxFrame[lx][ly], NO_MASKING);
2070 MarkTileDirty(x, y);
2073 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2075 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2078 void DrawLevelElementAnimation(int x, int y, int element)
2080 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2082 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2085 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2087 int sx = SCREENX(x), sy = SCREENY(y);
2089 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2092 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2095 DrawGraphicAnimation(sx, sy, graphic);
2098 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2099 DrawLevelFieldCrumbledSand(x, y);
2101 if (GFX_CRUMBLED(Feld[x][y]))
2102 DrawLevelFieldCrumbledSand(x, y);
2106 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2108 int sx = SCREENX(x), sy = SCREENY(y);
2111 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2114 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2116 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2119 DrawGraphicAnimation(sx, sy, graphic);
2121 if (GFX_CRUMBLED(element))
2122 DrawLevelFieldCrumbledSand(x, y);
2125 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2127 if (player->use_murphy)
2129 /* this works only because currently only one player can be "murphy" ... */
2130 static int last_horizontal_dir = MV_LEFT;
2131 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2133 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2134 last_horizontal_dir = move_dir;
2136 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2138 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2140 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2146 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2149 static boolean equalGraphics(int graphic1, int graphic2)
2151 struct GraphicInfo *g1 = &graphic_info[graphic1];
2152 struct GraphicInfo *g2 = &graphic_info[graphic2];
2154 return (g1->bitmap == g2->bitmap &&
2155 g1->src_x == g2->src_x &&
2156 g1->src_y == g2->src_y &&
2157 g1->anim_frames == g2->anim_frames &&
2158 g1->anim_delay == g2->anim_delay &&
2159 g1->anim_mode == g2->anim_mode);
2162 void DrawAllPlayers()
2166 for (i = 0; i < MAX_PLAYERS; i++)
2167 if (stored_player[i].active)
2168 DrawPlayer(&stored_player[i]);
2171 void DrawPlayerField(int x, int y)
2173 if (!IS_PLAYER(x, y))
2176 DrawPlayer(PLAYERINFO(x, y));
2179 void DrawPlayer(struct PlayerInfo *player)
2181 int jx = player->jx;
2182 int jy = player->jy;
2183 int move_dir = player->MovDir;
2184 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2185 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2186 int last_jx = (player->is_moving ? jx - dx : jx);
2187 int last_jy = (player->is_moving ? jy - dy : jy);
2188 int next_jx = jx + dx;
2189 int next_jy = jy + dy;
2190 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2191 boolean player_is_opaque = FALSE;
2192 int sx = SCREENX(jx), sy = SCREENY(jy);
2193 int sxx = 0, syy = 0;
2194 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2196 int action = ACTION_DEFAULT;
2197 int last_player_graphic = getPlayerGraphic(player, move_dir);
2198 int last_player_frame = player->Frame;
2201 /* GfxElement[][] is set to the element the player is digging or collecting;
2202 remove also for off-screen player if the player is not moving anymore */
2203 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2204 GfxElement[jx][jy] = EL_UNDEFINED;
2206 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2210 if (!IN_LEV_FIELD(jx, jy))
2212 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2213 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2214 printf("DrawPlayerField(): This should never happen!\n");
2219 if (element == EL_EXPLOSION)
2222 action = (player->is_pushing ? ACTION_PUSHING :
2223 player->is_digging ? ACTION_DIGGING :
2224 player->is_collecting ? ACTION_COLLECTING :
2225 player->is_moving ? ACTION_MOVING :
2226 player->is_snapping ? ACTION_SNAPPING :
2227 player->is_dropping ? ACTION_DROPPING :
2228 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2230 if (player->is_waiting)
2231 move_dir = player->dir_waiting;
2233 InitPlayerGfxAnimation(player, action, move_dir);
2235 /* ----------------------------------------------------------------------- */
2236 /* draw things in the field the player is leaving, if needed */
2237 /* ----------------------------------------------------------------------- */
2239 if (player->is_moving)
2241 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2243 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2245 if (last_element == EL_DYNAMITE_ACTIVE ||
2246 last_element == EL_EM_DYNAMITE_ACTIVE ||
2247 last_element == EL_SP_DISK_RED_ACTIVE)
2248 DrawDynamite(last_jx, last_jy);
2250 DrawLevelFieldThruMask(last_jx, last_jy);
2252 else if (last_element == EL_DYNAMITE_ACTIVE ||
2253 last_element == EL_EM_DYNAMITE_ACTIVE ||
2254 last_element == EL_SP_DISK_RED_ACTIVE)
2255 DrawDynamite(last_jx, last_jy);
2257 /* !!! this is not enough to prevent flickering of players which are
2258 moving next to each others without a free tile between them -- this
2259 can only be solved by drawing all players layer by layer (first the
2260 background, then the foreground etc.) !!! => TODO */
2261 else if (!IS_PLAYER(last_jx, last_jy))
2262 DrawLevelField(last_jx, last_jy);
2265 DrawLevelField(last_jx, last_jy);
2268 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2269 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2272 if (!IN_SCR_FIELD(sx, sy))
2275 if (setup.direct_draw)
2276 SetDrawtoField(DRAW_BUFFERED);
2278 /* ----------------------------------------------------------------------- */
2279 /* draw things behind the player, if needed */
2280 /* ----------------------------------------------------------------------- */
2283 DrawLevelElement(jx, jy, Back[jx][jy]);
2284 else if (IS_ACTIVE_BOMB(element))
2285 DrawLevelElement(jx, jy, EL_EMPTY);
2288 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2290 int old_element = GfxElement[jx][jy];
2291 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2292 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2294 if (GFX_CRUMBLED(old_element))
2295 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2297 DrawGraphic(sx, sy, old_graphic, frame);
2299 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2300 player_is_opaque = TRUE;
2304 GfxElement[jx][jy] = EL_UNDEFINED;
2306 /* make sure that pushed elements are drawn with correct frame rate */
2308 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2310 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2311 GfxFrame[jx][jy] = player->StepFrame;
2313 if (player->is_pushing && player->is_moving)
2314 GfxFrame[jx][jy] = player->StepFrame;
2317 DrawLevelField(jx, jy);
2321 /* ----------------------------------------------------------------------- */
2322 /* draw player himself */
2323 /* ----------------------------------------------------------------------- */
2325 graphic = getPlayerGraphic(player, move_dir);
2327 /* in the case of changed player action or direction, prevent the current
2328 animation frame from being restarted for identical animations */
2329 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2330 player->Frame = last_player_frame;
2332 frame = getGraphicAnimationFrame(graphic, player->Frame);
2336 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2337 sxx = player->GfxPos;
2339 syy = player->GfxPos;
2342 if (!setup.soft_scrolling && ScreenMovPos)
2345 if (player_is_opaque)
2346 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2348 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2350 if (SHIELD_ON(player))
2352 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2353 IMG_SHIELD_NORMAL_ACTIVE);
2354 int frame = getGraphicAnimationFrame(graphic, -1);
2356 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2359 /* ----------------------------------------------------------------------- */
2360 /* draw things the player is pushing, if needed */
2361 /* ----------------------------------------------------------------------- */
2364 printf("::: %d, %d [%d, %d] [%d]\n",
2365 player->is_pushing, player_is_moving, player->GfxAction,
2366 player->is_moving, player_is_moving);
2370 if (player->is_pushing && player->is_moving)
2372 int px = SCREENX(jx), py = SCREENY(jy);
2373 int pxx = (TILEX - ABS(sxx)) * dx;
2374 int pyy = (TILEY - ABS(syy)) * dy;
2375 int gfx_frame = GfxFrame[jx][jy];
2381 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2383 element = Feld[next_jx][next_jy];
2384 gfx_frame = GfxFrame[next_jx][next_jy];
2387 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2390 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2391 frame = getGraphicAnimationFrame(graphic, sync_frame);
2393 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2396 /* draw background element under pushed element (like the Sokoban field) */
2397 if (Back[next_jx][next_jy])
2398 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2400 /* masked drawing is needed for EMC style (double) movement graphics */
2401 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2405 /* ----------------------------------------------------------------------- */
2406 /* draw things in front of player (active dynamite or dynabombs) */
2407 /* ----------------------------------------------------------------------- */
2409 if (IS_ACTIVE_BOMB(element))
2411 graphic = el2img(element);
2412 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2414 if (game.emulation == EMU_SUPAPLEX)
2415 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2417 DrawGraphicThruMask(sx, sy, graphic, frame);
2420 if (player_is_moving && last_element == EL_EXPLOSION)
2422 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2423 GfxElement[last_jx][last_jy] : EL_EMPTY);
2424 int graphic = el_act2img(element, ACTION_EXPLODING);
2425 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2426 int phase = ExplodePhase[last_jx][last_jy] - 1;
2427 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2430 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2433 /* ----------------------------------------------------------------------- */
2434 /* draw elements the player is just walking/passing through/under */
2435 /* ----------------------------------------------------------------------- */
2437 if (player_is_moving)
2439 /* handle the field the player is leaving ... */
2440 if (IS_ACCESSIBLE_INSIDE(last_element))
2441 DrawLevelField(last_jx, last_jy);
2442 else if (IS_ACCESSIBLE_UNDER(last_element))
2443 DrawLevelFieldThruMask(last_jx, last_jy);
2446 /* do not redraw accessible elements if the player is just pushing them */
2447 if (!player_is_moving || !player->is_pushing)
2449 /* ... and the field the player is entering */
2450 if (IS_ACCESSIBLE_INSIDE(element))
2451 DrawLevelField(jx, jy);
2452 else if (IS_ACCESSIBLE_UNDER(element))
2453 DrawLevelFieldThruMask(jx, jy);
2456 if (setup.direct_draw)
2458 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2459 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2460 int x_size = TILEX * (1 + ABS(jx - last_jx));
2461 int y_size = TILEY * (1 + ABS(jy - last_jy));
2463 BlitBitmap(drawto_field, window,
2464 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2465 SetDrawtoField(DRAW_DIRECT);
2468 MarkTileDirty(sx, sy);
2471 /* ------------------------------------------------------------------------- */
2473 void WaitForEventToContinue()
2475 boolean still_wait = TRUE;
2477 /* simulate releasing mouse button over last gadget, if still pressed */
2479 HandleGadgets(-1, -1, 0);
2481 button_status = MB_RELEASED;
2497 case EVENT_BUTTONPRESS:
2498 case EVENT_KEYPRESS:
2502 case EVENT_KEYRELEASE:
2503 ClearPlayerAction();
2507 HandleOtherEvents(&event);
2511 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2518 /* don't eat all CPU time */
2523 #define MAX_REQUEST_LINES 13
2524 #define MAX_REQUEST_LINE_FONT1_LEN 7
2525 #define MAX_REQUEST_LINE_FONT2_LEN 10
2527 boolean Request(char *text, unsigned int req_state)
2529 int mx, my, ty, result = -1;
2530 unsigned int old_door_state;
2531 int last_game_status = game_status; /* save current game status */
2532 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2533 int font_nr = FONT_TEXT_2;
2534 int max_word_len = 0;
2537 for (text_ptr = text; *text_ptr; text_ptr++)
2539 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2541 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2543 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2545 font_nr = FONT_TEXT_1;
2547 font_nr = FONT_LEVEL_NUMBER;
2554 if (game_status == GAME_MODE_PLAYING &&
2555 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2556 BlitScreenToBitmap_EM(backbuffer);
2558 /* disable deactivated drawing when quick-loading level tape recording */
2559 if (tape.playing && tape.deactivate_display)
2560 TapeDeactivateDisplayOff(TRUE);
2562 SetMouseCursor(CURSOR_DEFAULT);
2564 #if defined(NETWORK_AVALIABLE)
2565 /* pause network game while waiting for request to answer */
2566 if (options.network &&
2567 game_status == GAME_MODE_PLAYING &&
2568 req_state & REQUEST_WAIT_FOR_INPUT)
2569 SendToServer_PausePlaying();
2572 old_door_state = GetDoorState();
2574 /* simulate releasing mouse button over last gadget, if still pressed */
2576 HandleGadgets(-1, -1, 0);
2580 if (old_door_state & DOOR_OPEN_1)
2582 CloseDoor(DOOR_CLOSE_1);
2584 /* save old door content */
2585 BlitBitmap(bitmap_db_door, bitmap_db_door,
2586 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2587 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2591 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2594 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2596 /* clear door drawing field */
2597 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2599 /* force DOOR font on preview level */
2600 game_status = GAME_MODE_PSEUDO_DOOR;
2602 /* write text for request */
2603 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2605 char text_line[max_request_line_len + 1];
2611 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2614 if (!tc || tc == ' ')
2625 strncpy(text_line, text, tl);
2628 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2629 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2630 text_line, font_nr);
2632 text += tl + (tc == ' ' ? 1 : 0);
2635 game_status = last_game_status; /* restore current game status */
2637 if (req_state & REQ_ASK)
2639 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2640 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2642 else if (req_state & REQ_CONFIRM)
2644 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2646 else if (req_state & REQ_PLAYER)
2648 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2649 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2650 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2651 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2654 /* copy request gadgets to door backbuffer */
2655 BlitBitmap(drawto, bitmap_db_door,
2656 DX, DY, DXSIZE, DYSIZE,
2657 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2659 OpenDoor(DOOR_OPEN_1);
2661 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2663 if (game_status == GAME_MODE_PLAYING)
2665 SetPanelBackground();
2666 SetDrawBackgroundMask(REDRAW_DOOR_1);
2670 SetDrawBackgroundMask(REDRAW_FIELD);
2676 if (game_status != GAME_MODE_MAIN)
2679 button_status = MB_RELEASED;
2681 request_gadget_id = -1;
2683 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2695 case EVENT_BUTTONPRESS:
2696 case EVENT_BUTTONRELEASE:
2697 case EVENT_MOTIONNOTIFY:
2699 if (event.type == EVENT_MOTIONNOTIFY)
2701 if (!PointerInWindow(window))
2702 continue; /* window and pointer are on different screens */
2707 motion_status = TRUE;
2708 mx = ((MotionEvent *) &event)->x;
2709 my = ((MotionEvent *) &event)->y;
2713 motion_status = FALSE;
2714 mx = ((ButtonEvent *) &event)->x;
2715 my = ((ButtonEvent *) &event)->y;
2716 if (event.type == EVENT_BUTTONPRESS)
2717 button_status = ((ButtonEvent *) &event)->button;
2719 button_status = MB_RELEASED;
2722 /* this sets 'request_gadget_id' */
2723 HandleGadgets(mx, my, button_status);
2725 switch (request_gadget_id)
2727 case TOOL_CTRL_ID_YES:
2730 case TOOL_CTRL_ID_NO:
2733 case TOOL_CTRL_ID_CONFIRM:
2734 result = TRUE | FALSE;
2737 case TOOL_CTRL_ID_PLAYER_1:
2740 case TOOL_CTRL_ID_PLAYER_2:
2743 case TOOL_CTRL_ID_PLAYER_3:
2746 case TOOL_CTRL_ID_PLAYER_4:
2757 case EVENT_KEYPRESS:
2758 switch (GetEventKey((KeyEvent *)&event, TRUE))
2771 if (req_state & REQ_PLAYER)
2775 case EVENT_KEYRELEASE:
2776 ClearPlayerAction();
2780 HandleOtherEvents(&event);
2784 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2786 int joy = AnyJoystick();
2788 if (joy & JOY_BUTTON_1)
2790 else if (joy & JOY_BUTTON_2)
2796 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2798 HandleGameActions();
2805 if (!PendingEvent()) /* delay only if no pending events */
2814 if (!PendingEvent()) /* delay only if no pending events */
2817 /* don't eat all CPU time */
2824 if (game_status != GAME_MODE_MAIN)
2829 if (!(req_state & REQ_STAY_OPEN))
2831 CloseDoor(DOOR_CLOSE_1);
2833 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2834 (req_state & REQ_REOPEN))
2835 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2840 if (game_status == GAME_MODE_PLAYING)
2842 SetPanelBackground();
2843 SetDrawBackgroundMask(REDRAW_DOOR_1);
2847 SetDrawBackgroundMask(REDRAW_FIELD);
2850 #if defined(NETWORK_AVALIABLE)
2851 /* continue network game after request */
2852 if (options.network &&
2853 game_status == GAME_MODE_PLAYING &&
2854 req_state & REQUEST_WAIT_FOR_INPUT)
2855 SendToServer_ContinuePlaying();
2858 /* restore deactivated drawing when quick-loading level tape recording */
2859 if (tape.playing && tape.deactivate_display)
2860 TapeDeactivateDisplayOn();
2865 unsigned int OpenDoor(unsigned int door_state)
2867 if (door_state & DOOR_COPY_BACK)
2869 if (door_state & DOOR_OPEN_1)
2870 BlitBitmap(bitmap_db_door, bitmap_db_door,
2871 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2872 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2874 if (door_state & DOOR_OPEN_2)
2875 BlitBitmap(bitmap_db_door, bitmap_db_door,
2876 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2877 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2879 door_state &= ~DOOR_COPY_BACK;
2882 return MoveDoor(door_state);
2885 unsigned int CloseDoor(unsigned int door_state)
2887 unsigned int old_door_state = GetDoorState();
2889 if (!(door_state & DOOR_NO_COPY_BACK))
2891 if (old_door_state & DOOR_OPEN_1)
2892 BlitBitmap(backbuffer, bitmap_db_door,
2893 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2895 if (old_door_state & DOOR_OPEN_2)
2896 BlitBitmap(backbuffer, bitmap_db_door,
2897 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2899 door_state &= ~DOOR_NO_COPY_BACK;
2902 return MoveDoor(door_state);
2905 unsigned int GetDoorState()
2907 return MoveDoor(DOOR_GET_STATE);
2910 unsigned int SetDoorState(unsigned int door_state)
2912 return MoveDoor(door_state | DOOR_SET_STATE);
2915 unsigned int MoveDoor(unsigned int door_state)
2917 static int door1 = DOOR_OPEN_1;
2918 static int door2 = DOOR_CLOSE_2;
2919 unsigned long door_delay = 0;
2920 unsigned long door_delay_value;
2923 if (door_1.width < 0 || door_1.width > DXSIZE)
2924 door_1.width = DXSIZE;
2925 if (door_1.height < 0 || door_1.height > DYSIZE)
2926 door_1.height = DYSIZE;
2927 if (door_2.width < 0 || door_2.width > VXSIZE)
2928 door_2.width = VXSIZE;
2929 if (door_2.height < 0 || door_2.height > VYSIZE)
2930 door_2.height = VYSIZE;
2932 if (door_state == DOOR_GET_STATE)
2933 return (door1 | door2);
2935 if (door_state & DOOR_SET_STATE)
2937 if (door_state & DOOR_ACTION_1)
2938 door1 = door_state & DOOR_ACTION_1;
2939 if (door_state & DOOR_ACTION_2)
2940 door2 = door_state & DOOR_ACTION_2;
2942 return (door1 | door2);
2945 if (!(door_state & DOOR_FORCE_REDRAW))
2947 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2948 door_state &= ~DOOR_OPEN_1;
2949 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2950 door_state &= ~DOOR_CLOSE_1;
2951 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2952 door_state &= ~DOOR_OPEN_2;
2953 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2954 door_state &= ~DOOR_CLOSE_2;
2957 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2960 if (setup.quick_doors)
2962 stepsize = 20; /* must be choosen to always draw last frame */
2963 door_delay_value = 0;
2966 if (global.autoplay_leveldir)
2968 door_state |= DOOR_NO_DELAY;
2969 door_state &= ~DOOR_CLOSE_ALL;
2972 if (door_state & DOOR_ACTION)
2974 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2975 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2976 boolean door_1_done = (!handle_door_1);
2977 boolean door_2_done = (!handle_door_2);
2978 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2979 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2980 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2981 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2982 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2983 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2984 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2985 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2986 int door_skip = max_door_size - door_size;
2987 int end = door_size;
2988 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2991 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2993 /* opening door sound has priority over simultaneously closing door */
2994 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2995 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2996 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2997 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3000 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3003 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3004 GC gc = bitmap->stored_clip_gc;
3006 if (door_state & DOOR_ACTION_1)
3008 int a = MIN(x * door_1.step_offset, end);
3009 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3010 int i = p + door_skip;
3012 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3014 BlitBitmap(bitmap_db_door, drawto,
3015 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3016 DXSIZE, DYSIZE, DX, DY);
3020 BlitBitmap(bitmap_db_door, drawto,
3021 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3022 DXSIZE, DYSIZE - p / 2, DX, DY);
3024 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3027 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3029 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3030 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3031 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3032 int dst2_x = DX, dst2_y = DY;
3033 int width = i, height = DYSIZE;
3035 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3036 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3039 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3040 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3043 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3045 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3046 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3047 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3048 int dst2_x = DX, dst2_y = DY;
3049 int width = DXSIZE, height = i;
3051 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3052 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3055 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3056 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3059 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3061 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3063 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3064 BlitBitmapMasked(bitmap, drawto,
3065 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3066 DX + DXSIZE - i, DY + j);
3067 BlitBitmapMasked(bitmap, drawto,
3068 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3069 DX + DXSIZE - i, DY + 140 + j);
3070 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3071 DY - (DOOR_GFX_PAGEY1 + j));
3072 BlitBitmapMasked(bitmap, drawto,
3073 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3075 BlitBitmapMasked(bitmap, drawto,
3076 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3079 BlitBitmapMasked(bitmap, drawto,
3080 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3082 BlitBitmapMasked(bitmap, drawto,
3083 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3085 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3086 BlitBitmapMasked(bitmap, drawto,
3087 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3088 DX + DXSIZE - i, DY + 77 + j);
3089 BlitBitmapMasked(bitmap, drawto,
3090 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3091 DX + DXSIZE - i, DY + 203 + j);
3094 redraw_mask |= REDRAW_DOOR_1;
3095 door_1_done = (a == end);
3098 if (door_state & DOOR_ACTION_2)
3100 int a = MIN(x * door_2.step_offset, door_size);
3101 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3102 int i = p + door_skip;
3104 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3106 BlitBitmap(bitmap_db_door, drawto,
3107 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3108 VXSIZE, VYSIZE, VX, VY);
3110 else if (x <= VYSIZE)
3112 BlitBitmap(bitmap_db_door, drawto,
3113 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3114 VXSIZE, VYSIZE - p / 2, VX, VY);
3116 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3119 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3121 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3122 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3123 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3124 int dst2_x = VX, dst2_y = VY;
3125 int width = i, height = VYSIZE;
3127 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3128 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3131 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3132 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3135 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3137 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3138 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3139 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3140 int dst2_x = VX, dst2_y = VY;
3141 int width = VXSIZE, height = i;
3143 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3144 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3147 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3148 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3151 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3153 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3155 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3156 BlitBitmapMasked(bitmap, drawto,
3157 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3158 VX + VXSIZE - i, VY + j);
3159 SetClipOrigin(bitmap, gc,
3160 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3161 BlitBitmapMasked(bitmap, drawto,
3162 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3165 BlitBitmapMasked(bitmap, drawto,
3166 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3167 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3168 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3169 BlitBitmapMasked(bitmap, drawto,
3170 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3172 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3175 redraw_mask |= REDRAW_DOOR_2;
3176 door_2_done = (a == VXSIZE);
3179 if (!(door_state & DOOR_NO_DELAY))
3183 if (game_status == GAME_MODE_MAIN)
3186 WaitUntilDelayReached(&door_delay, door_delay_value);
3191 if (door_state & DOOR_ACTION_1)
3192 door1 = door_state & DOOR_ACTION_1;
3193 if (door_state & DOOR_ACTION_2)
3194 door2 = door_state & DOOR_ACTION_2;
3196 return (door1 | door2);
3199 void DrawSpecialEditorDoor()
3201 /* draw bigger toolbox window */
3202 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3203 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3205 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3206 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3209 redraw_mask |= REDRAW_ALL;
3212 void UndrawSpecialEditorDoor()
3214 /* draw normal tape recorder window */
3215 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3216 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3219 redraw_mask |= REDRAW_ALL;
3223 /* ---------- new tool button stuff ---------------------------------------- */
3225 /* graphic position values for tool buttons */
3226 #define TOOL_BUTTON_YES_XPOS 2
3227 #define TOOL_BUTTON_YES_YPOS 250
3228 #define TOOL_BUTTON_YES_GFX_YPOS 0
3229 #define TOOL_BUTTON_YES_XSIZE 46
3230 #define TOOL_BUTTON_YES_YSIZE 28
3231 #define TOOL_BUTTON_NO_XPOS 52
3232 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3233 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3234 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3235 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3236 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3237 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3238 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3239 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3240 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3241 #define TOOL_BUTTON_PLAYER_XSIZE 30
3242 #define TOOL_BUTTON_PLAYER_YSIZE 30
3243 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3244 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3245 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3246 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3247 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3248 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3249 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3250 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3251 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3252 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3253 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3254 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3255 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3256 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3257 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3258 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3259 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3260 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3261 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3262 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3271 } toolbutton_info[NUM_TOOL_BUTTONS] =
3274 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3275 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3276 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3281 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3282 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3283 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3288 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3289 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3290 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3291 TOOL_CTRL_ID_CONFIRM,
3295 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3296 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3297 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3298 TOOL_CTRL_ID_PLAYER_1,
3302 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3303 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3304 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3305 TOOL_CTRL_ID_PLAYER_2,
3309 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3310 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3311 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3312 TOOL_CTRL_ID_PLAYER_3,
3316 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3317 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3318 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3319 TOOL_CTRL_ID_PLAYER_4,
3324 void CreateToolButtons()
3328 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3330 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3331 Bitmap *deco_bitmap = None;
3332 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3333 struct GadgetInfo *gi;
3334 unsigned long event_mask;
3335 int gd_xoffset, gd_yoffset;
3336 int gd_x1, gd_x2, gd_y;
3339 event_mask = GD_EVENT_RELEASED;
3341 gd_xoffset = toolbutton_info[i].xpos;
3342 gd_yoffset = toolbutton_info[i].ypos;
3343 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3344 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3345 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3347 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3349 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3351 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3352 &deco_bitmap, &deco_x, &deco_y);
3353 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3354 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3357 gi = CreateGadget(GDI_CUSTOM_ID, id,
3358 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3359 GDI_X, DX + toolbutton_info[i].x,
3360 GDI_Y, DY + toolbutton_info[i].y,
3361 GDI_WIDTH, toolbutton_info[i].width,
3362 GDI_HEIGHT, toolbutton_info[i].height,
3363 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3364 GDI_STATE, GD_BUTTON_UNPRESSED,
3365 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3366 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3367 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3368 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3369 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3370 GDI_DECORATION_SHIFTING, 1, 1,
3371 GDI_DIRECT_DRAW, FALSE,
3372 GDI_EVENT_MASK, event_mask,
3373 GDI_CALLBACK_ACTION, HandleToolButtons,
3377 Error(ERR_EXIT, "cannot create gadget");
3379 tool_gadget[id] = gi;
3383 void FreeToolButtons()
3387 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3388 FreeGadget(tool_gadget[i]);
3391 static void UnmapToolButtons()
3395 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3396 UnmapGadget(tool_gadget[i]);
3399 static void HandleToolButtons(struct GadgetInfo *gi)
3401 request_gadget_id = gi->custom_id;
3404 static struct Mapping_EM_to_RND_object
3407 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3408 boolean is_backside; /* backside of moving element */
3414 em_object_mapping_list[] =
3417 Xblank, TRUE, FALSE,
3421 Yacid_splash_eB, FALSE, FALSE,
3422 EL_ACID_SPLASH_RIGHT, -1, -1
3425 Yacid_splash_wB, FALSE, FALSE,
3426 EL_ACID_SPLASH_LEFT, -1, -1
3429 #ifdef EM_ENGINE_BAD_ROLL
3431 Xstone_force_e, FALSE, FALSE,
3432 EL_ROCK, -1, MV_BIT_RIGHT
3435 Xstone_force_w, FALSE, FALSE,
3436 EL_ROCK, -1, MV_BIT_LEFT
3439 Xnut_force_e, FALSE, FALSE,
3440 EL_NUT, -1, MV_BIT_RIGHT
3443 Xnut_force_w, FALSE, FALSE,
3444 EL_NUT, -1, MV_BIT_LEFT
3447 Xspring_force_e, FALSE, FALSE,
3448 EL_SPRING, -1, MV_BIT_RIGHT
3451 Xspring_force_w, FALSE, FALSE,
3452 EL_SPRING, -1, MV_BIT_LEFT
3455 Xemerald_force_e, FALSE, FALSE,
3456 EL_EMERALD, -1, MV_BIT_RIGHT
3459 Xemerald_force_w, FALSE, FALSE,
3460 EL_EMERALD, -1, MV_BIT_LEFT
3463 Xdiamond_force_e, FALSE, FALSE,
3464 EL_DIAMOND, -1, MV_BIT_RIGHT
3467 Xdiamond_force_w, FALSE, FALSE,
3468 EL_DIAMOND, -1, MV_BIT_LEFT
3471 Xbomb_force_e, FALSE, FALSE,
3472 EL_BOMB, -1, MV_BIT_RIGHT
3475 Xbomb_force_w, FALSE, FALSE,
3476 EL_BOMB, -1, MV_BIT_LEFT
3478 #endif /* EM_ENGINE_BAD_ROLL */
3481 Xstone, TRUE, FALSE,
3485 Xstone_pause, FALSE, FALSE,
3489 Xstone_fall, FALSE, FALSE,
3493 Ystone_s, FALSE, FALSE,
3494 EL_ROCK, ACTION_FALLING, -1
3497 Ystone_sB, FALSE, TRUE,
3498 EL_ROCK, ACTION_FALLING, -1
3501 Ystone_e, FALSE, FALSE,
3502 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3505 Ystone_eB, FALSE, TRUE,
3506 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3509 Ystone_w, FALSE, FALSE,
3510 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3513 Ystone_wB, FALSE, TRUE,
3514 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3521 Xnut_pause, FALSE, FALSE,
3525 Xnut_fall, FALSE, FALSE,
3529 Ynut_s, FALSE, FALSE,
3530 EL_NUT, ACTION_FALLING, -1
3533 Ynut_sB, FALSE, TRUE,
3534 EL_NUT, ACTION_FALLING, -1
3537 Ynut_e, FALSE, FALSE,
3538 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3541 Ynut_eB, FALSE, TRUE,
3542 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3545 Ynut_w, FALSE, FALSE,
3546 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3549 Ynut_wB, FALSE, TRUE,
3550 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3553 Xbug_n, TRUE, FALSE,
3557 Xbug_e, TRUE, FALSE,
3558 EL_BUG_RIGHT, -1, -1
3561 Xbug_s, TRUE, FALSE,
3565 Xbug_w, TRUE, FALSE,
3569 Xbug_gon, FALSE, FALSE,
3573 Xbug_goe, FALSE, FALSE,
3574 EL_BUG_RIGHT, -1, -1
3577 Xbug_gos, FALSE, FALSE,
3581 Xbug_gow, FALSE, FALSE,
3585 Ybug_n, FALSE, FALSE,
3586 EL_BUG, ACTION_MOVING, MV_BIT_UP
3589 Ybug_nB, FALSE, TRUE,
3590 EL_BUG, ACTION_MOVING, MV_BIT_UP
3593 Ybug_e, FALSE, FALSE,
3594 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3597 Ybug_eB, FALSE, TRUE,
3598 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3601 Ybug_s, FALSE, FALSE,
3602 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3605 Ybug_sB, FALSE, TRUE,
3606 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3609 Ybug_w, FALSE, FALSE,
3610 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3613 Ybug_wB, FALSE, TRUE,
3614 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3617 Ybug_w_n, FALSE, FALSE,
3618 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3621 Ybug_n_e, FALSE, FALSE,
3622 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3625 Ybug_e_s, FALSE, FALSE,
3626 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3629 Ybug_s_w, FALSE, FALSE,
3630 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3633 Ybug_e_n, FALSE, FALSE,
3634 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3637 Ybug_s_e, FALSE, FALSE,
3638 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3641 Ybug_w_s, FALSE, FALSE,
3642 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3645 Ybug_n_w, FALSE, FALSE,
3646 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3649 Ybug_stone, FALSE, FALSE,
3650 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3653 Ybug_spring, FALSE, FALSE,
3654 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3657 Xtank_n, TRUE, FALSE,
3658 EL_SPACESHIP_UP, -1, -1
3661 Xtank_e, TRUE, FALSE,
3662 EL_SPACESHIP_RIGHT, -1, -1
3665 Xtank_s, TRUE, FALSE,
3666 EL_SPACESHIP_DOWN, -1, -1
3669 Xtank_w, TRUE, FALSE,
3670 EL_SPACESHIP_LEFT, -1, -1
3673 Xtank_gon, FALSE, FALSE,
3674 EL_SPACESHIP_UP, -1, -1
3677 Xtank_goe, FALSE, FALSE,
3678 EL_SPACESHIP_RIGHT, -1, -1
3681 Xtank_gos, FALSE, FALSE,
3682 EL_SPACESHIP_DOWN, -1, -1
3685 Xtank_gow, FALSE, FALSE,
3686 EL_SPACESHIP_LEFT, -1, -1
3689 Ytank_n, FALSE, FALSE,
3690 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3693 Ytank_nB, FALSE, TRUE,
3694 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3697 Ytank_e, FALSE, FALSE,
3698 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3701 Ytank_eB, FALSE, TRUE,
3702 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3705 Ytank_s, FALSE, FALSE,
3706 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3709 Ytank_sB, FALSE, TRUE,
3710 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3713 Ytank_w, FALSE, FALSE,
3714 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3717 Ytank_wB, FALSE, TRUE,
3718 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3721 Ytank_w_n, FALSE, FALSE,
3722 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3725 Ytank_n_e, FALSE, FALSE,
3726 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3729 Ytank_e_s, FALSE, FALSE,
3730 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3733 Ytank_s_w, FALSE, FALSE,
3734 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3737 Ytank_e_n, FALSE, FALSE,
3738 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3741 Ytank_s_e, FALSE, FALSE,
3742 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3745 Ytank_w_s, FALSE, FALSE,
3746 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3749 Ytank_n_w, FALSE, FALSE,
3750 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3753 Ytank_stone, FALSE, FALSE,
3754 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3757 Ytank_spring, FALSE, FALSE,
3758 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3761 Xandroid, TRUE, FALSE,
3762 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3765 Xandroid_1_n, FALSE, FALSE,
3766 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3769 Xandroid_2_n, FALSE, FALSE,
3770 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3773 Xandroid_1_e, FALSE, FALSE,
3774 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3777 Xandroid_2_e, FALSE, FALSE,
3778 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3781 Xandroid_1_w, FALSE, FALSE,
3782 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3785 Xandroid_2_w, FALSE, FALSE,
3786 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3789 Xandroid_1_s, FALSE, FALSE,
3790 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3793 Xandroid_2_s, FALSE, FALSE,
3794 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3797 Yandroid_n, FALSE, FALSE,
3798 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3801 Yandroid_nB, FALSE, TRUE,
3802 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3805 Yandroid_ne, FALSE, FALSE,
3806 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3809 Yandroid_neB, FALSE, TRUE,
3810 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3813 Yandroid_e, FALSE, FALSE,
3814 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3817 Yandroid_eB, FALSE, TRUE,
3818 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3821 Yandroid_se, FALSE, FALSE,
3822 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3825 Yandroid_seB, FALSE, TRUE,
3826 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3829 Yandroid_s, FALSE, FALSE,
3830 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3833 Yandroid_sB, FALSE, TRUE,
3834 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3837 Yandroid_sw, FALSE, FALSE,
3838 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3841 Yandroid_swB, FALSE, TRUE,
3842 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3845 Yandroid_w, FALSE, FALSE,
3846 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3849 Yandroid_wB, FALSE, TRUE,
3850 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3853 Yandroid_nw, FALSE, FALSE,
3854 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3857 Yandroid_nwB, FALSE, TRUE,
3858 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3861 Xspring, TRUE, FALSE,
3865 Xspring_pause, FALSE, FALSE,
3869 Xspring_e, FALSE, FALSE,
3873 Xspring_w, FALSE, FALSE,
3877 Xspring_fall, FALSE, FALSE,
3881 Yspring_s, FALSE, FALSE,
3882 EL_SPRING, ACTION_FALLING, -1
3885 Yspring_sB, FALSE, TRUE,
3886 EL_SPRING, ACTION_FALLING, -1
3889 Yspring_e, FALSE, FALSE,
3890 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3893 Yspring_eB, FALSE, TRUE,
3894 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3897 Yspring_w, FALSE, FALSE,
3898 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3901 Yspring_wB, FALSE, TRUE,
3902 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3905 Yspring_kill_e, FALSE, FALSE,
3906 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3909 Yspring_kill_eB, FALSE, TRUE,
3910 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3913 Yspring_kill_w, FALSE, FALSE,
3914 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3917 Yspring_kill_wB, FALSE, TRUE,
3918 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3921 Xeater_n, TRUE, FALSE,
3922 EL_YAMYAM_UP, -1, -1
3925 Xeater_e, TRUE, FALSE,
3926 EL_YAMYAM_RIGHT, -1, -1
3929 Xeater_w, TRUE, FALSE,
3930 EL_YAMYAM_LEFT, -1, -1
3933 Xeater_s, TRUE, FALSE,
3934 EL_YAMYAM_DOWN, -1, -1
3937 Yeater_n, FALSE, FALSE,
3938 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3941 Yeater_nB, FALSE, TRUE,
3942 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3945 Yeater_e, FALSE, FALSE,
3946 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3949 Yeater_eB, FALSE, TRUE,
3950 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3953 Yeater_s, FALSE, FALSE,
3954 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3957 Yeater_sB, FALSE, TRUE,
3958 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3961 Yeater_w, FALSE, FALSE,
3962 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3965 Yeater_wB, FALSE, TRUE,
3966 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3969 Yeater_stone, FALSE, FALSE,
3970 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3973 Yeater_spring, FALSE, FALSE,
3974 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3977 Xalien, TRUE, FALSE,
3981 Xalien_pause, FALSE, FALSE,
3985 Yalien_n, FALSE, FALSE,
3986 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3989 Yalien_nB, FALSE, TRUE,
3990 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3993 Yalien_e, FALSE, FALSE,
3994 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3997 Yalien_eB, FALSE, TRUE,
3998 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4001 Yalien_s, FALSE, FALSE,
4002 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4005 Yalien_sB, FALSE, TRUE,
4006 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4009 Yalien_w, FALSE, FALSE,
4010 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4013 Yalien_wB, FALSE, TRUE,
4014 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4017 Yalien_stone, FALSE, FALSE,
4018 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4021 Yalien_spring, FALSE, FALSE,
4022 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4025 Xemerald, TRUE, FALSE,
4029 Xemerald_pause, FALSE, FALSE,
4033 Xemerald_fall, FALSE, FALSE,
4037 Xemerald_shine, FALSE, FALSE,
4038 EL_EMERALD, ACTION_TWINKLING, -1
4041 Yemerald_s, FALSE, FALSE,
4042 EL_EMERALD, ACTION_FALLING, -1
4045 Yemerald_sB, FALSE, TRUE,
4046 EL_EMERALD, ACTION_FALLING, -1
4049 Yemerald_e, FALSE, FALSE,
4050 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4053 Yemerald_eB, FALSE, TRUE,
4054 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4057 Yemerald_w, FALSE, FALSE,
4058 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4061 Yemerald_wB, FALSE, TRUE,
4062 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4065 Yemerald_eat, FALSE, FALSE,
4066 EL_EMERALD, ACTION_COLLECTING, -1
4069 Yemerald_stone, FALSE, FALSE,
4070 EL_NUT, ACTION_BREAKING, -1
4073 Xdiamond, TRUE, FALSE,
4077 Xdiamond_pause, FALSE, FALSE,
4081 Xdiamond_fall, FALSE, FALSE,
4085 Xdiamond_shine, FALSE, FALSE,
4086 EL_DIAMOND, ACTION_TWINKLING, -1
4089 Ydiamond_s, FALSE, FALSE,
4090 EL_DIAMOND, ACTION_FALLING, -1
4093 Ydiamond_sB, FALSE, TRUE,
4094 EL_DIAMOND, ACTION_FALLING, -1
4097 Ydiamond_e, FALSE, FALSE,
4098 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4101 Ydiamond_eB, FALSE, TRUE,
4102 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4105 Ydiamond_w, FALSE, FALSE,
4106 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4109 Ydiamond_wB, FALSE, TRUE,
4110 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4113 Ydiamond_eat, FALSE, FALSE,
4114 EL_DIAMOND, ACTION_COLLECTING, -1
4117 Ydiamond_stone, FALSE, FALSE,
4118 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4121 Xdrip_fall, TRUE, FALSE,
4122 EL_AMOEBA_DROP, -1, -1
4125 Xdrip_stretch, FALSE, FALSE,
4126 EL_AMOEBA_DROP, ACTION_FALLING, -1
4129 Xdrip_stretchB, FALSE, TRUE,
4130 EL_AMOEBA_DROP, ACTION_FALLING, -1
4133 Xdrip_eat, FALSE, FALSE,
4134 EL_AMOEBA_DROP, ACTION_GROWING, -1
4137 Ydrip_s1, FALSE, FALSE,
4138 EL_AMOEBA_DROP, ACTION_FALLING, -1
4141 Ydrip_s1B, FALSE, TRUE,
4142 EL_AMOEBA_DROP, ACTION_FALLING, -1
4145 Ydrip_s2, FALSE, FALSE,
4146 EL_AMOEBA_DROP, ACTION_FALLING, -1
4149 Ydrip_s2B, FALSE, TRUE,
4150 EL_AMOEBA_DROP, ACTION_FALLING, -1
4157 Xbomb_pause, FALSE, FALSE,
4161 Xbomb_fall, FALSE, FALSE,
4165 Ybomb_s, FALSE, FALSE,
4166 EL_BOMB, ACTION_FALLING, -1
4169 Ybomb_sB, FALSE, TRUE,
4170 EL_BOMB, ACTION_FALLING, -1
4173 Ybomb_e, FALSE, FALSE,
4174 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4177 Ybomb_eB, FALSE, TRUE,
4178 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4181 Ybomb_w, FALSE, FALSE,
4182 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4185 Ybomb_wB, FALSE, TRUE,
4186 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4189 Ybomb_eat, FALSE, FALSE,
4190 EL_BOMB, ACTION_ACTIVATING, -1
4193 Xballoon, TRUE, FALSE,
4197 Yballoon_n, FALSE, FALSE,
4198 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4201 Yballoon_nB, FALSE, TRUE,
4202 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4205 Yballoon_e, FALSE, FALSE,
4206 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4209 Yballoon_eB, FALSE, TRUE,
4210 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4213 Yballoon_s, FALSE, FALSE,
4214 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4217 Yballoon_sB, FALSE, TRUE,
4218 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4221 Yballoon_w, FALSE, FALSE,
4222 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4225 Yballoon_wB, FALSE, TRUE,
4226 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4229 Xgrass, TRUE, FALSE,
4230 EL_EMC_GRASS, -1, -1
4233 Ygrass_nB, FALSE, FALSE,
4234 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4237 Ygrass_eB, FALSE, FALSE,
4238 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4241 Ygrass_sB, FALSE, FALSE,
4242 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4245 Ygrass_wB, FALSE, FALSE,
4246 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4253 Ydirt_nB, FALSE, FALSE,
4254 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4257 Ydirt_eB, FALSE, FALSE,
4258 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4261 Ydirt_sB, FALSE, FALSE,
4262 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4265 Ydirt_wB, FALSE, FALSE,
4266 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4269 Xacid_ne, TRUE, FALSE,
4270 EL_ACID_POOL_TOPRIGHT, -1, -1
4273 Xacid_se, TRUE, FALSE,
4274 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4277 Xacid_s, TRUE, FALSE,
4278 EL_ACID_POOL_BOTTOM, -1, -1
4281 Xacid_sw, TRUE, FALSE,
4282 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4285 Xacid_nw, TRUE, FALSE,
4286 EL_ACID_POOL_TOPLEFT, -1, -1
4289 Xacid_1, TRUE, FALSE,
4293 Xacid_2, FALSE, FALSE,
4297 Xacid_3, FALSE, FALSE,
4301 Xacid_4, FALSE, FALSE,
4305 Xacid_5, FALSE, FALSE,
4309 Xacid_6, FALSE, FALSE,
4313 Xacid_7, FALSE, FALSE,
4317 Xacid_8, FALSE, FALSE,
4321 Xball_1, TRUE, FALSE,
4322 EL_EMC_MAGIC_BALL, -1, -1
4325 Xball_1B, FALSE, FALSE,
4326 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4329 Xball_2, FALSE, FALSE,
4330 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4333 Xball_2B, FALSE, FALSE,
4334 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4337 Yball_eat, FALSE, FALSE,
4338 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4341 Ykey_1_eat, FALSE, FALSE,
4342 EL_EM_KEY_1, ACTION_COLLECTING, -1
4345 Ykey_2_eat, FALSE, FALSE,
4346 EL_EM_KEY_2, ACTION_COLLECTING, -1
4349 Ykey_3_eat, FALSE, FALSE,
4350 EL_EM_KEY_3, ACTION_COLLECTING, -1
4353 Ykey_4_eat, FALSE, FALSE,
4354 EL_EM_KEY_4, ACTION_COLLECTING, -1
4357 Ykey_5_eat, FALSE, FALSE,
4358 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4361 Ykey_6_eat, FALSE, FALSE,
4362 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4365 Ykey_7_eat, FALSE, FALSE,
4366 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4369 Ykey_8_eat, FALSE, FALSE,
4370 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4373 Ylenses_eat, FALSE, FALSE,
4374 EL_EMC_LENSES, ACTION_COLLECTING, -1
4377 Ymagnify_eat, FALSE, FALSE,
4378 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4381 Ygrass_eat, FALSE, FALSE,
4382 EL_EMC_GRASS, ACTION_SNAPPING, -1
4385 Ydirt_eat, FALSE, FALSE,
4386 EL_SAND, ACTION_SNAPPING, -1
4389 Xgrow_ns, TRUE, FALSE,
4390 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4393 Ygrow_ns_eat, FALSE, FALSE,
4394 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4397 Xgrow_ew, TRUE, FALSE,
4398 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4401 Ygrow_ew_eat, FALSE, FALSE,
4402 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4405 Xwonderwall, TRUE, FALSE,
4406 EL_MAGIC_WALL, -1, -1
4409 XwonderwallB, FALSE, FALSE,
4410 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4413 Xamoeba_1, TRUE, FALSE,
4414 EL_AMOEBA_DRY, ACTION_OTHER, -1
4417 Xamoeba_2, FALSE, FALSE,
4418 EL_AMOEBA_DRY, ACTION_OTHER, -1
4421 Xamoeba_3, FALSE, FALSE,
4422 EL_AMOEBA_DRY, ACTION_OTHER, -1
4425 Xamoeba_4, FALSE, FALSE,
4426 EL_AMOEBA_DRY, ACTION_OTHER, -1
4429 Xamoeba_5, TRUE, FALSE,
4430 EL_AMOEBA_WET, ACTION_OTHER, -1
4433 Xamoeba_6, FALSE, FALSE,
4434 EL_AMOEBA_WET, ACTION_OTHER, -1
4437 Xamoeba_7, FALSE, FALSE,
4438 EL_AMOEBA_WET, ACTION_OTHER, -1
4441 Xamoeba_8, FALSE, FALSE,
4442 EL_AMOEBA_WET, ACTION_OTHER, -1
4445 Xdoor_1, TRUE, FALSE,
4446 EL_EM_GATE_1, -1, -1
4449 Xdoor_2, TRUE, FALSE,
4450 EL_EM_GATE_2, -1, -1
4453 Xdoor_3, TRUE, FALSE,
4454 EL_EM_GATE_3, -1, -1
4457 Xdoor_4, TRUE, FALSE,
4458 EL_EM_GATE_4, -1, -1
4461 Xdoor_5, TRUE, FALSE,
4462 EL_EMC_GATE_5, -1, -1
4465 Xdoor_6, TRUE, FALSE,
4466 EL_EMC_GATE_6, -1, -1
4469 Xdoor_7, TRUE, FALSE,
4470 EL_EMC_GATE_7, -1, -1
4473 Xdoor_8, TRUE, FALSE,
4474 EL_EMC_GATE_8, -1, -1
4477 Xkey_1, TRUE, FALSE,
4481 Xkey_2, TRUE, FALSE,
4485 Xkey_3, TRUE, FALSE,
4489 Xkey_4, TRUE, FALSE,
4493 Xkey_5, TRUE, FALSE,
4494 EL_EMC_KEY_5, -1, -1
4497 Xkey_6, TRUE, FALSE,
4498 EL_EMC_KEY_6, -1, -1
4501 Xkey_7, TRUE, FALSE,
4502 EL_EMC_KEY_7, -1, -1
4505 Xkey_8, TRUE, FALSE,
4506 EL_EMC_KEY_8, -1, -1
4509 Xwind_n, TRUE, FALSE,
4510 EL_BALLOON_SWITCH_UP, -1, -1
4513 Xwind_e, TRUE, FALSE,
4514 EL_BALLOON_SWITCH_RIGHT, -1, -1
4517 Xwind_s, TRUE, FALSE,
4518 EL_BALLOON_SWITCH_DOWN, -1, -1
4521 Xwind_w, TRUE, FALSE,
4522 EL_BALLOON_SWITCH_LEFT, -1, -1
4525 Xwind_nesw, TRUE, FALSE,
4526 EL_BALLOON_SWITCH_ANY, -1, -1
4529 Xwind_stop, TRUE, FALSE,
4530 EL_BALLOON_SWITCH_NONE, -1, -1
4534 EL_EM_EXIT_CLOSED, -1, -1
4537 Xexit_1, TRUE, FALSE,
4538 EL_EM_EXIT_OPEN, -1, -1
4541 Xexit_2, FALSE, FALSE,
4542 EL_EM_EXIT_OPEN, -1, -1
4545 Xexit_3, FALSE, FALSE,
4546 EL_EM_EXIT_OPEN, -1, -1
4549 Xdynamite, TRUE, FALSE,
4550 EL_EM_DYNAMITE, -1, -1
4553 Ydynamite_eat, FALSE, FALSE,
4554 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4557 Xdynamite_1, TRUE, FALSE,
4558 EL_EM_DYNAMITE_ACTIVE, -1, -1
4561 Xdynamite_2, FALSE, FALSE,
4562 EL_EM_DYNAMITE_ACTIVE, -1, -1
4565 Xdynamite_3, FALSE, FALSE,
4566 EL_EM_DYNAMITE_ACTIVE, -1, -1
4569 Xdynamite_4, FALSE, FALSE,
4570 EL_EM_DYNAMITE_ACTIVE, -1, -1
4573 Xbumper, TRUE, FALSE,
4574 EL_EMC_SPRING_BUMPER, -1, -1
4577 XbumperB, FALSE, FALSE,
4578 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4581 Xwheel, TRUE, FALSE,
4582 EL_ROBOT_WHEEL, -1, -1
4585 XwheelB, FALSE, FALSE,
4586 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4589 Xswitch, TRUE, FALSE,
4590 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4593 XswitchB, FALSE, FALSE,
4594 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4598 EL_QUICKSAND_EMPTY, -1, -1
4601 Xsand_stone, TRUE, FALSE,
4602 EL_QUICKSAND_FULL, -1, -1
4605 Xsand_stonein_1, FALSE, TRUE,
4606 EL_ROCK, ACTION_FILLING, -1
4609 Xsand_stonein_2, FALSE, TRUE,
4610 EL_ROCK, ACTION_FILLING, -1
4613 Xsand_stonein_3, FALSE, TRUE,
4614 EL_ROCK, ACTION_FILLING, -1
4617 Xsand_stonein_4, FALSE, TRUE,
4618 EL_ROCK, ACTION_FILLING, -1
4621 Xsand_stonesand_1, FALSE, FALSE,
4622 EL_QUICKSAND_FULL, -1, -1
4625 Xsand_stonesand_2, FALSE, FALSE,
4626 EL_QUICKSAND_FULL, -1, -1
4629 Xsand_stonesand_3, FALSE, FALSE,
4630 EL_QUICKSAND_FULL, -1, -1
4633 Xsand_stonesand_4, FALSE, FALSE,
4634 EL_QUICKSAND_FULL, -1, -1
4637 Xsand_stoneout_1, FALSE, FALSE,
4638 EL_ROCK, ACTION_EMPTYING, -1
4641 Xsand_stoneout_2, FALSE, FALSE,
4642 EL_ROCK, ACTION_EMPTYING, -1
4645 Xsand_sandstone_1, FALSE, FALSE,
4646 EL_QUICKSAND_FULL, -1, -1
4649 Xsand_sandstone_2, FALSE, FALSE,
4650 EL_QUICKSAND_FULL, -1, -1
4653 Xsand_sandstone_3, FALSE, FALSE,
4654 EL_QUICKSAND_FULL, -1, -1
4657 Xsand_sandstone_4, FALSE, FALSE,
4658 EL_QUICKSAND_FULL, -1, -1
4661 Xplant, TRUE, FALSE,
4662 EL_EMC_PLANT, -1, -1
4665 Yplant, FALSE, FALSE,
4666 EL_EMC_PLANT, -1, -1
4669 Xlenses, TRUE, FALSE,
4670 EL_EMC_LENSES, -1, -1
4673 Xmagnify, TRUE, FALSE,
4674 EL_EMC_MAGNIFIER, -1, -1
4677 Xdripper, TRUE, FALSE,
4678 EL_EMC_DRIPPER, -1, -1
4681 XdripperB, FALSE, FALSE,
4682 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4685 Xfake_blank, TRUE, FALSE,
4686 EL_INVISIBLE_WALL, -1, -1
4689 Xfake_blankB, FALSE, FALSE,
4690 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4693 Xfake_grass, TRUE, FALSE,
4694 EL_EMC_FAKE_GRASS, -1, -1
4697 Xfake_grassB, FALSE, FALSE,
4698 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4701 Xfake_door_1, TRUE, FALSE,
4702 EL_EM_GATE_1_GRAY, -1, -1
4705 Xfake_door_2, TRUE, FALSE,
4706 EL_EM_GATE_2_GRAY, -1, -1
4709 Xfake_door_3, TRUE, FALSE,
4710 EL_EM_GATE_3_GRAY, -1, -1
4713 Xfake_door_4, TRUE, FALSE,
4714 EL_EM_GATE_4_GRAY, -1, -1
4717 Xfake_door_5, TRUE, FALSE,
4718 EL_EMC_GATE_5_GRAY, -1, -1
4721 Xfake_door_6, TRUE, FALSE,
4722 EL_EMC_GATE_6_GRAY, -1, -1
4725 Xfake_door_7, TRUE, FALSE,
4726 EL_EMC_GATE_7_GRAY, -1, -1
4729 Xfake_door_8, TRUE, FALSE,
4730 EL_EMC_GATE_8_GRAY, -1, -1
4733 Xfake_acid_1, TRUE, FALSE,
4734 EL_EMC_FAKE_ACID, -1, -1
4737 Xfake_acid_2, FALSE, FALSE,
4738 EL_EMC_FAKE_ACID, -1, -1
4741 Xfake_acid_3, FALSE, FALSE,
4742 EL_EMC_FAKE_ACID, -1, -1
4745 Xfake_acid_4, FALSE, FALSE,
4746 EL_EMC_FAKE_ACID, -1, -1
4749 Xfake_acid_5, FALSE, FALSE,
4750 EL_EMC_FAKE_ACID, -1, -1
4753 Xfake_acid_6, FALSE, FALSE,
4754 EL_EMC_FAKE_ACID, -1, -1
4757 Xfake_acid_7, FALSE, FALSE,
4758 EL_EMC_FAKE_ACID, -1, -1
4761 Xfake_acid_8, FALSE, FALSE,
4762 EL_EMC_FAKE_ACID, -1, -1
4765 Xsteel_1, TRUE, FALSE,
4766 EL_STEELWALL, -1, -1
4769 Xsteel_2, TRUE, FALSE,
4770 EL_EMC_STEELWALL_2, -1, -1
4773 Xsteel_3, TRUE, FALSE,
4774 EL_EMC_STEELWALL_3, -1, -1
4777 Xsteel_4, TRUE, FALSE,
4778 EL_EMC_STEELWALL_4, -1, -1
4781 Xwall_1, TRUE, FALSE,
4785 Xwall_2, TRUE, FALSE,
4786 EL_EMC_WALL_14, -1, -1
4789 Xwall_3, TRUE, FALSE,
4790 EL_EMC_WALL_15, -1, -1
4793 Xwall_4, TRUE, FALSE,
4794 EL_EMC_WALL_16, -1, -1
4797 Xround_wall_1, TRUE, FALSE,
4798 EL_WALL_SLIPPERY, -1, -1
4801 Xround_wall_2, TRUE, FALSE,
4802 EL_EMC_WALL_SLIPPERY_2, -1, -1
4805 Xround_wall_3, TRUE, FALSE,
4806 EL_EMC_WALL_SLIPPERY_3, -1, -1
4809 Xround_wall_4, TRUE, FALSE,
4810 EL_EMC_WALL_SLIPPERY_4, -1, -1
4813 Xdecor_1, TRUE, FALSE,
4814 EL_EMC_WALL_8, -1, -1
4817 Xdecor_2, TRUE, FALSE,
4818 EL_EMC_WALL_6, -1, -1
4821 Xdecor_3, TRUE, FALSE,
4822 EL_EMC_WALL_4, -1, -1
4825 Xdecor_4, TRUE, FALSE,
4826 EL_EMC_WALL_7, -1, -1
4829 Xdecor_5, TRUE, FALSE,
4830 EL_EMC_WALL_5, -1, -1
4833 Xdecor_6, TRUE, FALSE,
4834 EL_EMC_WALL_9, -1, -1
4837 Xdecor_7, TRUE, FALSE,
4838 EL_EMC_WALL_10, -1, -1
4841 Xdecor_8, TRUE, FALSE,
4842 EL_EMC_WALL_1, -1, -1
4845 Xdecor_9, TRUE, FALSE,
4846 EL_EMC_WALL_2, -1, -1
4849 Xdecor_10, TRUE, FALSE,
4850 EL_EMC_WALL_3, -1, -1
4853 Xdecor_11, TRUE, FALSE,
4854 EL_EMC_WALL_11, -1, -1
4857 Xdecor_12, TRUE, FALSE,
4858 EL_EMC_WALL_12, -1, -1
4861 Xalpha_0, TRUE, FALSE,
4862 EL_CHAR('0'), -1, -1
4865 Xalpha_1, TRUE, FALSE,
4866 EL_CHAR('1'), -1, -1
4869 Xalpha_2, TRUE, FALSE,
4870 EL_CHAR('2'), -1, -1
4873 Xalpha_3, TRUE, FALSE,
4874 EL_CHAR('3'), -1, -1
4877 Xalpha_4, TRUE, FALSE,
4878 EL_CHAR('4'), -1, -1
4881 Xalpha_5, TRUE, FALSE,
4882 EL_CHAR('5'), -1, -1
4885 Xalpha_6, TRUE, FALSE,
4886 EL_CHAR('6'), -1, -1
4889 Xalpha_7, TRUE, FALSE,
4890 EL_CHAR('7'), -1, -1
4893 Xalpha_8, TRUE, FALSE,
4894 EL_CHAR('8'), -1, -1
4897 Xalpha_9, TRUE, FALSE,
4898 EL_CHAR('9'), -1, -1
4901 Xalpha_excla, TRUE, FALSE,
4902 EL_CHAR('!'), -1, -1
4905 Xalpha_quote, TRUE, FALSE,
4906 EL_CHAR('"'), -1, -1
4909 Xalpha_comma, TRUE, FALSE,
4910 EL_CHAR(','), -1, -1
4913 Xalpha_minus, TRUE, FALSE,
4914 EL_CHAR('-'), -1, -1
4917 Xalpha_perio, TRUE, FALSE,
4918 EL_CHAR('.'), -1, -1
4921 Xalpha_colon, TRUE, FALSE,
4922 EL_CHAR(':'), -1, -1
4925 Xalpha_quest, TRUE, FALSE,
4926 EL_CHAR('?'), -1, -1
4929 Xalpha_a, TRUE, FALSE,
4930 EL_CHAR('A'), -1, -1
4933 Xalpha_b, TRUE, FALSE,
4934 EL_CHAR('B'), -1, -1
4937 Xalpha_c, TRUE, FALSE,
4938 EL_CHAR('C'), -1, -1
4941 Xalpha_d, TRUE, FALSE,
4942 EL_CHAR('D'), -1, -1
4945 Xalpha_e, TRUE, FALSE,
4946 EL_CHAR('E'), -1, -1
4949 Xalpha_f, TRUE, FALSE,
4950 EL_CHAR('F'), -1, -1
4953 Xalpha_g, TRUE, FALSE,
4954 EL_CHAR('G'), -1, -1
4957 Xalpha_h, TRUE, FALSE,
4958 EL_CHAR('H'), -1, -1
4961 Xalpha_i, TRUE, FALSE,
4962 EL_CHAR('I'), -1, -1
4965 Xalpha_j, TRUE, FALSE,
4966 EL_CHAR('J'), -1, -1
4969 Xalpha_k, TRUE, FALSE,
4970 EL_CHAR('K'), -1, -1
4973 Xalpha_l, TRUE, FALSE,
4974 EL_CHAR('L'), -1, -1
4977 Xalpha_m, TRUE, FALSE,
4978 EL_CHAR('M'), -1, -1
4981 Xalpha_n, TRUE, FALSE,
4982 EL_CHAR('N'), -1, -1
4985 Xalpha_o, TRUE, FALSE,
4986 EL_CHAR('O'), -1, -1
4989 Xalpha_p, TRUE, FALSE,
4990 EL_CHAR('P'), -1, -1
4993 Xalpha_q, TRUE, FALSE,
4994 EL_CHAR('Q'), -1, -1
4997 Xalpha_r, TRUE, FALSE,
4998 EL_CHAR('R'), -1, -1
5001 Xalpha_s, TRUE, FALSE,
5002 EL_CHAR('S'), -1, -1
5005 Xalpha_t, TRUE, FALSE,
5006 EL_CHAR('T'), -1, -1
5009 Xalpha_u, TRUE, FALSE,
5010 EL_CHAR('U'), -1, -1
5013 Xalpha_v, TRUE, FALSE,
5014 EL_CHAR('V'), -1, -1
5017 Xalpha_w, TRUE, FALSE,
5018 EL_CHAR('W'), -1, -1
5021 Xalpha_x, TRUE, FALSE,
5022 EL_CHAR('X'), -1, -1
5025 Xalpha_y, TRUE, FALSE,
5026 EL_CHAR('Y'), -1, -1
5029 Xalpha_z, TRUE, FALSE,
5030 EL_CHAR('Z'), -1, -1
5033 Xalpha_arrow_e, TRUE, FALSE,
5034 EL_CHAR('>'), -1, -1
5037 Xalpha_arrow_w, TRUE, FALSE,
5038 EL_CHAR('<'), -1, -1
5041 Xalpha_copyr, TRUE, FALSE,
5042 EL_CHAR('©'), -1, -1
5046 Xboom_bug, FALSE, FALSE,
5047 EL_BUG, ACTION_EXPLODING, -1
5050 Xboom_bomb, FALSE, FALSE,
5051 EL_BOMB, ACTION_EXPLODING, -1
5054 Xboom_android, FALSE, FALSE,
5055 EL_EMC_ANDROID, ACTION_OTHER, -1
5058 Xboom_1, FALSE, FALSE,
5059 EL_DEFAULT, ACTION_EXPLODING, -1
5062 Xboom_2, FALSE, FALSE,
5063 EL_DEFAULT, ACTION_EXPLODING, -1
5066 Znormal, FALSE, FALSE,
5070 Zdynamite, FALSE, FALSE,
5074 Zplayer, FALSE, FALSE,
5078 ZBORDER, FALSE, FALSE,
5088 static struct Mapping_EM_to_RND_player
5097 em_player_mapping_list[] =
5101 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5105 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5109 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5113 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5117 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5121 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5125 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5129 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5133 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5137 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5141 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5145 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5149 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5153 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5157 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5161 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5165 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5169 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5173 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5177 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5181 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5185 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5189 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5193 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5197 EL_PLAYER_1, ACTION_DEFAULT, -1,
5201 EL_PLAYER_2, ACTION_DEFAULT, -1,
5205 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5209 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5213 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5217 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5221 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5225 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5229 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5233 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5237 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5241 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5245 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5249 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5253 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5257 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5261 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5265 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5269 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5273 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5277 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5281 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5285 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5289 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5293 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5297 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5301 EL_PLAYER_3, ACTION_DEFAULT, -1,
5305 EL_PLAYER_4, ACTION_DEFAULT, -1,
5314 int map_element_RND_to_EM(int element_rnd)
5316 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5317 static boolean mapping_initialized = FALSE;
5319 if (!mapping_initialized)
5323 /* return "Xalpha_quest" for all undefined elements in mapping array */
5324 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5325 mapping_RND_to_EM[i] = Xalpha_quest;
5327 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5328 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5329 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5330 em_object_mapping_list[i].element_em;
5332 mapping_initialized = TRUE;
5335 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5336 return mapping_RND_to_EM[element_rnd];
5338 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5343 int map_element_EM_to_RND(int element_em)
5345 static unsigned short mapping_EM_to_RND[TILE_MAX];
5346 static boolean mapping_initialized = FALSE;
5348 if (!mapping_initialized)
5352 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5353 for (i = 0; i < TILE_MAX; i++)
5354 mapping_EM_to_RND[i] = EL_UNKNOWN;
5356 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5357 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5358 em_object_mapping_list[i].element_rnd;
5360 mapping_initialized = TRUE;
5363 if (element_em >= 0 && element_em < TILE_MAX)
5364 return mapping_EM_to_RND[element_em];
5366 Error(ERR_WARN, "invalid EM level element %d", element_em);
5371 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5373 struct LevelInfo_EM *level_em = level->native_em_level;
5374 struct LEVEL *lev = level_em->lev;
5377 for (i = 0; i < TILE_MAX; i++)
5378 lev->android_array[i] = Xblank;
5380 for (i = 0; i < level->num_android_clone_elements; i++)
5382 int element_rnd = level->android_clone_element[i];
5383 int element_em = map_element_RND_to_EM(element_rnd);
5385 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5386 if (em_object_mapping_list[j].element_rnd == element_rnd)
5387 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5391 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5393 struct LevelInfo_EM *level_em = level->native_em_level;
5394 struct LEVEL *lev = level_em->lev;
5397 level->num_android_clone_elements = 0;
5399 for (i = 0; i < TILE_MAX; i++)
5401 int element_em = lev->android_array[i];
5403 boolean element_found = FALSE;
5405 if (element_em == Xblank)
5408 element_rnd = map_element_EM_to_RND(element_em);
5410 for (j = 0; j < level->num_android_clone_elements; j++)
5411 if (level->android_clone_element[j] == element_rnd)
5412 element_found = TRUE;
5416 level->android_clone_element[level->num_android_clone_elements++] =
5419 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5424 if (level->num_android_clone_elements == 0)
5426 level->num_android_clone_elements = 1;
5427 level->android_clone_element[0] = EL_EMPTY;
5431 int map_direction_RND_to_EM(int direction)
5433 return (direction == MV_UP ? 0 :
5434 direction == MV_RIGHT ? 1 :
5435 direction == MV_DOWN ? 2 :
5436 direction == MV_LEFT ? 3 :
5440 int map_direction_EM_to_RND(int direction)
5442 return (direction == 0 ? MV_UP :
5443 direction == 1 ? MV_RIGHT :
5444 direction == 2 ? MV_DOWN :
5445 direction == 3 ? MV_LEFT :
5449 int get_next_element(int element)
5453 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5454 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5455 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5456 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5457 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5458 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5459 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5460 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5461 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5462 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5463 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5465 default: return element;
5470 int el_act_dir2img(int element, int action, int direction)
5472 element = GFX_ELEMENT(element);
5474 if (direction == MV_NONE)
5475 return element_info[element].graphic[action];
5477 direction = MV_DIR_TO_BIT(direction);
5479 return element_info[element].direction_graphic[action][direction];
5482 int el_act_dir2img(int element, int action, int direction)
5484 element = GFX_ELEMENT(element);
5485 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5487 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5488 return element_info[element].direction_graphic[action][direction];
5493 static int el_act_dir2crm(int element, int action, int direction)
5495 element = GFX_ELEMENT(element);
5497 if (direction == MV_NONE)
5498 return element_info[element].crumbled[action];
5500 direction = MV_DIR_TO_BIT(direction);
5502 return element_info[element].direction_crumbled[action][direction];
5505 static int el_act_dir2crm(int element, int action, int direction)
5507 element = GFX_ELEMENT(element);
5508 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5510 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5511 return element_info[element].direction_crumbled[action][direction];
5515 int el_act2img(int element, int action)
5517 element = GFX_ELEMENT(element);
5519 return element_info[element].graphic[action];
5522 int el_act2crm(int element, int action)
5524 element = GFX_ELEMENT(element);
5526 return element_info[element].crumbled[action];
5529 int el_dir2img(int element, int direction)
5531 element = GFX_ELEMENT(element);
5533 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5536 int el2baseimg(int element)
5538 return element_info[element].graphic[ACTION_DEFAULT];
5541 int el2img(int element)
5543 element = GFX_ELEMENT(element);
5545 return element_info[element].graphic[ACTION_DEFAULT];
5548 int el2edimg(int element)
5550 element = GFX_ELEMENT(element);
5552 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5555 int el2preimg(int element)
5557 element = GFX_ELEMENT(element);
5559 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5562 int font2baseimg(int font_nr)
5564 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5567 int getNumActivePlayers_EM()
5569 int num_players = 0;
5575 for (i = 0; i < MAX_PLAYERS; i++)
5576 if (tape.player_participates[i])
5582 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5584 int game_frame_delay_value;
5586 game_frame_delay_value =
5587 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5588 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5591 if (tape.playing && tape.warp_forward && !tape.pausing)
5592 game_frame_delay_value = 0;
5594 return game_frame_delay_value;
5597 unsigned int InitRND(long seed)
5599 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5600 return InitEngineRandom_EM(seed);
5602 return InitEngineRandom_RND(seed);
5605 void InitGraphicInfo_EM(void)
5607 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5608 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5612 int num_em_gfx_errors = 0;
5614 if (graphic_info_em_object[0][0].bitmap == NULL)
5616 /* EM graphics not yet initialized in em_open_all() */
5621 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5624 /* always start with reliable default values */
5625 for (i = 0; i < TILE_MAX; i++)
5627 object_mapping[i].element_rnd = EL_UNKNOWN;
5628 object_mapping[i].is_backside = FALSE;
5629 object_mapping[i].action = ACTION_DEFAULT;
5630 object_mapping[i].direction = MV_NONE;
5633 /* always start with reliable default values */
5634 for (p = 0; p < MAX_PLAYERS; p++)
5636 for (i = 0; i < SPR_MAX; i++)
5638 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5639 player_mapping[p][i].action = ACTION_DEFAULT;
5640 player_mapping[p][i].direction = MV_NONE;
5644 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5646 int e = em_object_mapping_list[i].element_em;
5648 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5649 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5651 if (em_object_mapping_list[i].action != -1)
5652 object_mapping[e].action = em_object_mapping_list[i].action;
5654 if (em_object_mapping_list[i].direction != -1)
5655 object_mapping[e].direction =
5656 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5659 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5661 int a = em_player_mapping_list[i].action_em;
5662 int p = em_player_mapping_list[i].player_nr;
5664 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5666 if (em_player_mapping_list[i].action != -1)
5667 player_mapping[p][a].action = em_player_mapping_list[i].action;
5669 if (em_player_mapping_list[i].direction != -1)
5670 player_mapping[p][a].direction =
5671 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5674 for (i = 0; i < TILE_MAX; i++)
5676 int element = object_mapping[i].element_rnd;
5677 int action = object_mapping[i].action;
5678 int direction = object_mapping[i].direction;
5679 boolean is_backside = object_mapping[i].is_backside;
5680 boolean action_removing = (action == ACTION_DIGGING ||
5681 action == ACTION_SNAPPING ||
5682 action == ACTION_COLLECTING);
5683 boolean action_exploding = ((action == ACTION_EXPLODING ||
5684 action == ACTION_SMASHED_BY_ROCK ||
5685 action == ACTION_SMASHED_BY_SPRING) &&
5686 element != EL_DIAMOND);
5687 boolean action_active = (action == ACTION_ACTIVE);
5688 boolean action_other = (action == ACTION_OTHER);
5690 for (j = 0; j < 8; j++)
5692 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5693 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5695 i == Xdrip_stretch ? element :
5696 i == Xdrip_stretchB ? element :
5697 i == Ydrip_s1 ? element :
5698 i == Ydrip_s1B ? element :
5699 i == Xball_1B ? element :
5700 i == Xball_2 ? element :
5701 i == Xball_2B ? element :
5702 i == Yball_eat ? element :
5703 i == Ykey_1_eat ? element :
5704 i == Ykey_2_eat ? element :
5705 i == Ykey_3_eat ? element :
5706 i == Ykey_4_eat ? element :
5707 i == Ykey_5_eat ? element :
5708 i == Ykey_6_eat ? element :
5709 i == Ykey_7_eat ? element :
5710 i == Ykey_8_eat ? element :
5711 i == Ylenses_eat ? element :
5712 i == Ymagnify_eat ? element :
5713 i == Ygrass_eat ? element :
5714 i == Ydirt_eat ? element :
5715 i == Yemerald_stone ? EL_EMERALD :
5716 i == Ydiamond_stone ? EL_ROCK :
5717 i == Xsand_stonein_1 ? element :
5718 i == Xsand_stonein_2 ? element :
5719 i == Xsand_stonein_3 ? element :
5720 i == Xsand_stonein_4 ? element :
5721 is_backside ? EL_EMPTY :
5722 action_removing ? EL_EMPTY :
5724 int effective_action = (j < 7 ? action :
5725 i == Xdrip_stretch ? action :
5726 i == Xdrip_stretchB ? action :
5727 i == Ydrip_s1 ? action :
5728 i == Ydrip_s1B ? action :
5729 i == Xball_1B ? action :
5730 i == Xball_2 ? action :
5731 i == Xball_2B ? action :
5732 i == Yball_eat ? action :
5733 i == Ykey_1_eat ? action :
5734 i == Ykey_2_eat ? action :
5735 i == Ykey_3_eat ? action :
5736 i == Ykey_4_eat ? action :
5737 i == Ykey_5_eat ? action :
5738 i == Ykey_6_eat ? action :
5739 i == Ykey_7_eat ? action :
5740 i == Ykey_8_eat ? action :
5741 i == Ylenses_eat ? action :
5742 i == Ymagnify_eat ? action :
5743 i == Ygrass_eat ? action :
5744 i == Ydirt_eat ? action :
5745 i == Xsand_stonein_1 ? action :
5746 i == Xsand_stonein_2 ? action :
5747 i == Xsand_stonein_3 ? action :
5748 i == Xsand_stonein_4 ? action :
5749 i == Xsand_stoneout_1 ? action :
5750 i == Xsand_stoneout_2 ? action :
5751 i == Xboom_android ? ACTION_EXPLODING :
5752 action_exploding ? ACTION_EXPLODING :
5753 action_active ? action :
5754 action_other ? action :
5756 int graphic = (el_act_dir2img(effective_element, effective_action,
5758 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5760 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5761 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5762 boolean has_action_graphics = (graphic != base_graphic);
5763 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5764 struct GraphicInfo *g = &graphic_info[graphic];
5765 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5768 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5769 boolean special_animation = (action != ACTION_DEFAULT &&
5770 g->anim_frames == 3 &&
5771 g->anim_delay == 2 &&
5772 g->anim_mode & ANIM_LINEAR);
5773 int sync_frame = (i == Xdrip_stretch ? 7 :
5774 i == Xdrip_stretchB ? 7 :
5775 i == Ydrip_s2 ? j + 8 :
5776 i == Ydrip_s2B ? j + 8 :
5785 i == Xfake_acid_1 ? 0 :
5786 i == Xfake_acid_2 ? 10 :
5787 i == Xfake_acid_3 ? 20 :
5788 i == Xfake_acid_4 ? 30 :
5789 i == Xfake_acid_5 ? 40 :
5790 i == Xfake_acid_6 ? 50 :
5791 i == Xfake_acid_7 ? 60 :
5792 i == Xfake_acid_8 ? 70 :
5794 i == Xball_2B ? j + 8 :
5795 i == Yball_eat ? j + 1 :
5796 i == Ykey_1_eat ? j + 1 :
5797 i == Ykey_2_eat ? j + 1 :
5798 i == Ykey_3_eat ? j + 1 :
5799 i == Ykey_4_eat ? j + 1 :
5800 i == Ykey_5_eat ? j + 1 :
5801 i == Ykey_6_eat ? j + 1 :
5802 i == Ykey_7_eat ? j + 1 :
5803 i == Ykey_8_eat ? j + 1 :
5804 i == Ylenses_eat ? j + 1 :
5805 i == Ymagnify_eat ? j + 1 :
5806 i == Ygrass_eat ? j + 1 :
5807 i == Ydirt_eat ? j + 1 :
5808 i == Xamoeba_1 ? 0 :
5809 i == Xamoeba_2 ? 1 :
5810 i == Xamoeba_3 ? 2 :
5811 i == Xamoeba_4 ? 3 :
5812 i == Xamoeba_5 ? 0 :
5813 i == Xamoeba_6 ? 1 :
5814 i == Xamoeba_7 ? 2 :
5815 i == Xamoeba_8 ? 3 :
5816 i == Xexit_2 ? j + 8 :
5817 i == Xexit_3 ? j + 16 :
5818 i == Xdynamite_1 ? 0 :
5819 i == Xdynamite_2 ? 8 :
5820 i == Xdynamite_3 ? 16 :
5821 i == Xdynamite_4 ? 24 :
5822 i == Xsand_stonein_1 ? j + 1 :
5823 i == Xsand_stonein_2 ? j + 9 :
5824 i == Xsand_stonein_3 ? j + 17 :
5825 i == Xsand_stonein_4 ? j + 25 :
5826 i == Xsand_stoneout_1 && j == 0 ? 0 :
5827 i == Xsand_stoneout_1 && j == 1 ? 0 :
5828 i == Xsand_stoneout_1 && j == 2 ? 1 :
5829 i == Xsand_stoneout_1 && j == 3 ? 2 :
5830 i == Xsand_stoneout_1 && j == 4 ? 2 :
5831 i == Xsand_stoneout_1 && j == 5 ? 3 :
5832 i == Xsand_stoneout_1 && j == 6 ? 4 :
5833 i == Xsand_stoneout_1 && j == 7 ? 4 :
5834 i == Xsand_stoneout_2 && j == 0 ? 5 :
5835 i == Xsand_stoneout_2 && j == 1 ? 6 :
5836 i == Xsand_stoneout_2 && j == 2 ? 7 :
5837 i == Xsand_stoneout_2 && j == 3 ? 8 :
5838 i == Xsand_stoneout_2 && j == 4 ? 9 :
5839 i == Xsand_stoneout_2 && j == 5 ? 11 :
5840 i == Xsand_stoneout_2 && j == 6 ? 13 :
5841 i == Xsand_stoneout_2 && j == 7 ? 15 :
5842 i == Xboom_bug && j == 1 ? 2 :
5843 i == Xboom_bug && j == 2 ? 2 :
5844 i == Xboom_bug && j == 3 ? 4 :
5845 i == Xboom_bug && j == 4 ? 4 :
5846 i == Xboom_bug && j == 5 ? 2 :
5847 i == Xboom_bug && j == 6 ? 2 :
5848 i == Xboom_bug && j == 7 ? 0 :
5849 i == Xboom_bomb && j == 1 ? 2 :
5850 i == Xboom_bomb && j == 2 ? 2 :
5851 i == Xboom_bomb && j == 3 ? 4 :
5852 i == Xboom_bomb && j == 4 ? 4 :
5853 i == Xboom_bomb && j == 5 ? 2 :
5854 i == Xboom_bomb && j == 6 ? 2 :
5855 i == Xboom_bomb && j == 7 ? 0 :
5856 i == Xboom_android && j == 7 ? 6 :
5857 i == Xboom_1 && j == 1 ? 2 :
5858 i == Xboom_1 && j == 2 ? 2 :
5859 i == Xboom_1 && j == 3 ? 4 :
5860 i == Xboom_1 && j == 4 ? 4 :
5861 i == Xboom_1 && j == 5 ? 6 :
5862 i == Xboom_1 && j == 6 ? 6 :
5863 i == Xboom_1 && j == 7 ? 8 :
5864 i == Xboom_2 && j == 0 ? 8 :
5865 i == Xboom_2 && j == 1 ? 8 :
5866 i == Xboom_2 && j == 2 ? 10 :
5867 i == Xboom_2 && j == 3 ? 10 :
5868 i == Xboom_2 && j == 4 ? 10 :
5869 i == Xboom_2 && j == 5 ? 12 :
5870 i == Xboom_2 && j == 6 ? 12 :
5871 i == Xboom_2 && j == 7 ? 12 :
5872 special_animation && j == 4 ? 3 :
5873 effective_action != action ? 0 :
5877 Bitmap *debug_bitmap = g_em->bitmap;
5878 int debug_src_x = g_em->src_x;
5879 int debug_src_y = g_em->src_y;
5882 int frame = getAnimationFrame(g->anim_frames,
5885 g->anim_start_frame,
5888 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5889 g->double_movement && is_backside);
5891 g_em->bitmap = src_bitmap;
5892 g_em->src_x = src_x;
5893 g_em->src_y = src_y;
5894 g_em->src_offset_x = 0;
5895 g_em->src_offset_y = 0;
5896 g_em->dst_offset_x = 0;
5897 g_em->dst_offset_y = 0;
5898 g_em->width = TILEX;
5899 g_em->height = TILEY;
5901 g_em->crumbled_bitmap = NULL;
5902 g_em->crumbled_src_x = 0;
5903 g_em->crumbled_src_y = 0;
5904 g_em->crumbled_border_size = 0;
5906 g_em->has_crumbled_graphics = FALSE;
5907 g_em->preserve_background = FALSE;
5910 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5911 printf("::: empty crumbled: %d [%s], %d, %d\n",
5912 effective_element, element_info[effective_element].token_name,
5913 effective_action, direction);
5916 /* if element can be crumbled, but certain action graphics are just empty
5917 space (like snapping sand with the original R'n'D graphics), do not
5918 treat these empty space graphics as crumbled graphics in EMC engine */
5919 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5921 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5923 g_em->has_crumbled_graphics = TRUE;
5924 g_em->crumbled_bitmap = src_bitmap;
5925 g_em->crumbled_src_x = src_x;
5926 g_em->crumbled_src_y = src_y;
5927 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5931 if (element == EL_ROCK &&
5932 effective_action == ACTION_FILLING)
5933 printf("::: has_action_graphics == %d\n", has_action_graphics);
5936 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5937 effective_action == ACTION_MOVING ||
5938 effective_action == ACTION_PUSHING ||
5939 effective_action == ACTION_EATING)) ||
5940 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5941 effective_action == ACTION_EMPTYING)))
5944 (effective_action == ACTION_FALLING ||
5945 effective_action == ACTION_FILLING ||
5946 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5947 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5948 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5949 int num_steps = (i == Ydrip_s1 ? 16 :
5950 i == Ydrip_s1B ? 16 :
5951 i == Ydrip_s2 ? 16 :
5952 i == Ydrip_s2B ? 16 :
5953 i == Xsand_stonein_1 ? 32 :
5954 i == Xsand_stonein_2 ? 32 :
5955 i == Xsand_stonein_3 ? 32 :
5956 i == Xsand_stonein_4 ? 32 :
5957 i == Xsand_stoneout_1 ? 16 :
5958 i == Xsand_stoneout_2 ? 16 : 8);
5959 int cx = ABS(dx) * (TILEX / num_steps);
5960 int cy = ABS(dy) * (TILEY / num_steps);
5961 int step_frame = (i == Ydrip_s2 ? j + 8 :
5962 i == Ydrip_s2B ? j + 8 :
5963 i == Xsand_stonein_2 ? j + 8 :
5964 i == Xsand_stonein_3 ? j + 16 :
5965 i == Xsand_stonein_4 ? j + 24 :
5966 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5967 int step = (is_backside ? step_frame : num_steps - step_frame);
5969 if (is_backside) /* tile where movement starts */
5971 if (dx < 0 || dy < 0)
5973 g_em->src_offset_x = cx * step;
5974 g_em->src_offset_y = cy * step;
5978 g_em->dst_offset_x = cx * step;
5979 g_em->dst_offset_y = cy * step;
5982 else /* tile where movement ends */
5984 if (dx < 0 || dy < 0)
5986 g_em->dst_offset_x = cx * step;
5987 g_em->dst_offset_y = cy * step;
5991 g_em->src_offset_x = cx * step;
5992 g_em->src_offset_y = cy * step;
5996 g_em->width = TILEX - cx * step;
5997 g_em->height = TILEY - cy * step;
6000 /* create unique graphic identifier to decide if tile must be redrawn */
6001 /* bit 31 - 16 (16 bit): EM style graphic
6002 bit 15 - 12 ( 4 bit): EM style frame
6003 bit 11 - 6 ( 6 bit): graphic width
6004 bit 5 - 0 ( 6 bit): graphic height */
6005 g_em->unique_identifier =
6006 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6010 /* skip check for EMC elements not contained in original EMC artwork */
6011 if (element == EL_EMC_FAKE_ACID)
6014 if (g_em->bitmap != debug_bitmap ||
6015 g_em->src_x != debug_src_x ||
6016 g_em->src_y != debug_src_y ||
6017 g_em->src_offset_x != 0 ||
6018 g_em->src_offset_y != 0 ||
6019 g_em->dst_offset_x != 0 ||
6020 g_em->dst_offset_y != 0 ||
6021 g_em->width != TILEX ||
6022 g_em->height != TILEY)
6024 static int last_i = -1;
6032 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6033 i, element, element_info[element].token_name,
6034 element_action_info[effective_action].suffix, direction);
6036 if (element != effective_element)
6037 printf(" [%d ('%s')]",
6039 element_info[effective_element].token_name);
6043 if (g_em->bitmap != debug_bitmap)
6044 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6045 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6047 if (g_em->src_x != debug_src_x ||
6048 g_em->src_y != debug_src_y)
6049 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6050 j, (is_backside ? 'B' : 'F'),
6051 g_em->src_x, g_em->src_y,
6052 g_em->src_x / 32, g_em->src_y / 32,
6053 debug_src_x, debug_src_y,
6054 debug_src_x / 32, debug_src_y / 32);
6056 if (g_em->src_offset_x != 0 ||
6057 g_em->src_offset_y != 0 ||
6058 g_em->dst_offset_x != 0 ||
6059 g_em->dst_offset_y != 0)
6060 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6062 g_em->src_offset_x, g_em->src_offset_y,
6063 g_em->dst_offset_x, g_em->dst_offset_y);
6065 if (g_em->width != TILEX ||
6066 g_em->height != TILEY)
6067 printf(" %d (%d): size %d,%d should be %d,%d\n",
6069 g_em->width, g_em->height, TILEX, TILEY);
6071 num_em_gfx_errors++;
6078 for (i = 0; i < TILE_MAX; i++)
6080 for (j = 0; j < 8; j++)
6082 int element = object_mapping[i].element_rnd;
6083 int action = object_mapping[i].action;
6084 int direction = object_mapping[i].direction;
6085 boolean is_backside = object_mapping[i].is_backside;
6086 int graphic_action = el_act_dir2img(element, action, direction);
6087 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6089 if ((action == ACTION_SMASHED_BY_ROCK ||
6090 action == ACTION_SMASHED_BY_SPRING ||
6091 action == ACTION_EATING) &&
6092 graphic_action == graphic_default)
6094 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6095 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6096 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6097 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6100 /* no separate animation for "smashed by rock" -- use rock instead */
6101 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6102 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6104 g_em->bitmap = g_xx->bitmap;
6105 g_em->src_x = g_xx->src_x;
6106 g_em->src_y = g_xx->src_y;
6107 g_em->src_offset_x = g_xx->src_offset_x;
6108 g_em->src_offset_y = g_xx->src_offset_y;
6109 g_em->dst_offset_x = g_xx->dst_offset_x;
6110 g_em->dst_offset_y = g_xx->dst_offset_y;
6111 g_em->width = g_xx->width;
6112 g_em->height = g_xx->height;
6113 g_em->unique_identifier = g_xx->unique_identifier;
6116 g_em->preserve_background = TRUE;
6121 for (p = 0; p < MAX_PLAYERS; p++)
6123 for (i = 0; i < SPR_MAX; i++)
6125 int element = player_mapping[p][i].element_rnd;
6126 int action = player_mapping[p][i].action;
6127 int direction = player_mapping[p][i].direction;
6129 for (j = 0; j < 8; j++)
6131 int effective_element = element;
6132 int effective_action = action;
6133 int graphic = (direction == MV_NONE ?
6134 el_act2img(effective_element, effective_action) :
6135 el_act_dir2img(effective_element, effective_action,
6137 struct GraphicInfo *g = &graphic_info[graphic];
6138 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6144 Bitmap *debug_bitmap = g_em->bitmap;
6145 int debug_src_x = g_em->src_x;
6146 int debug_src_y = g_em->src_y;
6149 int frame = getAnimationFrame(g->anim_frames,
6152 g->anim_start_frame,
6155 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6157 g_em->bitmap = src_bitmap;
6158 g_em->src_x = src_x;
6159 g_em->src_y = src_y;
6160 g_em->src_offset_x = 0;
6161 g_em->src_offset_y = 0;
6162 g_em->dst_offset_x = 0;
6163 g_em->dst_offset_y = 0;
6164 g_em->width = TILEX;
6165 g_em->height = TILEY;
6169 /* skip check for EMC elements not contained in original EMC artwork */
6170 if (element == EL_PLAYER_3 ||
6171 element == EL_PLAYER_4)
6174 if (g_em->bitmap != debug_bitmap ||
6175 g_em->src_x != debug_src_x ||
6176 g_em->src_y != debug_src_y)
6178 static int last_i = -1;
6186 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6187 p, i, element, element_info[element].token_name,
6188 element_action_info[effective_action].suffix, direction);
6190 if (element != effective_element)
6191 printf(" [%d ('%s')]",
6193 element_info[effective_element].token_name);
6197 if (g_em->bitmap != debug_bitmap)
6198 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6199 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6201 if (g_em->src_x != debug_src_x ||
6202 g_em->src_y != debug_src_y)
6203 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6205 g_em->src_x, g_em->src_y,
6206 g_em->src_x / 32, g_em->src_y / 32,
6207 debug_src_x, debug_src_y,
6208 debug_src_x / 32, debug_src_y / 32);
6210 num_em_gfx_errors++;
6220 printf("::: [%d errors found]\n", num_em_gfx_errors);
6226 void PlayMenuSound()
6228 int sound = menu.sound[game_status];
6230 if (sound == SND_UNDEFINED)
6233 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6234 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6237 if (IS_LOOP_SOUND(sound))
6238 PlaySoundLoop(sound);
6243 void PlayMenuSoundStereo(int sound, int stereo_position)
6245 if (sound == SND_UNDEFINED)
6248 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6249 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6252 if (IS_LOOP_SOUND(sound))
6253 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6255 PlaySoundStereo(sound, stereo_position);
6258 void PlayMenuSoundIfLoop()
6260 int sound = menu.sound[game_status];
6262 if (sound == SND_UNDEFINED)
6265 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6266 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6269 if (IS_LOOP_SOUND(sound))
6270 PlaySoundLoop(sound);
6273 void PlayMenuMusic()
6275 int music = menu.music[game_status];
6277 if (music == MUS_UNDEFINED)
6280 if (!setup.sound_music)
6286 void PlaySoundActivating()
6289 PlaySound(SND_MENU_ITEM_ACTIVATING);
6293 void PlaySoundSelecting()
6296 PlaySound(SND_MENU_ITEM_SELECTING);
6300 void ToggleFullscreenIfNeeded()
6302 boolean change_fullscreen = (setup.fullscreen !=
6303 video.fullscreen_enabled);
6304 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6305 !strEqual(setup.fullscreen_mode,
6306 video.fullscreen_mode_current));
6308 if (!video.fullscreen_available)
6312 if (change_fullscreen || change_fullscreen_mode)
6314 if (setup.fullscreen != video.fullscreen_enabled ||
6315 setup.fullscreen_mode != video.fullscreen_mode_current)
6318 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6320 /* save backbuffer content which gets lost when toggling fullscreen mode */
6321 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6324 if (change_fullscreen_mode)
6326 if (setup.fullscreen && video.fullscreen_enabled)
6329 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6331 /* (this is now set in sdl.c) */
6333 video.fullscreen_mode_current = setup.fullscreen_mode;
6335 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6338 /* toggle fullscreen */
6339 ChangeVideoModeIfNeeded(setup.fullscreen);
6341 setup.fullscreen = video.fullscreen_enabled;
6343 /* restore backbuffer content from temporary backbuffer backup bitmap */
6344 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6346 FreeBitmap(tmp_backbuffer);
6349 /* update visible window/screen */
6350 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6352 redraw_mask = REDRAW_ALL;