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)
2797 if (!PendingEvent()) /* delay only if no pending events */
2800 /* don't eat all CPU time */
2805 if (game_status != GAME_MODE_MAIN)
2810 if (!(req_state & REQ_STAY_OPEN))
2812 CloseDoor(DOOR_CLOSE_1);
2814 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2815 (req_state & REQ_REOPEN))
2816 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2821 if (game_status == GAME_MODE_PLAYING)
2823 SetPanelBackground();
2824 SetDrawBackgroundMask(REDRAW_DOOR_1);
2828 SetDrawBackgroundMask(REDRAW_FIELD);
2831 #if defined(NETWORK_AVALIABLE)
2832 /* continue network game after request */
2833 if (options.network &&
2834 game_status == GAME_MODE_PLAYING &&
2835 req_state & REQUEST_WAIT_FOR_INPUT)
2836 SendToServer_ContinuePlaying();
2839 /* restore deactivated drawing when quick-loading level tape recording */
2840 if (tape.playing && tape.deactivate_display)
2841 TapeDeactivateDisplayOn();
2846 unsigned int OpenDoor(unsigned int door_state)
2848 if (door_state & DOOR_COPY_BACK)
2850 if (door_state & DOOR_OPEN_1)
2851 BlitBitmap(bitmap_db_door, bitmap_db_door,
2852 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2853 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2855 if (door_state & DOOR_OPEN_2)
2856 BlitBitmap(bitmap_db_door, bitmap_db_door,
2857 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2858 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2860 door_state &= ~DOOR_COPY_BACK;
2863 return MoveDoor(door_state);
2866 unsigned int CloseDoor(unsigned int door_state)
2868 unsigned int old_door_state = GetDoorState();
2870 if (!(door_state & DOOR_NO_COPY_BACK))
2872 if (old_door_state & DOOR_OPEN_1)
2873 BlitBitmap(backbuffer, bitmap_db_door,
2874 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2876 if (old_door_state & DOOR_OPEN_2)
2877 BlitBitmap(backbuffer, bitmap_db_door,
2878 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2880 door_state &= ~DOOR_NO_COPY_BACK;
2883 return MoveDoor(door_state);
2886 unsigned int GetDoorState()
2888 return MoveDoor(DOOR_GET_STATE);
2891 unsigned int SetDoorState(unsigned int door_state)
2893 return MoveDoor(door_state | DOOR_SET_STATE);
2896 unsigned int MoveDoor(unsigned int door_state)
2898 static int door1 = DOOR_OPEN_1;
2899 static int door2 = DOOR_CLOSE_2;
2900 unsigned long door_delay = 0;
2901 unsigned long door_delay_value;
2904 if (door_1.width < 0 || door_1.width > DXSIZE)
2905 door_1.width = DXSIZE;
2906 if (door_1.height < 0 || door_1.height > DYSIZE)
2907 door_1.height = DYSIZE;
2908 if (door_2.width < 0 || door_2.width > VXSIZE)
2909 door_2.width = VXSIZE;
2910 if (door_2.height < 0 || door_2.height > VYSIZE)
2911 door_2.height = VYSIZE;
2913 if (door_state == DOOR_GET_STATE)
2914 return (door1 | door2);
2916 if (door_state & DOOR_SET_STATE)
2918 if (door_state & DOOR_ACTION_1)
2919 door1 = door_state & DOOR_ACTION_1;
2920 if (door_state & DOOR_ACTION_2)
2921 door2 = door_state & DOOR_ACTION_2;
2923 return (door1 | door2);
2926 if (!(door_state & DOOR_FORCE_REDRAW))
2928 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2929 door_state &= ~DOOR_OPEN_1;
2930 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2931 door_state &= ~DOOR_CLOSE_1;
2932 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2933 door_state &= ~DOOR_OPEN_2;
2934 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2935 door_state &= ~DOOR_CLOSE_2;
2938 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2941 if (setup.quick_doors)
2943 stepsize = 20; /* must be choosen to always draw last frame */
2944 door_delay_value = 0;
2947 if (global.autoplay_leveldir)
2949 door_state |= DOOR_NO_DELAY;
2950 door_state &= ~DOOR_CLOSE_ALL;
2953 if (door_state & DOOR_ACTION)
2955 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2956 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2957 boolean door_1_done = (!handle_door_1);
2958 boolean door_2_done = (!handle_door_2);
2959 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2960 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2961 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2962 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2963 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2964 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2965 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2966 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2967 int door_skip = max_door_size - door_size;
2968 int end = door_size;
2969 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2972 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2974 /* opening door sound has priority over simultaneously closing door */
2975 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2976 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2977 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2978 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2981 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2984 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2985 GC gc = bitmap->stored_clip_gc;
2987 if (door_state & DOOR_ACTION_1)
2989 int a = MIN(x * door_1.step_offset, end);
2990 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2991 int i = p + door_skip;
2993 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2995 BlitBitmap(bitmap_db_door, drawto,
2996 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2997 DXSIZE, DYSIZE, DX, DY);
3001 BlitBitmap(bitmap_db_door, drawto,
3002 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3003 DXSIZE, DYSIZE - p / 2, DX, DY);
3005 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3008 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3010 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3011 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3012 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3013 int dst2_x = DX, dst2_y = DY;
3014 int width = i, height = DYSIZE;
3016 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3017 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3020 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3021 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3024 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3026 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3027 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3028 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3029 int dst2_x = DX, dst2_y = DY;
3030 int width = DXSIZE, height = i;
3032 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3033 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3036 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3037 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3040 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3042 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3044 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3045 BlitBitmapMasked(bitmap, drawto,
3046 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3047 DX + DXSIZE - i, DY + j);
3048 BlitBitmapMasked(bitmap, drawto,
3049 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3050 DX + DXSIZE - i, DY + 140 + j);
3051 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3052 DY - (DOOR_GFX_PAGEY1 + j));
3053 BlitBitmapMasked(bitmap, drawto,
3054 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3056 BlitBitmapMasked(bitmap, drawto,
3057 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3060 BlitBitmapMasked(bitmap, drawto,
3061 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3063 BlitBitmapMasked(bitmap, drawto,
3064 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3066 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3067 BlitBitmapMasked(bitmap, drawto,
3068 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3069 DX + DXSIZE - i, DY + 77 + j);
3070 BlitBitmapMasked(bitmap, drawto,
3071 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3072 DX + DXSIZE - i, DY + 203 + j);
3075 redraw_mask |= REDRAW_DOOR_1;
3076 door_1_done = (a == end);
3079 if (door_state & DOOR_ACTION_2)
3081 int a = MIN(x * door_2.step_offset, door_size);
3082 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3083 int i = p + door_skip;
3085 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3087 BlitBitmap(bitmap_db_door, drawto,
3088 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3089 VXSIZE, VYSIZE, VX, VY);
3091 else if (x <= VYSIZE)
3093 BlitBitmap(bitmap_db_door, drawto,
3094 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3095 VXSIZE, VYSIZE - p / 2, VX, VY);
3097 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3100 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3102 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3103 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3104 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3105 int dst2_x = VX, dst2_y = VY;
3106 int width = i, height = VYSIZE;
3108 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3109 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3112 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3113 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3116 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3118 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3119 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3120 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3121 int dst2_x = VX, dst2_y = VY;
3122 int width = VXSIZE, height = i;
3124 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3125 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3128 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3129 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3132 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3134 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3136 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3137 BlitBitmapMasked(bitmap, drawto,
3138 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3139 VX + VXSIZE - i, VY + j);
3140 SetClipOrigin(bitmap, gc,
3141 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3142 BlitBitmapMasked(bitmap, drawto,
3143 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3146 BlitBitmapMasked(bitmap, drawto,
3147 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3148 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3149 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3150 BlitBitmapMasked(bitmap, drawto,
3151 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3153 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3156 redraw_mask |= REDRAW_DOOR_2;
3157 door_2_done = (a == VXSIZE);
3160 if (!(door_state & DOOR_NO_DELAY))
3164 if (game_status == GAME_MODE_MAIN)
3167 WaitUntilDelayReached(&door_delay, door_delay_value);
3172 if (door_state & DOOR_ACTION_1)
3173 door1 = door_state & DOOR_ACTION_1;
3174 if (door_state & DOOR_ACTION_2)
3175 door2 = door_state & DOOR_ACTION_2;
3177 return (door1 | door2);
3180 void DrawSpecialEditorDoor()
3182 /* draw bigger toolbox window */
3183 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3184 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3186 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3187 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3190 redraw_mask |= REDRAW_ALL;
3193 void UndrawSpecialEditorDoor()
3195 /* draw normal tape recorder window */
3196 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3197 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3200 redraw_mask |= REDRAW_ALL;
3204 /* ---------- new tool button stuff ---------------------------------------- */
3206 /* graphic position values for tool buttons */
3207 #define TOOL_BUTTON_YES_XPOS 2
3208 #define TOOL_BUTTON_YES_YPOS 250
3209 #define TOOL_BUTTON_YES_GFX_YPOS 0
3210 #define TOOL_BUTTON_YES_XSIZE 46
3211 #define TOOL_BUTTON_YES_YSIZE 28
3212 #define TOOL_BUTTON_NO_XPOS 52
3213 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3214 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3215 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3216 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3217 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3218 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3219 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3220 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3221 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3222 #define TOOL_BUTTON_PLAYER_XSIZE 30
3223 #define TOOL_BUTTON_PLAYER_YSIZE 30
3224 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3225 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3226 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3227 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3228 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3229 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3230 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3231 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3232 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3233 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3234 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3235 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3236 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3237 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3238 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3239 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3240 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3241 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3242 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3243 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3252 } toolbutton_info[NUM_TOOL_BUTTONS] =
3255 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3256 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3257 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3262 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3263 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3264 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3269 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3270 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3271 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3272 TOOL_CTRL_ID_CONFIRM,
3276 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3277 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3278 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3279 TOOL_CTRL_ID_PLAYER_1,
3283 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3284 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3285 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3286 TOOL_CTRL_ID_PLAYER_2,
3290 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3291 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3292 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3293 TOOL_CTRL_ID_PLAYER_3,
3297 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3298 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3299 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3300 TOOL_CTRL_ID_PLAYER_4,
3305 void CreateToolButtons()
3309 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3311 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3312 Bitmap *deco_bitmap = None;
3313 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3314 struct GadgetInfo *gi;
3315 unsigned long event_mask;
3316 int gd_xoffset, gd_yoffset;
3317 int gd_x1, gd_x2, gd_y;
3320 event_mask = GD_EVENT_RELEASED;
3322 gd_xoffset = toolbutton_info[i].xpos;
3323 gd_yoffset = toolbutton_info[i].ypos;
3324 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3325 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3326 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3328 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3330 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3332 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3333 &deco_bitmap, &deco_x, &deco_y);
3334 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3335 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3338 gi = CreateGadget(GDI_CUSTOM_ID, id,
3339 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3340 GDI_X, DX + toolbutton_info[i].x,
3341 GDI_Y, DY + toolbutton_info[i].y,
3342 GDI_WIDTH, toolbutton_info[i].width,
3343 GDI_HEIGHT, toolbutton_info[i].height,
3344 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3345 GDI_STATE, GD_BUTTON_UNPRESSED,
3346 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3347 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3348 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3349 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3350 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3351 GDI_DECORATION_SHIFTING, 1, 1,
3352 GDI_DIRECT_DRAW, FALSE,
3353 GDI_EVENT_MASK, event_mask,
3354 GDI_CALLBACK_ACTION, HandleToolButtons,
3358 Error(ERR_EXIT, "cannot create gadget");
3360 tool_gadget[id] = gi;
3364 void FreeToolButtons()
3368 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3369 FreeGadget(tool_gadget[i]);
3372 static void UnmapToolButtons()
3376 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3377 UnmapGadget(tool_gadget[i]);
3380 static void HandleToolButtons(struct GadgetInfo *gi)
3382 request_gadget_id = gi->custom_id;
3385 static struct Mapping_EM_to_RND_object
3388 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3389 boolean is_backside; /* backside of moving element */
3395 em_object_mapping_list[] =
3398 Xblank, TRUE, FALSE,
3402 Yacid_splash_eB, FALSE, FALSE,
3403 EL_ACID_SPLASH_RIGHT, -1, -1
3406 Yacid_splash_wB, FALSE, FALSE,
3407 EL_ACID_SPLASH_LEFT, -1, -1
3410 #ifdef EM_ENGINE_BAD_ROLL
3412 Xstone_force_e, FALSE, FALSE,
3413 EL_ROCK, -1, MV_BIT_RIGHT
3416 Xstone_force_w, FALSE, FALSE,
3417 EL_ROCK, -1, MV_BIT_LEFT
3420 Xnut_force_e, FALSE, FALSE,
3421 EL_NUT, -1, MV_BIT_RIGHT
3424 Xnut_force_w, FALSE, FALSE,
3425 EL_NUT, -1, MV_BIT_LEFT
3428 Xspring_force_e, FALSE, FALSE,
3429 EL_SPRING, -1, MV_BIT_RIGHT
3432 Xspring_force_w, FALSE, FALSE,
3433 EL_SPRING, -1, MV_BIT_LEFT
3436 Xemerald_force_e, FALSE, FALSE,
3437 EL_EMERALD, -1, MV_BIT_RIGHT
3440 Xemerald_force_w, FALSE, FALSE,
3441 EL_EMERALD, -1, MV_BIT_LEFT
3444 Xdiamond_force_e, FALSE, FALSE,
3445 EL_DIAMOND, -1, MV_BIT_RIGHT
3448 Xdiamond_force_w, FALSE, FALSE,
3449 EL_DIAMOND, -1, MV_BIT_LEFT
3452 Xbomb_force_e, FALSE, FALSE,
3453 EL_BOMB, -1, MV_BIT_RIGHT
3456 Xbomb_force_w, FALSE, FALSE,
3457 EL_BOMB, -1, MV_BIT_LEFT
3459 #endif /* EM_ENGINE_BAD_ROLL */
3462 Xstone, TRUE, FALSE,
3466 Xstone_pause, FALSE, FALSE,
3470 Xstone_fall, FALSE, FALSE,
3474 Ystone_s, FALSE, FALSE,
3475 EL_ROCK, ACTION_FALLING, -1
3478 Ystone_sB, FALSE, TRUE,
3479 EL_ROCK, ACTION_FALLING, -1
3482 Ystone_e, FALSE, FALSE,
3483 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3486 Ystone_eB, FALSE, TRUE,
3487 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3490 Ystone_w, FALSE, FALSE,
3491 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3494 Ystone_wB, FALSE, TRUE,
3495 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3502 Xnut_pause, FALSE, FALSE,
3506 Xnut_fall, FALSE, FALSE,
3510 Ynut_s, FALSE, FALSE,
3511 EL_NUT, ACTION_FALLING, -1
3514 Ynut_sB, FALSE, TRUE,
3515 EL_NUT, ACTION_FALLING, -1
3518 Ynut_e, FALSE, FALSE,
3519 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3522 Ynut_eB, FALSE, TRUE,
3523 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3526 Ynut_w, FALSE, FALSE,
3527 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3530 Ynut_wB, FALSE, TRUE,
3531 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3534 Xbug_n, TRUE, FALSE,
3538 Xbug_e, TRUE, FALSE,
3539 EL_BUG_RIGHT, -1, -1
3542 Xbug_s, TRUE, FALSE,
3546 Xbug_w, TRUE, FALSE,
3550 Xbug_gon, FALSE, FALSE,
3554 Xbug_goe, FALSE, FALSE,
3555 EL_BUG_RIGHT, -1, -1
3558 Xbug_gos, FALSE, FALSE,
3562 Xbug_gow, FALSE, FALSE,
3566 Ybug_n, FALSE, FALSE,
3567 EL_BUG, ACTION_MOVING, MV_BIT_UP
3570 Ybug_nB, FALSE, TRUE,
3571 EL_BUG, ACTION_MOVING, MV_BIT_UP
3574 Ybug_e, FALSE, FALSE,
3575 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3578 Ybug_eB, FALSE, TRUE,
3579 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3582 Ybug_s, FALSE, FALSE,
3583 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3586 Ybug_sB, FALSE, TRUE,
3587 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3590 Ybug_w, FALSE, FALSE,
3591 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3594 Ybug_wB, FALSE, TRUE,
3595 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3598 Ybug_w_n, FALSE, FALSE,
3599 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3602 Ybug_n_e, FALSE, FALSE,
3603 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3606 Ybug_e_s, FALSE, FALSE,
3607 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3610 Ybug_s_w, FALSE, FALSE,
3611 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3614 Ybug_e_n, FALSE, FALSE,
3615 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3618 Ybug_s_e, FALSE, FALSE,
3619 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3622 Ybug_w_s, FALSE, FALSE,
3623 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3626 Ybug_n_w, FALSE, FALSE,
3627 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3630 Ybug_stone, FALSE, FALSE,
3631 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3634 Ybug_spring, FALSE, FALSE,
3635 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3638 Xtank_n, TRUE, FALSE,
3639 EL_SPACESHIP_UP, -1, -1
3642 Xtank_e, TRUE, FALSE,
3643 EL_SPACESHIP_RIGHT, -1, -1
3646 Xtank_s, TRUE, FALSE,
3647 EL_SPACESHIP_DOWN, -1, -1
3650 Xtank_w, TRUE, FALSE,
3651 EL_SPACESHIP_LEFT, -1, -1
3654 Xtank_gon, FALSE, FALSE,
3655 EL_SPACESHIP_UP, -1, -1
3658 Xtank_goe, FALSE, FALSE,
3659 EL_SPACESHIP_RIGHT, -1, -1
3662 Xtank_gos, FALSE, FALSE,
3663 EL_SPACESHIP_DOWN, -1, -1
3666 Xtank_gow, FALSE, FALSE,
3667 EL_SPACESHIP_LEFT, -1, -1
3670 Ytank_n, FALSE, FALSE,
3671 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3674 Ytank_nB, FALSE, TRUE,
3675 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3678 Ytank_e, FALSE, FALSE,
3679 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3682 Ytank_eB, FALSE, TRUE,
3683 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3686 Ytank_s, FALSE, FALSE,
3687 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3690 Ytank_sB, FALSE, TRUE,
3691 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3694 Ytank_w, FALSE, FALSE,
3695 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3698 Ytank_wB, FALSE, TRUE,
3699 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3702 Ytank_w_n, FALSE, FALSE,
3703 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3706 Ytank_n_e, FALSE, FALSE,
3707 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3710 Ytank_e_s, FALSE, FALSE,
3711 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3714 Ytank_s_w, FALSE, FALSE,
3715 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3718 Ytank_e_n, FALSE, FALSE,
3719 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3722 Ytank_s_e, FALSE, FALSE,
3723 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3726 Ytank_w_s, FALSE, FALSE,
3727 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3730 Ytank_n_w, FALSE, FALSE,
3731 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3734 Ytank_stone, FALSE, FALSE,
3735 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3738 Ytank_spring, FALSE, FALSE,
3739 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3742 Xandroid, TRUE, FALSE,
3743 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3746 Xandroid_1_n, FALSE, FALSE,
3747 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3750 Xandroid_2_n, FALSE, FALSE,
3751 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3754 Xandroid_1_e, FALSE, FALSE,
3755 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3758 Xandroid_2_e, FALSE, FALSE,
3759 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3762 Xandroid_1_w, FALSE, FALSE,
3763 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3766 Xandroid_2_w, FALSE, FALSE,
3767 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3770 Xandroid_1_s, FALSE, FALSE,
3771 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3774 Xandroid_2_s, FALSE, FALSE,
3775 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3778 Yandroid_n, FALSE, FALSE,
3779 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3782 Yandroid_nB, FALSE, TRUE,
3783 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3786 Yandroid_ne, FALSE, FALSE,
3787 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3790 Yandroid_neB, FALSE, TRUE,
3791 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3794 Yandroid_e, FALSE, FALSE,
3795 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3798 Yandroid_eB, FALSE, TRUE,
3799 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3802 Yandroid_se, FALSE, FALSE,
3803 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3806 Yandroid_seB, FALSE, TRUE,
3807 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3810 Yandroid_s, FALSE, FALSE,
3811 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3814 Yandroid_sB, FALSE, TRUE,
3815 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3818 Yandroid_sw, FALSE, FALSE,
3819 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3822 Yandroid_swB, FALSE, TRUE,
3823 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3826 Yandroid_w, FALSE, FALSE,
3827 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3830 Yandroid_wB, FALSE, TRUE,
3831 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3834 Yandroid_nw, FALSE, FALSE,
3835 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3838 Yandroid_nwB, FALSE, TRUE,
3839 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3842 Xspring, TRUE, FALSE,
3846 Xspring_pause, FALSE, FALSE,
3850 Xspring_e, FALSE, FALSE,
3854 Xspring_w, FALSE, FALSE,
3858 Xspring_fall, FALSE, FALSE,
3862 Yspring_s, FALSE, FALSE,
3863 EL_SPRING, ACTION_FALLING, -1
3866 Yspring_sB, FALSE, TRUE,
3867 EL_SPRING, ACTION_FALLING, -1
3870 Yspring_e, FALSE, FALSE,
3871 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3874 Yspring_eB, FALSE, TRUE,
3875 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3878 Yspring_w, FALSE, FALSE,
3879 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3882 Yspring_wB, FALSE, TRUE,
3883 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3886 Yspring_kill_e, FALSE, FALSE,
3887 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3890 Yspring_kill_eB, FALSE, TRUE,
3891 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3894 Yspring_kill_w, FALSE, FALSE,
3895 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3898 Yspring_kill_wB, FALSE, TRUE,
3899 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3902 Xeater_n, TRUE, FALSE,
3903 EL_YAMYAM_UP, -1, -1
3906 Xeater_e, TRUE, FALSE,
3907 EL_YAMYAM_RIGHT, -1, -1
3910 Xeater_w, TRUE, FALSE,
3911 EL_YAMYAM_LEFT, -1, -1
3914 Xeater_s, TRUE, FALSE,
3915 EL_YAMYAM_DOWN, -1, -1
3918 Yeater_n, FALSE, FALSE,
3919 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3922 Yeater_nB, FALSE, TRUE,
3923 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3926 Yeater_e, FALSE, FALSE,
3927 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3930 Yeater_eB, FALSE, TRUE,
3931 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3934 Yeater_s, FALSE, FALSE,
3935 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3938 Yeater_sB, FALSE, TRUE,
3939 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3942 Yeater_w, FALSE, FALSE,
3943 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3946 Yeater_wB, FALSE, TRUE,
3947 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3950 Yeater_stone, FALSE, FALSE,
3951 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3954 Yeater_spring, FALSE, FALSE,
3955 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3958 Xalien, TRUE, FALSE,
3962 Xalien_pause, FALSE, FALSE,
3966 Yalien_n, FALSE, FALSE,
3967 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3970 Yalien_nB, FALSE, TRUE,
3971 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3974 Yalien_e, FALSE, FALSE,
3975 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3978 Yalien_eB, FALSE, TRUE,
3979 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3982 Yalien_s, FALSE, FALSE,
3983 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3986 Yalien_sB, FALSE, TRUE,
3987 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3990 Yalien_w, FALSE, FALSE,
3991 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3994 Yalien_wB, FALSE, TRUE,
3995 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3998 Yalien_stone, FALSE, FALSE,
3999 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4002 Yalien_spring, FALSE, FALSE,
4003 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4006 Xemerald, TRUE, FALSE,
4010 Xemerald_pause, FALSE, FALSE,
4014 Xemerald_fall, FALSE, FALSE,
4018 Xemerald_shine, FALSE, FALSE,
4019 EL_EMERALD, ACTION_TWINKLING, -1
4022 Yemerald_s, FALSE, FALSE,
4023 EL_EMERALD, ACTION_FALLING, -1
4026 Yemerald_sB, FALSE, TRUE,
4027 EL_EMERALD, ACTION_FALLING, -1
4030 Yemerald_e, FALSE, FALSE,
4031 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4034 Yemerald_eB, FALSE, TRUE,
4035 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4038 Yemerald_w, FALSE, FALSE,
4039 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4042 Yemerald_wB, FALSE, TRUE,
4043 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4046 Yemerald_eat, FALSE, FALSE,
4047 EL_EMERALD, ACTION_COLLECTING, -1
4050 Yemerald_stone, FALSE, FALSE,
4051 EL_NUT, ACTION_BREAKING, -1
4054 Xdiamond, TRUE, FALSE,
4058 Xdiamond_pause, FALSE, FALSE,
4062 Xdiamond_fall, FALSE, FALSE,
4066 Xdiamond_shine, FALSE, FALSE,
4067 EL_DIAMOND, ACTION_TWINKLING, -1
4070 Ydiamond_s, FALSE, FALSE,
4071 EL_DIAMOND, ACTION_FALLING, -1
4074 Ydiamond_sB, FALSE, TRUE,
4075 EL_DIAMOND, ACTION_FALLING, -1
4078 Ydiamond_e, FALSE, FALSE,
4079 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4082 Ydiamond_eB, FALSE, TRUE,
4083 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4086 Ydiamond_w, FALSE, FALSE,
4087 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4090 Ydiamond_wB, FALSE, TRUE,
4091 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4094 Ydiamond_eat, FALSE, FALSE,
4095 EL_DIAMOND, ACTION_COLLECTING, -1
4098 Ydiamond_stone, FALSE, FALSE,
4099 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4102 Xdrip_fall, TRUE, FALSE,
4103 EL_AMOEBA_DROP, -1, -1
4106 Xdrip_stretch, FALSE, FALSE,
4107 EL_AMOEBA_DROP, ACTION_FALLING, -1
4110 Xdrip_stretchB, FALSE, TRUE,
4111 EL_AMOEBA_DROP, ACTION_FALLING, -1
4114 Xdrip_eat, FALSE, FALSE,
4115 EL_AMOEBA_DROP, ACTION_GROWING, -1
4118 Ydrip_s1, FALSE, FALSE,
4119 EL_AMOEBA_DROP, ACTION_FALLING, -1
4122 Ydrip_s1B, FALSE, TRUE,
4123 EL_AMOEBA_DROP, ACTION_FALLING, -1
4126 Ydrip_s2, FALSE, FALSE,
4127 EL_AMOEBA_DROP, ACTION_FALLING, -1
4130 Ydrip_s2B, FALSE, TRUE,
4131 EL_AMOEBA_DROP, ACTION_FALLING, -1
4138 Xbomb_pause, FALSE, FALSE,
4142 Xbomb_fall, FALSE, FALSE,
4146 Ybomb_s, FALSE, FALSE,
4147 EL_BOMB, ACTION_FALLING, -1
4150 Ybomb_sB, FALSE, TRUE,
4151 EL_BOMB, ACTION_FALLING, -1
4154 Ybomb_e, FALSE, FALSE,
4155 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4158 Ybomb_eB, FALSE, TRUE,
4159 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4162 Ybomb_w, FALSE, FALSE,
4163 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4166 Ybomb_wB, FALSE, TRUE,
4167 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4170 Ybomb_eat, FALSE, FALSE,
4171 EL_BOMB, ACTION_ACTIVATING, -1
4174 Xballoon, TRUE, FALSE,
4178 Yballoon_n, FALSE, FALSE,
4179 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4182 Yballoon_nB, FALSE, TRUE,
4183 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4186 Yballoon_e, FALSE, FALSE,
4187 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4190 Yballoon_eB, FALSE, TRUE,
4191 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4194 Yballoon_s, FALSE, FALSE,
4195 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4198 Yballoon_sB, FALSE, TRUE,
4199 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4202 Yballoon_w, FALSE, FALSE,
4203 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4206 Yballoon_wB, FALSE, TRUE,
4207 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4210 Xgrass, TRUE, FALSE,
4211 EL_EMC_GRASS, -1, -1
4214 Ygrass_nB, FALSE, FALSE,
4215 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4218 Ygrass_eB, FALSE, FALSE,
4219 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4222 Ygrass_sB, FALSE, FALSE,
4223 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4226 Ygrass_wB, FALSE, FALSE,
4227 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4234 Ydirt_nB, FALSE, FALSE,
4235 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4238 Ydirt_eB, FALSE, FALSE,
4239 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4242 Ydirt_sB, FALSE, FALSE,
4243 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4246 Ydirt_wB, FALSE, FALSE,
4247 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4250 Xacid_ne, TRUE, FALSE,
4251 EL_ACID_POOL_TOPRIGHT, -1, -1
4254 Xacid_se, TRUE, FALSE,
4255 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4258 Xacid_s, TRUE, FALSE,
4259 EL_ACID_POOL_BOTTOM, -1, -1
4262 Xacid_sw, TRUE, FALSE,
4263 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4266 Xacid_nw, TRUE, FALSE,
4267 EL_ACID_POOL_TOPLEFT, -1, -1
4270 Xacid_1, TRUE, FALSE,
4274 Xacid_2, FALSE, FALSE,
4278 Xacid_3, FALSE, FALSE,
4282 Xacid_4, FALSE, FALSE,
4286 Xacid_5, FALSE, FALSE,
4290 Xacid_6, FALSE, FALSE,
4294 Xacid_7, FALSE, FALSE,
4298 Xacid_8, FALSE, FALSE,
4302 Xball_1, TRUE, FALSE,
4303 EL_EMC_MAGIC_BALL, -1, -1
4306 Xball_1B, FALSE, FALSE,
4307 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4310 Xball_2, FALSE, FALSE,
4311 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4314 Xball_2B, FALSE, FALSE,
4315 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4318 Yball_eat, FALSE, FALSE,
4319 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4322 Ykey_1_eat, FALSE, FALSE,
4323 EL_EM_KEY_1, ACTION_COLLECTING, -1
4326 Ykey_2_eat, FALSE, FALSE,
4327 EL_EM_KEY_2, ACTION_COLLECTING, -1
4330 Ykey_3_eat, FALSE, FALSE,
4331 EL_EM_KEY_3, ACTION_COLLECTING, -1
4334 Ykey_4_eat, FALSE, FALSE,
4335 EL_EM_KEY_4, ACTION_COLLECTING, -1
4338 Ykey_5_eat, FALSE, FALSE,
4339 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4342 Ykey_6_eat, FALSE, FALSE,
4343 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4346 Ykey_7_eat, FALSE, FALSE,
4347 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4350 Ykey_8_eat, FALSE, FALSE,
4351 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4354 Ylenses_eat, FALSE, FALSE,
4355 EL_EMC_LENSES, ACTION_COLLECTING, -1
4358 Ymagnify_eat, FALSE, FALSE,
4359 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4362 Ygrass_eat, FALSE, FALSE,
4363 EL_EMC_GRASS, ACTION_SNAPPING, -1
4366 Ydirt_eat, FALSE, FALSE,
4367 EL_SAND, ACTION_SNAPPING, -1
4370 Xgrow_ns, TRUE, FALSE,
4371 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4374 Ygrow_ns_eat, FALSE, FALSE,
4375 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4378 Xgrow_ew, TRUE, FALSE,
4379 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4382 Ygrow_ew_eat, FALSE, FALSE,
4383 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4386 Xwonderwall, TRUE, FALSE,
4387 EL_MAGIC_WALL, -1, -1
4390 XwonderwallB, FALSE, FALSE,
4391 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4394 Xamoeba_1, TRUE, FALSE,
4395 EL_AMOEBA_DRY, ACTION_OTHER, -1
4398 Xamoeba_2, FALSE, FALSE,
4399 EL_AMOEBA_DRY, ACTION_OTHER, -1
4402 Xamoeba_3, FALSE, FALSE,
4403 EL_AMOEBA_DRY, ACTION_OTHER, -1
4406 Xamoeba_4, FALSE, FALSE,
4407 EL_AMOEBA_DRY, ACTION_OTHER, -1
4410 Xamoeba_5, TRUE, FALSE,
4411 EL_AMOEBA_WET, ACTION_OTHER, -1
4414 Xamoeba_6, FALSE, FALSE,
4415 EL_AMOEBA_WET, ACTION_OTHER, -1
4418 Xamoeba_7, FALSE, FALSE,
4419 EL_AMOEBA_WET, ACTION_OTHER, -1
4422 Xamoeba_8, FALSE, FALSE,
4423 EL_AMOEBA_WET, ACTION_OTHER, -1
4426 Xdoor_1, TRUE, FALSE,
4427 EL_EM_GATE_1, -1, -1
4430 Xdoor_2, TRUE, FALSE,
4431 EL_EM_GATE_2, -1, -1
4434 Xdoor_3, TRUE, FALSE,
4435 EL_EM_GATE_3, -1, -1
4438 Xdoor_4, TRUE, FALSE,
4439 EL_EM_GATE_4, -1, -1
4442 Xdoor_5, TRUE, FALSE,
4443 EL_EMC_GATE_5, -1, -1
4446 Xdoor_6, TRUE, FALSE,
4447 EL_EMC_GATE_6, -1, -1
4450 Xdoor_7, TRUE, FALSE,
4451 EL_EMC_GATE_7, -1, -1
4454 Xdoor_8, TRUE, FALSE,
4455 EL_EMC_GATE_8, -1, -1
4458 Xkey_1, TRUE, FALSE,
4462 Xkey_2, TRUE, FALSE,
4466 Xkey_3, TRUE, FALSE,
4470 Xkey_4, TRUE, FALSE,
4474 Xkey_5, TRUE, FALSE,
4475 EL_EMC_KEY_5, -1, -1
4478 Xkey_6, TRUE, FALSE,
4479 EL_EMC_KEY_6, -1, -1
4482 Xkey_7, TRUE, FALSE,
4483 EL_EMC_KEY_7, -1, -1
4486 Xkey_8, TRUE, FALSE,
4487 EL_EMC_KEY_8, -1, -1
4490 Xwind_n, TRUE, FALSE,
4491 EL_BALLOON_SWITCH_UP, -1, -1
4494 Xwind_e, TRUE, FALSE,
4495 EL_BALLOON_SWITCH_RIGHT, -1, -1
4498 Xwind_s, TRUE, FALSE,
4499 EL_BALLOON_SWITCH_DOWN, -1, -1
4502 Xwind_w, TRUE, FALSE,
4503 EL_BALLOON_SWITCH_LEFT, -1, -1
4506 Xwind_nesw, TRUE, FALSE,
4507 EL_BALLOON_SWITCH_ANY, -1, -1
4510 Xwind_stop, TRUE, FALSE,
4511 EL_BALLOON_SWITCH_NONE, -1, -1
4515 EL_EM_EXIT_CLOSED, -1, -1
4518 Xexit_1, TRUE, FALSE,
4519 EL_EM_EXIT_OPEN, -1, -1
4522 Xexit_2, FALSE, FALSE,
4523 EL_EM_EXIT_OPEN, -1, -1
4526 Xexit_3, FALSE, FALSE,
4527 EL_EM_EXIT_OPEN, -1, -1
4530 Xdynamite, TRUE, FALSE,
4531 EL_EM_DYNAMITE, -1, -1
4534 Ydynamite_eat, FALSE, FALSE,
4535 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4538 Xdynamite_1, TRUE, FALSE,
4539 EL_EM_DYNAMITE_ACTIVE, -1, -1
4542 Xdynamite_2, FALSE, FALSE,
4543 EL_EM_DYNAMITE_ACTIVE, -1, -1
4546 Xdynamite_3, FALSE, FALSE,
4547 EL_EM_DYNAMITE_ACTIVE, -1, -1
4550 Xdynamite_4, FALSE, FALSE,
4551 EL_EM_DYNAMITE_ACTIVE, -1, -1
4554 Xbumper, TRUE, FALSE,
4555 EL_EMC_SPRING_BUMPER, -1, -1
4558 XbumperB, FALSE, FALSE,
4559 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4562 Xwheel, TRUE, FALSE,
4563 EL_ROBOT_WHEEL, -1, -1
4566 XwheelB, FALSE, FALSE,
4567 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4570 Xswitch, TRUE, FALSE,
4571 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4574 XswitchB, FALSE, FALSE,
4575 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4579 EL_QUICKSAND_EMPTY, -1, -1
4582 Xsand_stone, TRUE, FALSE,
4583 EL_QUICKSAND_FULL, -1, -1
4586 Xsand_stonein_1, FALSE, TRUE,
4587 EL_ROCK, ACTION_FILLING, -1
4590 Xsand_stonein_2, FALSE, TRUE,
4591 EL_ROCK, ACTION_FILLING, -1
4594 Xsand_stonein_3, FALSE, TRUE,
4595 EL_ROCK, ACTION_FILLING, -1
4598 Xsand_stonein_4, FALSE, TRUE,
4599 EL_ROCK, ACTION_FILLING, -1
4602 Xsand_stonesand_1, FALSE, FALSE,
4603 EL_QUICKSAND_FULL, -1, -1
4606 Xsand_stonesand_2, FALSE, FALSE,
4607 EL_QUICKSAND_FULL, -1, -1
4610 Xsand_stonesand_3, FALSE, FALSE,
4611 EL_QUICKSAND_FULL, -1, -1
4614 Xsand_stonesand_4, FALSE, FALSE,
4615 EL_QUICKSAND_FULL, -1, -1
4618 Xsand_stoneout_1, FALSE, FALSE,
4619 EL_ROCK, ACTION_EMPTYING, -1
4622 Xsand_stoneout_2, FALSE, FALSE,
4623 EL_ROCK, ACTION_EMPTYING, -1
4626 Xsand_sandstone_1, FALSE, FALSE,
4627 EL_QUICKSAND_FULL, -1, -1
4630 Xsand_sandstone_2, FALSE, FALSE,
4631 EL_QUICKSAND_FULL, -1, -1
4634 Xsand_sandstone_3, FALSE, FALSE,
4635 EL_QUICKSAND_FULL, -1, -1
4638 Xsand_sandstone_4, FALSE, FALSE,
4639 EL_QUICKSAND_FULL, -1, -1
4642 Xplant, TRUE, FALSE,
4643 EL_EMC_PLANT, -1, -1
4646 Yplant, FALSE, FALSE,
4647 EL_EMC_PLANT, -1, -1
4650 Xlenses, TRUE, FALSE,
4651 EL_EMC_LENSES, -1, -1
4654 Xmagnify, TRUE, FALSE,
4655 EL_EMC_MAGNIFIER, -1, -1
4658 Xdripper, TRUE, FALSE,
4659 EL_EMC_DRIPPER, -1, -1
4662 XdripperB, FALSE, FALSE,
4663 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4666 Xfake_blank, TRUE, FALSE,
4667 EL_INVISIBLE_WALL, -1, -1
4670 Xfake_blankB, FALSE, FALSE,
4671 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4674 Xfake_grass, TRUE, FALSE,
4675 EL_EMC_FAKE_GRASS, -1, -1
4678 Xfake_grassB, FALSE, FALSE,
4679 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4682 Xfake_door_1, TRUE, FALSE,
4683 EL_EM_GATE_1_GRAY, -1, -1
4686 Xfake_door_2, TRUE, FALSE,
4687 EL_EM_GATE_2_GRAY, -1, -1
4690 Xfake_door_3, TRUE, FALSE,
4691 EL_EM_GATE_3_GRAY, -1, -1
4694 Xfake_door_4, TRUE, FALSE,
4695 EL_EM_GATE_4_GRAY, -1, -1
4698 Xfake_door_5, TRUE, FALSE,
4699 EL_EMC_GATE_5_GRAY, -1, -1
4702 Xfake_door_6, TRUE, FALSE,
4703 EL_EMC_GATE_6_GRAY, -1, -1
4706 Xfake_door_7, TRUE, FALSE,
4707 EL_EMC_GATE_7_GRAY, -1, -1
4710 Xfake_door_8, TRUE, FALSE,
4711 EL_EMC_GATE_8_GRAY, -1, -1
4714 Xfake_acid_1, TRUE, FALSE,
4715 EL_EMC_FAKE_ACID, -1, -1
4718 Xfake_acid_2, FALSE, FALSE,
4719 EL_EMC_FAKE_ACID, -1, -1
4722 Xfake_acid_3, FALSE, FALSE,
4723 EL_EMC_FAKE_ACID, -1, -1
4726 Xfake_acid_4, FALSE, FALSE,
4727 EL_EMC_FAKE_ACID, -1, -1
4730 Xfake_acid_5, FALSE, FALSE,
4731 EL_EMC_FAKE_ACID, -1, -1
4734 Xfake_acid_6, FALSE, FALSE,
4735 EL_EMC_FAKE_ACID, -1, -1
4738 Xfake_acid_7, FALSE, FALSE,
4739 EL_EMC_FAKE_ACID, -1, -1
4742 Xfake_acid_8, FALSE, FALSE,
4743 EL_EMC_FAKE_ACID, -1, -1
4746 Xsteel_1, TRUE, FALSE,
4747 EL_STEELWALL, -1, -1
4750 Xsteel_2, TRUE, FALSE,
4751 EL_EMC_STEELWALL_2, -1, -1
4754 Xsteel_3, TRUE, FALSE,
4755 EL_EMC_STEELWALL_3, -1, -1
4758 Xsteel_4, TRUE, FALSE,
4759 EL_EMC_STEELWALL_4, -1, -1
4762 Xwall_1, TRUE, FALSE,
4766 Xwall_2, TRUE, FALSE,
4767 EL_EMC_WALL_14, -1, -1
4770 Xwall_3, TRUE, FALSE,
4771 EL_EMC_WALL_15, -1, -1
4774 Xwall_4, TRUE, FALSE,
4775 EL_EMC_WALL_16, -1, -1
4778 Xround_wall_1, TRUE, FALSE,
4779 EL_WALL_SLIPPERY, -1, -1
4782 Xround_wall_2, TRUE, FALSE,
4783 EL_EMC_WALL_SLIPPERY_2, -1, -1
4786 Xround_wall_3, TRUE, FALSE,
4787 EL_EMC_WALL_SLIPPERY_3, -1, -1
4790 Xround_wall_4, TRUE, FALSE,
4791 EL_EMC_WALL_SLIPPERY_4, -1, -1
4794 Xdecor_1, TRUE, FALSE,
4795 EL_EMC_WALL_8, -1, -1
4798 Xdecor_2, TRUE, FALSE,
4799 EL_EMC_WALL_6, -1, -1
4802 Xdecor_3, TRUE, FALSE,
4803 EL_EMC_WALL_4, -1, -1
4806 Xdecor_4, TRUE, FALSE,
4807 EL_EMC_WALL_7, -1, -1
4810 Xdecor_5, TRUE, FALSE,
4811 EL_EMC_WALL_5, -1, -1
4814 Xdecor_6, TRUE, FALSE,
4815 EL_EMC_WALL_9, -1, -1
4818 Xdecor_7, TRUE, FALSE,
4819 EL_EMC_WALL_10, -1, -1
4822 Xdecor_8, TRUE, FALSE,
4823 EL_EMC_WALL_1, -1, -1
4826 Xdecor_9, TRUE, FALSE,
4827 EL_EMC_WALL_2, -1, -1
4830 Xdecor_10, TRUE, FALSE,
4831 EL_EMC_WALL_3, -1, -1
4834 Xdecor_11, TRUE, FALSE,
4835 EL_EMC_WALL_11, -1, -1
4838 Xdecor_12, TRUE, FALSE,
4839 EL_EMC_WALL_12, -1, -1
4842 Xalpha_0, TRUE, FALSE,
4843 EL_CHAR('0'), -1, -1
4846 Xalpha_1, TRUE, FALSE,
4847 EL_CHAR('1'), -1, -1
4850 Xalpha_2, TRUE, FALSE,
4851 EL_CHAR('2'), -1, -1
4854 Xalpha_3, TRUE, FALSE,
4855 EL_CHAR('3'), -1, -1
4858 Xalpha_4, TRUE, FALSE,
4859 EL_CHAR('4'), -1, -1
4862 Xalpha_5, TRUE, FALSE,
4863 EL_CHAR('5'), -1, -1
4866 Xalpha_6, TRUE, FALSE,
4867 EL_CHAR('6'), -1, -1
4870 Xalpha_7, TRUE, FALSE,
4871 EL_CHAR('7'), -1, -1
4874 Xalpha_8, TRUE, FALSE,
4875 EL_CHAR('8'), -1, -1
4878 Xalpha_9, TRUE, FALSE,
4879 EL_CHAR('9'), -1, -1
4882 Xalpha_excla, TRUE, FALSE,
4883 EL_CHAR('!'), -1, -1
4886 Xalpha_quote, TRUE, FALSE,
4887 EL_CHAR('"'), -1, -1
4890 Xalpha_comma, TRUE, FALSE,
4891 EL_CHAR(','), -1, -1
4894 Xalpha_minus, TRUE, FALSE,
4895 EL_CHAR('-'), -1, -1
4898 Xalpha_perio, TRUE, FALSE,
4899 EL_CHAR('.'), -1, -1
4902 Xalpha_colon, TRUE, FALSE,
4903 EL_CHAR(':'), -1, -1
4906 Xalpha_quest, TRUE, FALSE,
4907 EL_CHAR('?'), -1, -1
4910 Xalpha_a, TRUE, FALSE,
4911 EL_CHAR('A'), -1, -1
4914 Xalpha_b, TRUE, FALSE,
4915 EL_CHAR('B'), -1, -1
4918 Xalpha_c, TRUE, FALSE,
4919 EL_CHAR('C'), -1, -1
4922 Xalpha_d, TRUE, FALSE,
4923 EL_CHAR('D'), -1, -1
4926 Xalpha_e, TRUE, FALSE,
4927 EL_CHAR('E'), -1, -1
4930 Xalpha_f, TRUE, FALSE,
4931 EL_CHAR('F'), -1, -1
4934 Xalpha_g, TRUE, FALSE,
4935 EL_CHAR('G'), -1, -1
4938 Xalpha_h, TRUE, FALSE,
4939 EL_CHAR('H'), -1, -1
4942 Xalpha_i, TRUE, FALSE,
4943 EL_CHAR('I'), -1, -1
4946 Xalpha_j, TRUE, FALSE,
4947 EL_CHAR('J'), -1, -1
4950 Xalpha_k, TRUE, FALSE,
4951 EL_CHAR('K'), -1, -1
4954 Xalpha_l, TRUE, FALSE,
4955 EL_CHAR('L'), -1, -1
4958 Xalpha_m, TRUE, FALSE,
4959 EL_CHAR('M'), -1, -1
4962 Xalpha_n, TRUE, FALSE,
4963 EL_CHAR('N'), -1, -1
4966 Xalpha_o, TRUE, FALSE,
4967 EL_CHAR('O'), -1, -1
4970 Xalpha_p, TRUE, FALSE,
4971 EL_CHAR('P'), -1, -1
4974 Xalpha_q, TRUE, FALSE,
4975 EL_CHAR('Q'), -1, -1
4978 Xalpha_r, TRUE, FALSE,
4979 EL_CHAR('R'), -1, -1
4982 Xalpha_s, TRUE, FALSE,
4983 EL_CHAR('S'), -1, -1
4986 Xalpha_t, TRUE, FALSE,
4987 EL_CHAR('T'), -1, -1
4990 Xalpha_u, TRUE, FALSE,
4991 EL_CHAR('U'), -1, -1
4994 Xalpha_v, TRUE, FALSE,
4995 EL_CHAR('V'), -1, -1
4998 Xalpha_w, TRUE, FALSE,
4999 EL_CHAR('W'), -1, -1
5002 Xalpha_x, TRUE, FALSE,
5003 EL_CHAR('X'), -1, -1
5006 Xalpha_y, TRUE, FALSE,
5007 EL_CHAR('Y'), -1, -1
5010 Xalpha_z, TRUE, FALSE,
5011 EL_CHAR('Z'), -1, -1
5014 Xalpha_arrow_e, TRUE, FALSE,
5015 EL_CHAR('>'), -1, -1
5018 Xalpha_arrow_w, TRUE, FALSE,
5019 EL_CHAR('<'), -1, -1
5022 Xalpha_copyr, TRUE, FALSE,
5023 EL_CHAR('©'), -1, -1
5027 Xboom_bug, FALSE, FALSE,
5028 EL_BUG, ACTION_EXPLODING, -1
5031 Xboom_bomb, FALSE, FALSE,
5032 EL_BOMB, ACTION_EXPLODING, -1
5035 Xboom_android, FALSE, FALSE,
5036 EL_EMC_ANDROID, ACTION_OTHER, -1
5039 Xboom_1, FALSE, FALSE,
5040 EL_DEFAULT, ACTION_EXPLODING, -1
5043 Xboom_2, FALSE, FALSE,
5044 EL_DEFAULT, ACTION_EXPLODING, -1
5047 Znormal, FALSE, FALSE,
5051 Zdynamite, FALSE, FALSE,
5055 Zplayer, FALSE, FALSE,
5059 ZBORDER, FALSE, FALSE,
5069 static struct Mapping_EM_to_RND_player
5078 em_player_mapping_list[] =
5082 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5086 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5090 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5094 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5098 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5102 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5106 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5110 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5114 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5118 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5122 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5126 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5130 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5134 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5138 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5142 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5146 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5150 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5154 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5158 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5162 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5166 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5170 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5174 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5178 EL_PLAYER_1, ACTION_DEFAULT, -1,
5182 EL_PLAYER_2, ACTION_DEFAULT, -1,
5186 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5190 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5194 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5198 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5202 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5206 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5210 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5214 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5218 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5222 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5226 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5230 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5234 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5238 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5242 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5246 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5250 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5254 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5258 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5262 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5266 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5270 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5274 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5278 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5282 EL_PLAYER_3, ACTION_DEFAULT, -1,
5286 EL_PLAYER_4, ACTION_DEFAULT, -1,
5295 int map_element_RND_to_EM(int element_rnd)
5297 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5298 static boolean mapping_initialized = FALSE;
5300 if (!mapping_initialized)
5304 /* return "Xalpha_quest" for all undefined elements in mapping array */
5305 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5306 mapping_RND_to_EM[i] = Xalpha_quest;
5308 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5309 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5310 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5311 em_object_mapping_list[i].element_em;
5313 mapping_initialized = TRUE;
5316 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5317 return mapping_RND_to_EM[element_rnd];
5319 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5324 int map_element_EM_to_RND(int element_em)
5326 static unsigned short mapping_EM_to_RND[TILE_MAX];
5327 static boolean mapping_initialized = FALSE;
5329 if (!mapping_initialized)
5333 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5334 for (i = 0; i < TILE_MAX; i++)
5335 mapping_EM_to_RND[i] = EL_UNKNOWN;
5337 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5338 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5339 em_object_mapping_list[i].element_rnd;
5341 mapping_initialized = TRUE;
5344 if (element_em >= 0 && element_em < TILE_MAX)
5345 return mapping_EM_to_RND[element_em];
5347 Error(ERR_WARN, "invalid EM level element %d", element_em);
5352 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5354 struct LevelInfo_EM *level_em = level->native_em_level;
5355 struct LEVEL *lev = level_em->lev;
5358 for (i = 0; i < TILE_MAX; i++)
5359 lev->android_array[i] = Xblank;
5361 for (i = 0; i < level->num_android_clone_elements; i++)
5363 int element_rnd = level->android_clone_element[i];
5364 int element_em = map_element_RND_to_EM(element_rnd);
5366 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5367 if (em_object_mapping_list[j].element_rnd == element_rnd)
5368 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5372 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5374 struct LevelInfo_EM *level_em = level->native_em_level;
5375 struct LEVEL *lev = level_em->lev;
5378 level->num_android_clone_elements = 0;
5380 for (i = 0; i < TILE_MAX; i++)
5382 int element_em = lev->android_array[i];
5384 boolean element_found = FALSE;
5386 if (element_em == Xblank)
5389 element_rnd = map_element_EM_to_RND(element_em);
5391 for (j = 0; j < level->num_android_clone_elements; j++)
5392 if (level->android_clone_element[j] == element_rnd)
5393 element_found = TRUE;
5397 level->android_clone_element[level->num_android_clone_elements++] =
5400 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5405 if (level->num_android_clone_elements == 0)
5407 level->num_android_clone_elements = 1;
5408 level->android_clone_element[0] = EL_EMPTY;
5412 int map_direction_RND_to_EM(int direction)
5414 return (direction == MV_UP ? 0 :
5415 direction == MV_RIGHT ? 1 :
5416 direction == MV_DOWN ? 2 :
5417 direction == MV_LEFT ? 3 :
5421 int map_direction_EM_to_RND(int direction)
5423 return (direction == 0 ? MV_UP :
5424 direction == 1 ? MV_RIGHT :
5425 direction == 2 ? MV_DOWN :
5426 direction == 3 ? MV_LEFT :
5430 int get_next_element(int element)
5434 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5435 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5436 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5437 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5438 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5439 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5440 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5441 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5442 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5443 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5444 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5446 default: return element;
5451 int el_act_dir2img(int element, int action, int direction)
5453 element = GFX_ELEMENT(element);
5455 if (direction == MV_NONE)
5456 return element_info[element].graphic[action];
5458 direction = MV_DIR_TO_BIT(direction);
5460 return element_info[element].direction_graphic[action][direction];
5463 int el_act_dir2img(int element, int action, int direction)
5465 element = GFX_ELEMENT(element);
5466 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5468 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5469 return element_info[element].direction_graphic[action][direction];
5474 static int el_act_dir2crm(int element, int action, int direction)
5476 element = GFX_ELEMENT(element);
5478 if (direction == MV_NONE)
5479 return element_info[element].crumbled[action];
5481 direction = MV_DIR_TO_BIT(direction);
5483 return element_info[element].direction_crumbled[action][direction];
5486 static int el_act_dir2crm(int element, int action, int direction)
5488 element = GFX_ELEMENT(element);
5489 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5491 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5492 return element_info[element].direction_crumbled[action][direction];
5496 int el_act2img(int element, int action)
5498 element = GFX_ELEMENT(element);
5500 return element_info[element].graphic[action];
5503 int el_act2crm(int element, int action)
5505 element = GFX_ELEMENT(element);
5507 return element_info[element].crumbled[action];
5510 int el_dir2img(int element, int direction)
5512 element = GFX_ELEMENT(element);
5514 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5517 int el2baseimg(int element)
5519 return element_info[element].graphic[ACTION_DEFAULT];
5522 int el2img(int element)
5524 element = GFX_ELEMENT(element);
5526 return element_info[element].graphic[ACTION_DEFAULT];
5529 int el2edimg(int element)
5531 element = GFX_ELEMENT(element);
5533 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5536 int el2preimg(int element)
5538 element = GFX_ELEMENT(element);
5540 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5543 int font2baseimg(int font_nr)
5545 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5548 int getNumActivePlayers_EM()
5550 int num_players = 0;
5556 for (i = 0; i < MAX_PLAYERS; i++)
5557 if (tape.player_participates[i])
5563 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5565 int game_frame_delay_value;
5567 game_frame_delay_value =
5568 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5569 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5572 if (tape.playing && tape.warp_forward && !tape.pausing)
5573 game_frame_delay_value = 0;
5575 return game_frame_delay_value;
5578 unsigned int InitRND(long seed)
5580 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5581 return InitEngineRandom_EM(seed);
5583 return InitEngineRandom_RND(seed);
5586 void InitGraphicInfo_EM(void)
5588 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5589 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5593 int num_em_gfx_errors = 0;
5595 if (graphic_info_em_object[0][0].bitmap == NULL)
5597 /* EM graphics not yet initialized in em_open_all() */
5602 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5605 /* always start with reliable default values */
5606 for (i = 0; i < TILE_MAX; i++)
5608 object_mapping[i].element_rnd = EL_UNKNOWN;
5609 object_mapping[i].is_backside = FALSE;
5610 object_mapping[i].action = ACTION_DEFAULT;
5611 object_mapping[i].direction = MV_NONE;
5614 /* always start with reliable default values */
5615 for (p = 0; p < MAX_PLAYERS; p++)
5617 for (i = 0; i < SPR_MAX; i++)
5619 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5620 player_mapping[p][i].action = ACTION_DEFAULT;
5621 player_mapping[p][i].direction = MV_NONE;
5625 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5627 int e = em_object_mapping_list[i].element_em;
5629 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5630 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5632 if (em_object_mapping_list[i].action != -1)
5633 object_mapping[e].action = em_object_mapping_list[i].action;
5635 if (em_object_mapping_list[i].direction != -1)
5636 object_mapping[e].direction =
5637 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5640 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5642 int a = em_player_mapping_list[i].action_em;
5643 int p = em_player_mapping_list[i].player_nr;
5645 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5647 if (em_player_mapping_list[i].action != -1)
5648 player_mapping[p][a].action = em_player_mapping_list[i].action;
5650 if (em_player_mapping_list[i].direction != -1)
5651 player_mapping[p][a].direction =
5652 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5655 for (i = 0; i < TILE_MAX; i++)
5657 int element = object_mapping[i].element_rnd;
5658 int action = object_mapping[i].action;
5659 int direction = object_mapping[i].direction;
5660 boolean is_backside = object_mapping[i].is_backside;
5661 boolean action_removing = (action == ACTION_DIGGING ||
5662 action == ACTION_SNAPPING ||
5663 action == ACTION_COLLECTING);
5664 boolean action_exploding = ((action == ACTION_EXPLODING ||
5665 action == ACTION_SMASHED_BY_ROCK ||
5666 action == ACTION_SMASHED_BY_SPRING) &&
5667 element != EL_DIAMOND);
5668 boolean action_active = (action == ACTION_ACTIVE);
5669 boolean action_other = (action == ACTION_OTHER);
5671 for (j = 0; j < 8; j++)
5673 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5674 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5676 i == Xdrip_stretch ? element :
5677 i == Xdrip_stretchB ? element :
5678 i == Ydrip_s1 ? element :
5679 i == Ydrip_s1B ? element :
5680 i == Xball_1B ? element :
5681 i == Xball_2 ? element :
5682 i == Xball_2B ? element :
5683 i == Yball_eat ? element :
5684 i == Ykey_1_eat ? element :
5685 i == Ykey_2_eat ? element :
5686 i == Ykey_3_eat ? element :
5687 i == Ykey_4_eat ? element :
5688 i == Ykey_5_eat ? element :
5689 i == Ykey_6_eat ? element :
5690 i == Ykey_7_eat ? element :
5691 i == Ykey_8_eat ? element :
5692 i == Ylenses_eat ? element :
5693 i == Ymagnify_eat ? element :
5694 i == Ygrass_eat ? element :
5695 i == Ydirt_eat ? element :
5696 i == Yemerald_stone ? EL_EMERALD :
5697 i == Ydiamond_stone ? EL_ROCK :
5698 i == Xsand_stonein_1 ? element :
5699 i == Xsand_stonein_2 ? element :
5700 i == Xsand_stonein_3 ? element :
5701 i == Xsand_stonein_4 ? element :
5702 is_backside ? EL_EMPTY :
5703 action_removing ? EL_EMPTY :
5705 int effective_action = (j < 7 ? action :
5706 i == Xdrip_stretch ? action :
5707 i == Xdrip_stretchB ? action :
5708 i == Ydrip_s1 ? action :
5709 i == Ydrip_s1B ? action :
5710 i == Xball_1B ? action :
5711 i == Xball_2 ? action :
5712 i == Xball_2B ? action :
5713 i == Yball_eat ? action :
5714 i == Ykey_1_eat ? action :
5715 i == Ykey_2_eat ? action :
5716 i == Ykey_3_eat ? action :
5717 i == Ykey_4_eat ? action :
5718 i == Ykey_5_eat ? action :
5719 i == Ykey_6_eat ? action :
5720 i == Ykey_7_eat ? action :
5721 i == Ykey_8_eat ? action :
5722 i == Ylenses_eat ? action :
5723 i == Ymagnify_eat ? action :
5724 i == Ygrass_eat ? action :
5725 i == Ydirt_eat ? action :
5726 i == Xsand_stonein_1 ? action :
5727 i == Xsand_stonein_2 ? action :
5728 i == Xsand_stonein_3 ? action :
5729 i == Xsand_stonein_4 ? action :
5730 i == Xsand_stoneout_1 ? action :
5731 i == Xsand_stoneout_2 ? action :
5732 i == Xboom_android ? ACTION_EXPLODING :
5733 action_exploding ? ACTION_EXPLODING :
5734 action_active ? action :
5735 action_other ? action :
5737 int graphic = (el_act_dir2img(effective_element, effective_action,
5739 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5741 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5742 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5743 boolean has_action_graphics = (graphic != base_graphic);
5744 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5745 struct GraphicInfo *g = &graphic_info[graphic];
5746 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5749 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5750 boolean special_animation = (action != ACTION_DEFAULT &&
5751 g->anim_frames == 3 &&
5752 g->anim_delay == 2 &&
5753 g->anim_mode & ANIM_LINEAR);
5754 int sync_frame = (i == Xdrip_stretch ? 7 :
5755 i == Xdrip_stretchB ? 7 :
5756 i == Ydrip_s2 ? j + 8 :
5757 i == Ydrip_s2B ? j + 8 :
5766 i == Xfake_acid_1 ? 0 :
5767 i == Xfake_acid_2 ? 10 :
5768 i == Xfake_acid_3 ? 20 :
5769 i == Xfake_acid_4 ? 30 :
5770 i == Xfake_acid_5 ? 40 :
5771 i == Xfake_acid_6 ? 50 :
5772 i == Xfake_acid_7 ? 60 :
5773 i == Xfake_acid_8 ? 70 :
5775 i == Xball_2B ? j + 8 :
5776 i == Yball_eat ? j + 1 :
5777 i == Ykey_1_eat ? j + 1 :
5778 i == Ykey_2_eat ? j + 1 :
5779 i == Ykey_3_eat ? j + 1 :
5780 i == Ykey_4_eat ? j + 1 :
5781 i == Ykey_5_eat ? j + 1 :
5782 i == Ykey_6_eat ? j + 1 :
5783 i == Ykey_7_eat ? j + 1 :
5784 i == Ykey_8_eat ? j + 1 :
5785 i == Ylenses_eat ? j + 1 :
5786 i == Ymagnify_eat ? j + 1 :
5787 i == Ygrass_eat ? j + 1 :
5788 i == Ydirt_eat ? j + 1 :
5789 i == Xamoeba_1 ? 0 :
5790 i == Xamoeba_2 ? 1 :
5791 i == Xamoeba_3 ? 2 :
5792 i == Xamoeba_4 ? 3 :
5793 i == Xamoeba_5 ? 0 :
5794 i == Xamoeba_6 ? 1 :
5795 i == Xamoeba_7 ? 2 :
5796 i == Xamoeba_8 ? 3 :
5797 i == Xexit_2 ? j + 8 :
5798 i == Xexit_3 ? j + 16 :
5799 i == Xdynamite_1 ? 0 :
5800 i == Xdynamite_2 ? 8 :
5801 i == Xdynamite_3 ? 16 :
5802 i == Xdynamite_4 ? 24 :
5803 i == Xsand_stonein_1 ? j + 1 :
5804 i == Xsand_stonein_2 ? j + 9 :
5805 i == Xsand_stonein_3 ? j + 17 :
5806 i == Xsand_stonein_4 ? j + 25 :
5807 i == Xsand_stoneout_1 && j == 0 ? 0 :
5808 i == Xsand_stoneout_1 && j == 1 ? 0 :
5809 i == Xsand_stoneout_1 && j == 2 ? 1 :
5810 i == Xsand_stoneout_1 && j == 3 ? 2 :
5811 i == Xsand_stoneout_1 && j == 4 ? 2 :
5812 i == Xsand_stoneout_1 && j == 5 ? 3 :
5813 i == Xsand_stoneout_1 && j == 6 ? 4 :
5814 i == Xsand_stoneout_1 && j == 7 ? 4 :
5815 i == Xsand_stoneout_2 && j == 0 ? 5 :
5816 i == Xsand_stoneout_2 && j == 1 ? 6 :
5817 i == Xsand_stoneout_2 && j == 2 ? 7 :
5818 i == Xsand_stoneout_2 && j == 3 ? 8 :
5819 i == Xsand_stoneout_2 && j == 4 ? 9 :
5820 i == Xsand_stoneout_2 && j == 5 ? 11 :
5821 i == Xsand_stoneout_2 && j == 6 ? 13 :
5822 i == Xsand_stoneout_2 && j == 7 ? 15 :
5823 i == Xboom_bug && j == 1 ? 2 :
5824 i == Xboom_bug && j == 2 ? 2 :
5825 i == Xboom_bug && j == 3 ? 4 :
5826 i == Xboom_bug && j == 4 ? 4 :
5827 i == Xboom_bug && j == 5 ? 2 :
5828 i == Xboom_bug && j == 6 ? 2 :
5829 i == Xboom_bug && j == 7 ? 0 :
5830 i == Xboom_bomb && j == 1 ? 2 :
5831 i == Xboom_bomb && j == 2 ? 2 :
5832 i == Xboom_bomb && j == 3 ? 4 :
5833 i == Xboom_bomb && j == 4 ? 4 :
5834 i == Xboom_bomb && j == 5 ? 2 :
5835 i == Xboom_bomb && j == 6 ? 2 :
5836 i == Xboom_bomb && j == 7 ? 0 :
5837 i == Xboom_android && j == 7 ? 6 :
5838 i == Xboom_1 && j == 1 ? 2 :
5839 i == Xboom_1 && j == 2 ? 2 :
5840 i == Xboom_1 && j == 3 ? 4 :
5841 i == Xboom_1 && j == 4 ? 4 :
5842 i == Xboom_1 && j == 5 ? 6 :
5843 i == Xboom_1 && j == 6 ? 6 :
5844 i == Xboom_1 && j == 7 ? 8 :
5845 i == Xboom_2 && j == 0 ? 8 :
5846 i == Xboom_2 && j == 1 ? 8 :
5847 i == Xboom_2 && j == 2 ? 10 :
5848 i == Xboom_2 && j == 3 ? 10 :
5849 i == Xboom_2 && j == 4 ? 10 :
5850 i == Xboom_2 && j == 5 ? 12 :
5851 i == Xboom_2 && j == 6 ? 12 :
5852 i == Xboom_2 && j == 7 ? 12 :
5853 special_animation && j == 4 ? 3 :
5854 effective_action != action ? 0 :
5858 Bitmap *debug_bitmap = g_em->bitmap;
5859 int debug_src_x = g_em->src_x;
5860 int debug_src_y = g_em->src_y;
5863 int frame = getAnimationFrame(g->anim_frames,
5866 g->anim_start_frame,
5869 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5870 g->double_movement && is_backside);
5872 g_em->bitmap = src_bitmap;
5873 g_em->src_x = src_x;
5874 g_em->src_y = src_y;
5875 g_em->src_offset_x = 0;
5876 g_em->src_offset_y = 0;
5877 g_em->dst_offset_x = 0;
5878 g_em->dst_offset_y = 0;
5879 g_em->width = TILEX;
5880 g_em->height = TILEY;
5882 g_em->crumbled_bitmap = NULL;
5883 g_em->crumbled_src_x = 0;
5884 g_em->crumbled_src_y = 0;
5885 g_em->crumbled_border_size = 0;
5887 g_em->has_crumbled_graphics = FALSE;
5888 g_em->preserve_background = FALSE;
5891 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5892 printf("::: empty crumbled: %d [%s], %d, %d\n",
5893 effective_element, element_info[effective_element].token_name,
5894 effective_action, direction);
5897 /* if element can be crumbled, but certain action graphics are just empty
5898 space (like snapping sand with the original R'n'D graphics), do not
5899 treat these empty space graphics as crumbled graphics in EMC engine */
5900 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5902 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5904 g_em->has_crumbled_graphics = TRUE;
5905 g_em->crumbled_bitmap = src_bitmap;
5906 g_em->crumbled_src_x = src_x;
5907 g_em->crumbled_src_y = src_y;
5908 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5912 if (element == EL_ROCK &&
5913 effective_action == ACTION_FILLING)
5914 printf("::: has_action_graphics == %d\n", has_action_graphics);
5917 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5918 effective_action == ACTION_MOVING ||
5919 effective_action == ACTION_PUSHING ||
5920 effective_action == ACTION_EATING)) ||
5921 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5922 effective_action == ACTION_EMPTYING)))
5925 (effective_action == ACTION_FALLING ||
5926 effective_action == ACTION_FILLING ||
5927 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5928 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5929 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5930 int num_steps = (i == Ydrip_s1 ? 16 :
5931 i == Ydrip_s1B ? 16 :
5932 i == Ydrip_s2 ? 16 :
5933 i == Ydrip_s2B ? 16 :
5934 i == Xsand_stonein_1 ? 32 :
5935 i == Xsand_stonein_2 ? 32 :
5936 i == Xsand_stonein_3 ? 32 :
5937 i == Xsand_stonein_4 ? 32 :
5938 i == Xsand_stoneout_1 ? 16 :
5939 i == Xsand_stoneout_2 ? 16 : 8);
5940 int cx = ABS(dx) * (TILEX / num_steps);
5941 int cy = ABS(dy) * (TILEY / num_steps);
5942 int step_frame = (i == Ydrip_s2 ? j + 8 :
5943 i == Ydrip_s2B ? j + 8 :
5944 i == Xsand_stonein_2 ? j + 8 :
5945 i == Xsand_stonein_3 ? j + 16 :
5946 i == Xsand_stonein_4 ? j + 24 :
5947 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5948 int step = (is_backside ? step_frame : num_steps - step_frame);
5950 if (is_backside) /* tile where movement starts */
5952 if (dx < 0 || dy < 0)
5954 g_em->src_offset_x = cx * step;
5955 g_em->src_offset_y = cy * step;
5959 g_em->dst_offset_x = cx * step;
5960 g_em->dst_offset_y = cy * step;
5963 else /* tile where movement ends */
5965 if (dx < 0 || dy < 0)
5967 g_em->dst_offset_x = cx * step;
5968 g_em->dst_offset_y = cy * step;
5972 g_em->src_offset_x = cx * step;
5973 g_em->src_offset_y = cy * step;
5977 g_em->width = TILEX - cx * step;
5978 g_em->height = TILEY - cy * step;
5981 /* create unique graphic identifier to decide if tile must be redrawn */
5982 /* bit 31 - 16 (16 bit): EM style graphic
5983 bit 15 - 12 ( 4 bit): EM style frame
5984 bit 11 - 6 ( 6 bit): graphic width
5985 bit 5 - 0 ( 6 bit): graphic height */
5986 g_em->unique_identifier =
5987 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5991 /* skip check for EMC elements not contained in original EMC artwork */
5992 if (element == EL_EMC_FAKE_ACID)
5995 if (g_em->bitmap != debug_bitmap ||
5996 g_em->src_x != debug_src_x ||
5997 g_em->src_y != debug_src_y ||
5998 g_em->src_offset_x != 0 ||
5999 g_em->src_offset_y != 0 ||
6000 g_em->dst_offset_x != 0 ||
6001 g_em->dst_offset_y != 0 ||
6002 g_em->width != TILEX ||
6003 g_em->height != TILEY)
6005 static int last_i = -1;
6013 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6014 i, element, element_info[element].token_name,
6015 element_action_info[effective_action].suffix, direction);
6017 if (element != effective_element)
6018 printf(" [%d ('%s')]",
6020 element_info[effective_element].token_name);
6024 if (g_em->bitmap != debug_bitmap)
6025 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6026 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6028 if (g_em->src_x != debug_src_x ||
6029 g_em->src_y != debug_src_y)
6030 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6031 j, (is_backside ? 'B' : 'F'),
6032 g_em->src_x, g_em->src_y,
6033 g_em->src_x / 32, g_em->src_y / 32,
6034 debug_src_x, debug_src_y,
6035 debug_src_x / 32, debug_src_y / 32);
6037 if (g_em->src_offset_x != 0 ||
6038 g_em->src_offset_y != 0 ||
6039 g_em->dst_offset_x != 0 ||
6040 g_em->dst_offset_y != 0)
6041 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6043 g_em->src_offset_x, g_em->src_offset_y,
6044 g_em->dst_offset_x, g_em->dst_offset_y);
6046 if (g_em->width != TILEX ||
6047 g_em->height != TILEY)
6048 printf(" %d (%d): size %d,%d should be %d,%d\n",
6050 g_em->width, g_em->height, TILEX, TILEY);
6052 num_em_gfx_errors++;
6059 for (i = 0; i < TILE_MAX; i++)
6061 for (j = 0; j < 8; j++)
6063 int element = object_mapping[i].element_rnd;
6064 int action = object_mapping[i].action;
6065 int direction = object_mapping[i].direction;
6066 boolean is_backside = object_mapping[i].is_backside;
6067 int graphic_action = el_act_dir2img(element, action, direction);
6068 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6070 if ((action == ACTION_SMASHED_BY_ROCK ||
6071 action == ACTION_SMASHED_BY_SPRING ||
6072 action == ACTION_EATING) &&
6073 graphic_action == graphic_default)
6075 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6076 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6077 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6078 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6081 /* no separate animation for "smashed by rock" -- use rock instead */
6082 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6083 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6085 g_em->bitmap = g_xx->bitmap;
6086 g_em->src_x = g_xx->src_x;
6087 g_em->src_y = g_xx->src_y;
6088 g_em->src_offset_x = g_xx->src_offset_x;
6089 g_em->src_offset_y = g_xx->src_offset_y;
6090 g_em->dst_offset_x = g_xx->dst_offset_x;
6091 g_em->dst_offset_y = g_xx->dst_offset_y;
6092 g_em->width = g_xx->width;
6093 g_em->height = g_xx->height;
6094 g_em->unique_identifier = g_xx->unique_identifier;
6097 g_em->preserve_background = TRUE;
6102 for (p = 0; p < MAX_PLAYERS; p++)
6104 for (i = 0; i < SPR_MAX; i++)
6106 int element = player_mapping[p][i].element_rnd;
6107 int action = player_mapping[p][i].action;
6108 int direction = player_mapping[p][i].direction;
6110 for (j = 0; j < 8; j++)
6112 int effective_element = element;
6113 int effective_action = action;
6114 int graphic = (direction == MV_NONE ?
6115 el_act2img(effective_element, effective_action) :
6116 el_act_dir2img(effective_element, effective_action,
6118 struct GraphicInfo *g = &graphic_info[graphic];
6119 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6125 Bitmap *debug_bitmap = g_em->bitmap;
6126 int debug_src_x = g_em->src_x;
6127 int debug_src_y = g_em->src_y;
6130 int frame = getAnimationFrame(g->anim_frames,
6133 g->anim_start_frame,
6136 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6138 g_em->bitmap = src_bitmap;
6139 g_em->src_x = src_x;
6140 g_em->src_y = src_y;
6141 g_em->src_offset_x = 0;
6142 g_em->src_offset_y = 0;
6143 g_em->dst_offset_x = 0;
6144 g_em->dst_offset_y = 0;
6145 g_em->width = TILEX;
6146 g_em->height = TILEY;
6150 /* skip check for EMC elements not contained in original EMC artwork */
6151 if (element == EL_PLAYER_3 ||
6152 element == EL_PLAYER_4)
6155 if (g_em->bitmap != debug_bitmap ||
6156 g_em->src_x != debug_src_x ||
6157 g_em->src_y != debug_src_y)
6159 static int last_i = -1;
6167 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6168 p, i, element, element_info[element].token_name,
6169 element_action_info[effective_action].suffix, direction);
6171 if (element != effective_element)
6172 printf(" [%d ('%s')]",
6174 element_info[effective_element].token_name);
6178 if (g_em->bitmap != debug_bitmap)
6179 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6180 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6182 if (g_em->src_x != debug_src_x ||
6183 g_em->src_y != debug_src_y)
6184 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6186 g_em->src_x, g_em->src_y,
6187 g_em->src_x / 32, g_em->src_y / 32,
6188 debug_src_x, debug_src_y,
6189 debug_src_x / 32, debug_src_y / 32);
6191 num_em_gfx_errors++;
6201 printf("::: [%d errors found]\n", num_em_gfx_errors);
6207 void PlayMenuSound()
6209 int sound = menu.sound[game_status];
6211 if (sound == SND_UNDEFINED)
6214 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6215 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6218 if (IS_LOOP_SOUND(sound))
6219 PlaySoundLoop(sound);
6224 void PlayMenuSoundStereo(int sound, int stereo_position)
6226 if (sound == SND_UNDEFINED)
6229 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6230 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6233 if (IS_LOOP_SOUND(sound))
6234 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6236 PlaySoundStereo(sound, stereo_position);
6239 void PlayMenuSoundIfLoop()
6241 int sound = menu.sound[game_status];
6243 if (sound == SND_UNDEFINED)
6246 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6247 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6250 if (IS_LOOP_SOUND(sound))
6251 PlaySoundLoop(sound);
6254 void PlayMenuMusic()
6256 int music = menu.music[game_status];
6258 if (music == MUS_UNDEFINED)
6261 if (!setup.sound_music)
6267 void PlaySoundActivating()
6270 PlaySound(SND_MENU_ITEM_ACTIVATING);
6274 void PlaySoundSelecting()
6277 PlaySound(SND_MENU_ITEM_SELECTING);
6281 void ToggleFullscreenIfNeeded()
6283 boolean change_fullscreen = (setup.fullscreen !=
6284 video.fullscreen_enabled);
6285 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6286 !strEqual(setup.fullscreen_mode,
6287 video.fullscreen_mode_current));
6289 if (!video.fullscreen_available)
6293 if (change_fullscreen || change_fullscreen_mode)
6295 if (setup.fullscreen != video.fullscreen_enabled ||
6296 setup.fullscreen_mode != video.fullscreen_mode_current)
6299 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6301 /* save backbuffer content which gets lost when toggling fullscreen mode */
6302 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6305 if (change_fullscreen_mode)
6307 if (setup.fullscreen && video.fullscreen_enabled)
6310 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6312 /* (this is now set in sdl.c) */
6314 video.fullscreen_mode_current = setup.fullscreen_mode;
6316 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6319 /* toggle fullscreen */
6320 ChangeVideoModeIfNeeded(setup.fullscreen);
6322 setup.fullscreen = video.fullscreen_enabled;
6324 /* restore backbuffer content from temporary backbuffer backup bitmap */
6325 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6327 FreeBitmap(tmp_backbuffer);
6330 /* update visible window/screen */
6331 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6333 redraw_mask = REDRAW_ALL;