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)
248 if (redraw_mask & REDRAW_ALL)
249 DrawMaskedBorder_ALL();
252 if (redraw_mask & REDRAW_FIELD)
253 DrawMaskedBorder_FIELD();
254 if (redraw_mask & REDRAW_DOOR_1)
255 DrawMaskedBorder_DOOR_1();
256 if (redraw_mask & REDRAW_DOOR_2)
257 DrawMaskedBorder_DOOR_2();
258 if (redraw_mask & REDRAW_DOOR_3)
259 DrawMaskedBorder_DOOR_3();
266 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
268 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
269 redraw_mask &= ~REDRAW_MAIN;
271 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
272 redraw_mask |= REDRAW_FIELD;
274 if (redraw_mask & REDRAW_FIELD)
275 redraw_mask &= ~REDRAW_TILES;
277 if (redraw_mask == REDRAW_NONE)
280 if (redraw_mask & REDRAW_TILES &&
281 game_status == GAME_MODE_PLAYING &&
282 border.draw_masked[GAME_MODE_PLAYING])
283 redraw_mask |= REDRAW_FIELD;
285 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
287 static boolean last_frame_skipped = FALSE;
288 boolean skip_even_when_not_scrolling = TRUE;
289 boolean just_scrolling = (ScreenMovDir != 0);
290 boolean verbose = FALSE;
292 if (global.fps_slowdown_factor > 1 &&
293 (FrameCounter % global.fps_slowdown_factor) &&
294 (just_scrolling || skip_even_when_not_scrolling))
296 redraw_mask &= ~REDRAW_MAIN;
298 last_frame_skipped = TRUE;
301 printf("FRAME SKIPPED\n");
305 if (last_frame_skipped)
306 redraw_mask |= REDRAW_FIELD;
308 last_frame_skipped = FALSE;
311 printf("frame not skipped\n");
315 /* synchronize X11 graphics at this point; if we would synchronize the
316 display immediately after the buffer switching (after the XFlush),
317 this could mean that we have to wait for the graphics to complete,
318 although we could go on doing calculations for the next frame */
322 /* prevent drawing masked border to backbuffer when using playfield buffer */
323 if (game_status != GAME_MODE_PLAYING ||
324 redraw_mask & REDRAW_FROM_BACKBUFFER ||
325 buffer == backbuffer)
326 DrawMaskedBorder(redraw_mask);
328 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
330 if (redraw_mask & REDRAW_ALL)
332 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
334 redraw_mask = REDRAW_NONE;
337 if (redraw_mask & REDRAW_FIELD)
339 if (game_status != GAME_MODE_PLAYING ||
340 redraw_mask & REDRAW_FROM_BACKBUFFER)
342 BlitBitmap(backbuffer, window,
343 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
347 int fx = FX, fy = FY;
349 if (setup.soft_scrolling)
351 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
352 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
355 if (setup.soft_scrolling ||
356 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
357 ABS(ScreenMovPos) == ScrollStepSize ||
358 redraw_tiles > REDRAWTILES_THRESHOLD)
360 if (border.draw_masked[GAME_MODE_PLAYING])
362 if (buffer != backbuffer)
364 /* copy playfield buffer to backbuffer to add masked border */
365 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
366 DrawMaskedBorder(REDRAW_FIELD);
369 BlitBitmap(backbuffer, window,
370 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
375 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
380 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
382 (setup.soft_scrolling ?
383 "setup.soft_scrolling" :
384 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
385 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
386 ABS(ScreenGfxPos) == ScrollStepSize ?
387 "ABS(ScreenGfxPos) == ScrollStepSize" :
388 "redraw_tiles > REDRAWTILES_THRESHOLD"));
394 redraw_mask &= ~REDRAW_MAIN;
397 if (redraw_mask & REDRAW_DOORS)
399 if (redraw_mask & REDRAW_DOOR_1)
400 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
402 if (redraw_mask & REDRAW_DOOR_2)
403 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
405 if (redraw_mask & REDRAW_DOOR_3)
406 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
408 redraw_mask &= ~REDRAW_DOORS;
411 if (redraw_mask & REDRAW_MICROLEVEL)
413 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
414 SX, SY + 10 * TILEY);
416 redraw_mask &= ~REDRAW_MICROLEVEL;
419 if (redraw_mask & REDRAW_TILES)
421 for (x = 0; x < SCR_FIELDX; x++)
422 for (y = 0 ; y < SCR_FIELDY; y++)
423 if (redraw[redraw_x1 + x][redraw_y1 + y])
424 BlitBitmap(buffer, window,
425 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
426 SX + x * TILEX, SY + y * TILEY);
429 if (redraw_mask & REDRAW_FPS) /* display frames per second */
434 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
435 if (!global.fps_slowdown)
438 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
439 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
444 for (x = 0; x < MAX_BUF_XSIZE; x++)
445 for (y = 0; y < MAX_BUF_YSIZE; y++)
448 redraw_mask = REDRAW_NONE;
454 long fading_delay = 300;
456 if (setup.fading && (redraw_mask & REDRAW_FIELD))
463 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
466 for (i = 0; i < 2 * FULL_SYSIZE; i++)
468 for (y = 0; y < FULL_SYSIZE; y++)
470 BlitBitmap(backbuffer, window,
471 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
479 for (i = 1; i < FULL_SYSIZE; i+=2)
480 BlitBitmap(backbuffer, window,
481 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
487 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
488 BlitBitmapMasked(backbuffer, window,
489 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
494 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
495 BlitBitmapMasked(backbuffer, window,
496 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
501 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
502 BlitBitmapMasked(backbuffer, window,
503 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
508 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
509 BlitBitmapMasked(backbuffer, window,
510 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
515 redraw_mask &= ~REDRAW_MAIN;
522 void FadeExt(int fade_mask, int fade_mode)
524 void (*draw_border_function)(void) = NULL;
525 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
526 int x, y, width, height;
527 int fade_delay, post_delay;
529 if (fade_mask & REDRAW_FIELD)
534 height = FULL_SYSIZE;
536 fade_delay = menu.fade_delay;
537 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
539 draw_border_function = DrawMaskedBorder_FIELD;
541 else /* REDRAW_ALL */
548 fade_delay = title.fade_delay_final;
549 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? title.post_delay_final : 0);
552 redraw_mask |= fade_mask;
554 if (!setup.fade_screens || fade_delay == 0)
556 if (fade_mode == FADE_MODE_FADE_OUT)
557 ClearRectangle(backbuffer, x, y, width, height);
564 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
565 draw_border_function);
567 redraw_mask &= ~fade_mask;
570 void FadeIn(int fade_mask)
572 FadeExt(fade_mask, FADE_MODE_FADE_IN);
575 void FadeOut(int fade_mask)
577 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
580 void FadeCross(int fade_mask)
582 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
585 void FadeCrossSaveBackbuffer()
587 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
590 void SetWindowBackgroundImageIfDefined(int graphic)
592 if (graphic_info[graphic].bitmap)
593 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
596 void SetMainBackgroundImageIfDefined(int graphic)
598 if (graphic_info[graphic].bitmap)
599 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
602 void SetDoorBackgroundImageIfDefined(int graphic)
604 if (graphic_info[graphic].bitmap)
605 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
608 void SetWindowBackgroundImage(int graphic)
610 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
611 graphic_info[graphic].bitmap ?
612 graphic_info[graphic].bitmap :
613 graphic_info[IMG_BACKGROUND].bitmap);
616 void SetMainBackgroundImage(int graphic)
618 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
619 graphic_info[graphic].bitmap ?
620 graphic_info[graphic].bitmap :
621 graphic_info[IMG_BACKGROUND].bitmap);
624 void SetDoorBackgroundImage(int graphic)
626 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
627 graphic_info[graphic].bitmap ?
628 graphic_info[graphic].bitmap :
629 graphic_info[IMG_BACKGROUND].bitmap);
632 void SetPanelBackground()
634 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
635 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
637 SetDoorBackgroundBitmap(bitmap_db_panel);
640 void DrawBackground(int x, int y, int width, int height)
642 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
643 /* (when entering hall of fame after playing) */
645 ClearRectangleOnBackground(drawto, x, y, width, height);
647 ClearRectangleOnBackground(backbuffer, x, y, width, height);
650 redraw_mask |= REDRAW_FIELD;
653 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
655 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
657 if (font->bitmap == NULL)
660 DrawBackground(x, y, width, height);
663 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
665 struct GraphicInfo *g = &graphic_info[graphic];
667 if (g->bitmap == NULL)
670 DrawBackground(x, y, width, height);
675 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
676 /* (when entering hall of fame after playing) */
677 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
679 /* !!! maybe this should be done before clearing the background !!! */
680 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
682 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
683 SetDrawtoField(DRAW_BUFFERED);
686 SetDrawtoField(DRAW_BACKBUFFER);
688 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
690 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
691 SetDrawtoField(DRAW_DIRECT);
695 void MarkTileDirty(int x, int y)
697 int xx = redraw_x1 + x;
698 int yy = redraw_y1 + y;
703 redraw[xx][yy] = TRUE;
704 redraw_mask |= REDRAW_TILES;
707 void SetBorderElement()
711 BorderElement = EL_EMPTY;
713 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
715 for (x = 0; x < lev_fieldx; x++)
717 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
718 BorderElement = EL_STEELWALL;
720 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
726 void FloodFillLevel(int from_x, int from_y, int fill_element,
727 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
728 int max_fieldx, int max_fieldy)
732 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
733 static int safety = 0;
735 /* check if starting field still has the desired content */
736 if (field[from_x][from_y] == fill_element)
741 if (safety > max_fieldx * max_fieldy)
742 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
744 old_element = field[from_x][from_y];
745 field[from_x][from_y] = fill_element;
747 for (i = 0; i < 4; i++)
749 x = from_x + check[i][0];
750 y = from_y + check[i][1];
752 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
753 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
759 void SetRandomAnimationValue(int x, int y)
761 gfx.anim_random_frame = GfxRandom[x][y];
764 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
766 /* animation synchronized with global frame counter, not move position */
767 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
768 sync_frame = FrameCounter;
770 return getAnimationFrame(graphic_info[graphic].anim_frames,
771 graphic_info[graphic].anim_delay,
772 graphic_info[graphic].anim_mode,
773 graphic_info[graphic].anim_start_frame,
777 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
778 int *x, int *y, boolean get_backside)
780 struct GraphicInfo *g = &graphic_info[graphic];
781 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
782 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
786 if (g->offset_y == 0) /* frames are ordered horizontally */
788 int max_width = g->anim_frames_per_line * g->width;
789 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
791 *x = pos % max_width;
792 *y = src_y % g->height + pos / max_width * g->height;
794 else if (g->offset_x == 0) /* frames are ordered vertically */
796 int max_height = g->anim_frames_per_line * g->height;
797 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
799 *x = src_x % g->width + pos / max_height * g->width;
800 *y = pos % max_height;
802 else /* frames are ordered diagonally */
804 *x = src_x + frame * g->offset_x;
805 *y = src_y + frame * g->offset_y;
809 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
811 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
814 void DrawGraphic(int x, int y, int graphic, int frame)
817 if (!IN_SCR_FIELD(x, y))
819 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
820 printf("DrawGraphic(): This should never happen!\n");
825 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
829 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
835 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
836 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
839 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
842 if (!IN_SCR_FIELD(x, y))
844 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
845 printf("DrawGraphicThruMask(): This should never happen!\n");
850 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
855 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
861 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
863 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
864 dst_x - src_x, dst_y - src_y);
865 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
868 void DrawMiniGraphic(int x, int y, int graphic)
870 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
871 MarkTileDirty(x / 2, y / 2);
874 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
876 struct GraphicInfo *g = &graphic_info[graphic];
878 int mini_starty = g->bitmap->height * 2 / 3;
881 *x = mini_startx + g->src_x / 2;
882 *y = mini_starty + g->src_y / 2;
885 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
890 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
891 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
894 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
895 int graphic, int frame,
896 int cut_mode, int mask_mode)
901 int width = TILEX, height = TILEY;
904 if (dx || dy) /* shifted graphic */
906 if (x < BX1) /* object enters playfield from the left */
913 else if (x > BX2) /* object enters playfield from the right */
919 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
925 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
927 else if (dx) /* general horizontal movement */
928 MarkTileDirty(x + SIGN(dx), y);
930 if (y < BY1) /* object enters playfield from the top */
932 if (cut_mode==CUT_BELOW) /* object completely above top border */
940 else if (y > BY2) /* object enters playfield from the bottom */
946 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
952 else if (dy > 0 && cut_mode == CUT_ABOVE)
954 if (y == BY2) /* object completely above bottom border */
960 MarkTileDirty(x, y + 1);
961 } /* object leaves playfield to the bottom */
962 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
964 else if (dy) /* general vertical movement */
965 MarkTileDirty(x, y + SIGN(dy));
969 if (!IN_SCR_FIELD(x, y))
971 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
972 printf("DrawGraphicShifted(): This should never happen!\n");
977 if (width > 0 && height > 0)
979 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
984 dst_x = FX + x * TILEX + dx;
985 dst_y = FY + y * TILEY + dy;
987 if (mask_mode == USE_MASKING)
989 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
990 dst_x - src_x, dst_y - src_y);
991 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
995 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1002 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1003 int graphic, int frame,
1004 int cut_mode, int mask_mode)
1009 int width = TILEX, height = TILEY;
1012 int x2 = x + SIGN(dx);
1013 int y2 = y + SIGN(dy);
1014 int anim_frames = graphic_info[graphic].anim_frames;
1015 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1016 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1017 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1019 /* re-calculate animation frame for two-tile movement animation */
1020 frame = getGraphicAnimationFrame(graphic, sync_frame);
1022 /* check if movement start graphic inside screen area and should be drawn */
1023 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1025 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1027 dst_x = FX + x1 * TILEX;
1028 dst_y = FY + y1 * TILEY;
1030 if (mask_mode == USE_MASKING)
1032 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1033 dst_x - src_x, dst_y - src_y);
1034 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1038 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1041 MarkTileDirty(x1, y1);
1044 /* check if movement end graphic inside screen area and should be drawn */
1045 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1047 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1049 dst_x = FX + x2 * TILEX;
1050 dst_y = FY + y2 * TILEY;
1052 if (mask_mode == USE_MASKING)
1054 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1055 dst_x - src_x, dst_y - src_y);
1056 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1060 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1063 MarkTileDirty(x2, y2);
1067 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1068 int graphic, int frame,
1069 int cut_mode, int mask_mode)
1073 DrawGraphic(x, y, graphic, frame);
1078 if (graphic_info[graphic].double_movement) /* EM style movement images */
1079 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1081 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1084 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1085 int frame, int cut_mode)
1087 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1090 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1091 int cut_mode, int mask_mode)
1093 int lx = LEVELX(x), ly = LEVELY(y);
1097 if (IN_LEV_FIELD(lx, ly))
1099 SetRandomAnimationValue(lx, ly);
1101 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1102 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1104 /* do not use double (EM style) movement graphic when not moving */
1105 if (graphic_info[graphic].double_movement && !dx && !dy)
1107 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1108 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1111 else /* border element */
1113 graphic = el2img(element);
1114 frame = getGraphicAnimationFrame(graphic, -1);
1117 if (element == EL_EXPANDABLE_WALL)
1119 boolean left_stopped = FALSE, right_stopped = FALSE;
1121 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1122 left_stopped = TRUE;
1123 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1124 right_stopped = TRUE;
1126 if (left_stopped && right_stopped)
1128 else if (left_stopped)
1130 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1131 frame = graphic_info[graphic].anim_frames - 1;
1133 else if (right_stopped)
1135 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1136 frame = graphic_info[graphic].anim_frames - 1;
1141 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1142 else if (mask_mode == USE_MASKING)
1143 DrawGraphicThruMask(x, y, graphic, frame);
1145 DrawGraphic(x, y, graphic, frame);
1148 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1149 int cut_mode, int mask_mode)
1151 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1152 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1153 cut_mode, mask_mode);
1156 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1159 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1162 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1165 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1168 void DrawLevelElementThruMask(int x, int y, int element)
1170 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1173 void DrawLevelFieldThruMask(int x, int y)
1175 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1178 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1182 int sx = SCREENX(x), sy = SCREENY(y);
1184 int width, height, cx, cy, i;
1185 int crumbled_border_size = graphic_info[graphic].border_size;
1186 static int xy[4][2] =
1194 if (!IN_LEV_FIELD(x, y))
1197 element = TILE_GFX_ELEMENT(x, y);
1199 /* crumble field itself */
1200 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1202 if (!IN_SCR_FIELD(sx, sy))
1205 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1207 for (i = 0; i < 4; i++)
1209 int xx = x + xy[i][0];
1210 int yy = y + xy[i][1];
1212 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1215 /* check if neighbour field is of same type */
1216 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1219 if (i == 1 || i == 2)
1221 width = crumbled_border_size;
1223 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1229 height = crumbled_border_size;
1231 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1234 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1235 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1238 MarkTileDirty(sx, sy);
1240 else /* crumble neighbour fields */
1242 for (i = 0; i < 4; i++)
1244 int xx = x + xy[i][0];
1245 int yy = y + xy[i][1];
1246 int sxx = sx + xy[i][0];
1247 int syy = sy + xy[i][1];
1249 if (!IN_LEV_FIELD(xx, yy) ||
1250 !IN_SCR_FIELD(sxx, syy) ||
1254 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1257 element = TILE_GFX_ELEMENT(xx, yy);
1259 if (!GFX_CRUMBLED(element))
1262 graphic = el_act2crm(element, ACTION_DEFAULT);
1263 crumbled_border_size = graphic_info[graphic].border_size;
1265 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1267 if (i == 1 || i == 2)
1269 width = crumbled_border_size;
1271 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1277 height = crumbled_border_size;
1279 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1282 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1283 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1285 MarkTileDirty(sxx, syy);
1290 void DrawLevelFieldCrumbledSand(int x, int y)
1294 if (!IN_LEV_FIELD(x, y))
1298 /* !!! CHECK THIS !!! */
1301 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1302 GFX_CRUMBLED(GfxElement[x][y]))
1305 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1306 GfxElement[x][y] != EL_UNDEFINED &&
1307 GFX_CRUMBLED(GfxElement[x][y]))
1309 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1316 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1318 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1321 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1324 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1327 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1328 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1329 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1330 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1331 int sx = SCREENX(x), sy = SCREENY(y);
1333 DrawGraphic(sx, sy, graphic1, frame1);
1334 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1337 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1339 int sx = SCREENX(x), sy = SCREENY(y);
1340 static int xy[4][2] =
1349 for (i = 0; i < 4; i++)
1351 int xx = x + xy[i][0];
1352 int yy = y + xy[i][1];
1353 int sxx = sx + xy[i][0];
1354 int syy = sy + xy[i][1];
1356 if (!IN_LEV_FIELD(xx, yy) ||
1357 !IN_SCR_FIELD(sxx, syy) ||
1358 !GFX_CRUMBLED(Feld[xx][yy]) ||
1362 DrawLevelField(xx, yy);
1366 static int getBorderElement(int x, int y)
1370 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1371 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1372 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1373 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1374 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1375 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1376 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1378 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1379 int steel_position = (x == -1 && y == -1 ? 0 :
1380 x == lev_fieldx && y == -1 ? 1 :
1381 x == -1 && y == lev_fieldy ? 2 :
1382 x == lev_fieldx && y == lev_fieldy ? 3 :
1383 x == -1 || x == lev_fieldx ? 4 :
1384 y == -1 || y == lev_fieldy ? 5 : 6);
1386 return border[steel_position][steel_type];
1389 void DrawScreenElement(int x, int y, int element)
1391 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1392 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1395 void DrawLevelElement(int x, int y, int element)
1397 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1398 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1401 void DrawScreenField(int x, int y)
1403 int lx = LEVELX(x), ly = LEVELY(y);
1404 int element, content;
1406 if (!IN_LEV_FIELD(lx, ly))
1408 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1411 element = getBorderElement(lx, ly);
1413 DrawScreenElement(x, y, element);
1417 element = Feld[lx][ly];
1418 content = Store[lx][ly];
1420 if (IS_MOVING(lx, ly))
1422 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1423 boolean cut_mode = NO_CUTTING;
1425 if (element == EL_QUICKSAND_EMPTYING ||
1426 element == EL_QUICKSAND_FAST_EMPTYING ||
1427 element == EL_MAGIC_WALL_EMPTYING ||
1428 element == EL_BD_MAGIC_WALL_EMPTYING ||
1429 element == EL_DC_MAGIC_WALL_EMPTYING ||
1430 element == EL_AMOEBA_DROPPING)
1431 cut_mode = CUT_ABOVE;
1432 else if (element == EL_QUICKSAND_FILLING ||
1433 element == EL_QUICKSAND_FAST_FILLING ||
1434 element == EL_MAGIC_WALL_FILLING ||
1435 element == EL_BD_MAGIC_WALL_FILLING ||
1436 element == EL_DC_MAGIC_WALL_FILLING)
1437 cut_mode = CUT_BELOW;
1439 if (cut_mode == CUT_ABOVE)
1440 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1442 DrawScreenElement(x, y, EL_EMPTY);
1445 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1446 else if (cut_mode == NO_CUTTING)
1447 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1449 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1451 if (content == EL_ACID)
1453 int dir = MovDir[lx][ly];
1454 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1455 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1457 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1460 else if (IS_BLOCKED(lx, ly))
1465 boolean cut_mode = NO_CUTTING;
1466 int element_old, content_old;
1468 Blocked2Moving(lx, ly, &oldx, &oldy);
1471 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1472 MovDir[oldx][oldy] == MV_RIGHT);
1474 element_old = Feld[oldx][oldy];
1475 content_old = Store[oldx][oldy];
1477 if (element_old == EL_QUICKSAND_EMPTYING ||
1478 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1479 element_old == EL_MAGIC_WALL_EMPTYING ||
1480 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1481 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1482 element_old == EL_AMOEBA_DROPPING)
1483 cut_mode = CUT_ABOVE;
1485 DrawScreenElement(x, y, EL_EMPTY);
1488 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1490 else if (cut_mode == NO_CUTTING)
1491 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1494 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1497 else if (IS_DRAWABLE(element))
1498 DrawScreenElement(x, y, element);
1500 DrawScreenElement(x, y, EL_EMPTY);
1503 void DrawLevelField(int x, int y)
1505 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1506 DrawScreenField(SCREENX(x), SCREENY(y));
1507 else if (IS_MOVING(x, y))
1511 Moving2Blocked(x, y, &newx, &newy);
1512 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1513 DrawScreenField(SCREENX(newx), SCREENY(newy));
1515 else if (IS_BLOCKED(x, y))
1519 Blocked2Moving(x, y, &oldx, &oldy);
1520 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1521 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1525 void DrawMiniElement(int x, int y, int element)
1529 graphic = el2edimg(element);
1530 DrawMiniGraphic(x, y, graphic);
1533 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1535 int x = sx + scroll_x, y = sy + scroll_y;
1537 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1538 DrawMiniElement(sx, sy, EL_EMPTY);
1539 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1540 DrawMiniElement(sx, sy, Feld[x][y]);
1542 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1545 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1546 int x, int y, int xsize, int ysize, int font_nr)
1548 int font_width = getFontWidth(font_nr);
1549 int font_height = getFontHeight(font_nr);
1550 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1553 int dst_x = SX + startx + x * font_width;
1554 int dst_y = SY + starty + y * font_height;
1555 int width = graphic_info[graphic].width;
1556 int height = graphic_info[graphic].height;
1557 int inner_width = MAX(width - 2 * font_width, font_width);
1558 int inner_height = MAX(height - 2 * font_height, font_height);
1559 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1560 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1561 boolean draw_masked = graphic_info[graphic].draw_masked;
1563 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1565 if (src_bitmap == NULL || width < font_width || height < font_height)
1567 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1571 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1572 inner_sx + (x - 1) * font_width % inner_width);
1573 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1574 inner_sy + (y - 1) * font_height % inner_height);
1578 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1579 dst_x - src_x, dst_y - src_y);
1580 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1584 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1588 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1590 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1591 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1592 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1593 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1594 boolean no_delay = (tape.warp_forward);
1595 unsigned long anim_delay = 0;
1596 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1597 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1598 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1599 int font_width = getFontWidth(font_nr);
1600 int font_height = getFontHeight(font_nr);
1601 int max_xsize = level.envelope[envelope_nr].xsize;
1602 int max_ysize = level.envelope[envelope_nr].ysize;
1603 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1604 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1605 int xend = max_xsize;
1606 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1607 int xstep = (xstart < xend ? 1 : 0);
1608 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1611 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1613 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1614 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1615 int sx = (SXSIZE - xsize * font_width) / 2;
1616 int sy = (SYSIZE - ysize * font_height) / 2;
1619 SetDrawtoField(DRAW_BUFFERED);
1621 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1623 SetDrawtoField(DRAW_BACKBUFFER);
1625 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1626 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1629 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1630 level.envelope[envelope_nr].text, font_nr, max_xsize,
1631 xsize - 2, ysize - 2, mask_mode,
1632 level.envelope[envelope_nr].autowrap,
1633 level.envelope[envelope_nr].centered, FALSE);
1635 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1636 level.envelope[envelope_nr].text, font_nr, max_xsize,
1637 xsize - 2, ysize - 2, mask_mode);
1640 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1643 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1647 void ShowEnvelope(int envelope_nr)
1649 int element = EL_ENVELOPE_1 + envelope_nr;
1650 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1651 int sound_opening = element_info[element].sound[ACTION_OPENING];
1652 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1653 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1654 boolean no_delay = (tape.warp_forward);
1655 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1656 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1657 int anim_mode = graphic_info[graphic].anim_mode;
1658 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1659 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1661 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1663 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1665 if (anim_mode == ANIM_DEFAULT)
1666 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1668 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1671 Delay(wait_delay_value);
1673 WaitForEventToContinue();
1675 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1677 if (anim_mode != ANIM_NONE)
1678 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1680 if (anim_mode == ANIM_DEFAULT)
1681 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1683 game.envelope_active = FALSE;
1685 SetDrawtoField(DRAW_BUFFERED);
1687 redraw_mask |= REDRAW_FIELD;
1691 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1696 int width_mult, width_div;
1697 int height_mult, height_div;
1705 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1706 5 - log_2(tilesize));
1707 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1708 int width_mult = offset_calc[offset_calc_pos].width_mult;
1709 int width_div = offset_calc[offset_calc_pos].width_div;
1710 int height_mult = offset_calc[offset_calc_pos].height_mult;
1711 int height_div = offset_calc[offset_calc_pos].height_div;
1712 int mini_startx = src_bitmap->width * width_mult / width_div;
1713 int mini_starty = src_bitmap->height * height_mult / height_div;
1714 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1715 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1717 *bitmap = src_bitmap;
1722 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1726 int graphic = el2preimg(element);
1728 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1729 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1736 SetDrawBackgroundMask(REDRAW_NONE);
1739 for (x = BX1; x <= BX2; x++)
1740 for (y = BY1; y <= BY2; y++)
1741 DrawScreenField(x, y);
1743 redraw_mask |= REDRAW_FIELD;
1746 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1750 for (x = 0; x < size_x; x++)
1751 for (y = 0; y < size_y; y++)
1752 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1754 redraw_mask |= REDRAW_FIELD;
1757 static void DrawPreviewLevelExt(int from_x, int from_y)
1759 boolean show_level_border = (BorderElement != EL_EMPTY);
1760 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1761 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1762 int tile_size = preview.tile_size;
1763 int preview_width = preview.xsize * tile_size;
1764 int preview_height = preview.ysize * tile_size;
1765 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1766 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1767 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1768 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1771 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1773 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1774 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1776 for (x = 0; x < real_preview_xsize; x++)
1778 for (y = 0; y < real_preview_ysize; y++)
1780 int lx = from_x + x + (show_level_border ? -1 : 0);
1781 int ly = from_y + y + (show_level_border ? -1 : 0);
1782 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1783 getBorderElement(lx, ly));
1785 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1786 element, tile_size);
1790 redraw_mask |= REDRAW_MICROLEVEL;
1793 #define MICROLABEL_EMPTY 0
1794 #define MICROLABEL_LEVEL_NAME 1
1795 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1796 #define MICROLABEL_LEVEL_AUTHOR 3
1797 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1798 #define MICROLABEL_IMPORTED_FROM 5
1799 #define MICROLABEL_IMPORTED_BY_HEAD 6
1800 #define MICROLABEL_IMPORTED_BY 7
1802 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
1804 int max_text_width = SXSIZE;
1805 int font_width = getFontWidth(font_nr);
1807 if (pos->align == ALIGN_CENTER)
1808 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1809 else if (pos->align == ALIGN_RIGHT)
1810 max_text_width = pos->x;
1812 max_text_width = SXSIZE - pos->x;
1814 return max_text_width / font_width;
1817 static void DrawPreviewLevelLabelExt(int mode)
1819 struct TextPosInfo *pos = &menu.main.text.level_info_2;
1820 char label_text[MAX_OUTPUT_LINESIZE + 1];
1821 int max_len_label_text;
1823 int font_nr = pos->font;
1826 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1827 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1828 mode == MICROLABEL_IMPORTED_BY_HEAD)
1829 font_nr = pos->font_alt;
1831 int font_nr = FONT_TEXT_2;
1834 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1835 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1836 mode == MICROLABEL_IMPORTED_BY_HEAD)
1837 font_nr = FONT_TEXT_3;
1841 max_len_label_text = getMaxTextLength(pos, font_nr);
1843 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1847 if (pos->chars != -1)
1848 max_len_label_text = pos->chars;
1851 for (i = 0; i < max_len_label_text; i++)
1852 label_text[i] = ' ';
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);
1868 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1869 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1870 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1871 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1872 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1873 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1874 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1875 max_len_label_text);
1876 label_text[max_len_label_text] = '\0';
1878 if (strlen(label_text) > 0)
1881 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1883 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1884 int lypos = MICROLABEL2_YPOS;
1886 DrawText(lxpos, lypos, label_text, font_nr);
1890 redraw_mask |= REDRAW_MICROLEVEL;
1893 void DrawPreviewLevel(boolean restart)
1895 static unsigned long scroll_delay = 0;
1896 static unsigned long label_delay = 0;
1897 static int from_x, from_y, scroll_direction;
1898 static int label_state, label_counter;
1899 unsigned long scroll_delay_value = preview.step_delay;
1900 boolean show_level_border = (BorderElement != EL_EMPTY);
1901 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1902 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1903 int last_game_status = game_status; /* save current game status */
1906 /* force PREVIEW font on preview level */
1907 game_status = GAME_MODE_PSEUDO_PREVIEW;
1915 if (preview.anim_mode == ANIM_CENTERED)
1917 if (level_xsize > preview.xsize)
1918 from_x = (level_xsize - preview.xsize) / 2;
1919 if (level_ysize > preview.ysize)
1920 from_y = (level_ysize - preview.ysize) / 2;
1923 from_x += preview.xoffset;
1924 from_y += preview.yoffset;
1926 scroll_direction = MV_RIGHT;
1930 DrawPreviewLevelExt(from_x, from_y);
1931 DrawPreviewLevelLabelExt(label_state);
1933 /* initialize delay counters */
1934 DelayReached(&scroll_delay, 0);
1935 DelayReached(&label_delay, 0);
1937 if (leveldir_current->name)
1939 struct TextPosInfo *pos = &menu.main.text.level_info_1;
1940 char label_text[MAX_OUTPUT_LINESIZE + 1];
1942 int font_nr = pos->font;
1944 int font_nr = FONT_TEXT_1;
1947 int max_len_label_text = getMaxTextLength(pos, font_nr);
1949 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1957 if (pos->chars != -1)
1958 max_len_label_text = pos->chars;
1961 strncpy(label_text, leveldir_current->name, max_len_label_text);
1962 label_text[max_len_label_text] = '\0';
1965 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1967 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1968 lypos = SY + MICROLABEL1_YPOS;
1970 DrawText(lxpos, lypos, label_text, font_nr);
1974 game_status = last_game_status; /* restore current game status */
1979 /* scroll preview level, if needed */
1980 if (preview.anim_mode != ANIM_NONE &&
1981 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1982 DelayReached(&scroll_delay, scroll_delay_value))
1984 switch (scroll_direction)
1989 from_x -= preview.step_offset;
1990 from_x = (from_x < 0 ? 0 : from_x);
1993 scroll_direction = MV_UP;
1997 if (from_x < level_xsize - preview.xsize)
1999 from_x += preview.step_offset;
2000 from_x = (from_x > level_xsize - preview.xsize ?
2001 level_xsize - preview.xsize : from_x);
2004 scroll_direction = MV_DOWN;
2010 from_y -= preview.step_offset;
2011 from_y = (from_y < 0 ? 0 : from_y);
2014 scroll_direction = MV_RIGHT;
2018 if (from_y < level_ysize - preview.ysize)
2020 from_y += preview.step_offset;
2021 from_y = (from_y > level_ysize - preview.ysize ?
2022 level_ysize - preview.ysize : from_y);
2025 scroll_direction = MV_LEFT;
2032 DrawPreviewLevelExt(from_x, from_y);
2035 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2036 /* redraw micro level label, if needed */
2037 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2038 !strEqual(level.author, ANONYMOUS_NAME) &&
2039 !strEqual(level.author, leveldir_current->name) &&
2040 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2042 int max_label_counter = 23;
2044 if (leveldir_current->imported_from != NULL &&
2045 strlen(leveldir_current->imported_from) > 0)
2046 max_label_counter += 14;
2047 if (leveldir_current->imported_by != NULL &&
2048 strlen(leveldir_current->imported_by) > 0)
2049 max_label_counter += 14;
2051 label_counter = (label_counter + 1) % max_label_counter;
2052 label_state = (label_counter >= 0 && label_counter <= 7 ?
2053 MICROLABEL_LEVEL_NAME :
2054 label_counter >= 9 && label_counter <= 12 ?
2055 MICROLABEL_LEVEL_AUTHOR_HEAD :
2056 label_counter >= 14 && label_counter <= 21 ?
2057 MICROLABEL_LEVEL_AUTHOR :
2058 label_counter >= 23 && label_counter <= 26 ?
2059 MICROLABEL_IMPORTED_FROM_HEAD :
2060 label_counter >= 28 && label_counter <= 35 ?
2061 MICROLABEL_IMPORTED_FROM :
2062 label_counter >= 37 && label_counter <= 40 ?
2063 MICROLABEL_IMPORTED_BY_HEAD :
2064 label_counter >= 42 && label_counter <= 49 ?
2065 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2067 if (leveldir_current->imported_from == NULL &&
2068 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2069 label_state == MICROLABEL_IMPORTED_FROM))
2070 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2071 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2073 DrawPreviewLevelLabelExt(label_state);
2076 game_status = last_game_status; /* restore current game status */
2079 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2080 int graphic, int sync_frame, int mask_mode)
2082 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2084 if (mask_mode == USE_MASKING)
2085 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2087 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2090 inline void DrawGraphicAnimation(int x, int y, int graphic)
2092 int lx = LEVELX(x), ly = LEVELY(y);
2094 if (!IN_SCR_FIELD(x, y))
2097 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2098 graphic, GfxFrame[lx][ly], NO_MASKING);
2099 MarkTileDirty(x, y);
2102 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2104 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2107 void DrawLevelElementAnimation(int x, int y, int element)
2109 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2111 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2114 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2116 int sx = SCREENX(x), sy = SCREENY(y);
2118 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2121 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2124 DrawGraphicAnimation(sx, sy, graphic);
2127 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2128 DrawLevelFieldCrumbledSand(x, y);
2130 if (GFX_CRUMBLED(Feld[x][y]))
2131 DrawLevelFieldCrumbledSand(x, y);
2135 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2137 int sx = SCREENX(x), sy = SCREENY(y);
2140 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2143 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2145 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2148 DrawGraphicAnimation(sx, sy, graphic);
2150 if (GFX_CRUMBLED(element))
2151 DrawLevelFieldCrumbledSand(x, y);
2154 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2156 if (player->use_murphy)
2158 /* this works only because currently only one player can be "murphy" ... */
2159 static int last_horizontal_dir = MV_LEFT;
2160 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2162 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2163 last_horizontal_dir = move_dir;
2165 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2167 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2169 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2175 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2178 static boolean equalGraphics(int graphic1, int graphic2)
2180 struct GraphicInfo *g1 = &graphic_info[graphic1];
2181 struct GraphicInfo *g2 = &graphic_info[graphic2];
2183 return (g1->bitmap == g2->bitmap &&
2184 g1->src_x == g2->src_x &&
2185 g1->src_y == g2->src_y &&
2186 g1->anim_frames == g2->anim_frames &&
2187 g1->anim_delay == g2->anim_delay &&
2188 g1->anim_mode == g2->anim_mode);
2191 void DrawAllPlayers()
2195 for (i = 0; i < MAX_PLAYERS; i++)
2196 if (stored_player[i].active)
2197 DrawPlayer(&stored_player[i]);
2200 void DrawPlayerField(int x, int y)
2202 if (!IS_PLAYER(x, y))
2205 DrawPlayer(PLAYERINFO(x, y));
2208 void DrawPlayer(struct PlayerInfo *player)
2210 int jx = player->jx;
2211 int jy = player->jy;
2212 int move_dir = player->MovDir;
2213 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2214 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2215 int last_jx = (player->is_moving ? jx - dx : jx);
2216 int last_jy = (player->is_moving ? jy - dy : jy);
2217 int next_jx = jx + dx;
2218 int next_jy = jy + dy;
2219 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2220 boolean player_is_opaque = FALSE;
2221 int sx = SCREENX(jx), sy = SCREENY(jy);
2222 int sxx = 0, syy = 0;
2223 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2225 int action = ACTION_DEFAULT;
2226 int last_player_graphic = getPlayerGraphic(player, move_dir);
2227 int last_player_frame = player->Frame;
2230 /* GfxElement[][] is set to the element the player is digging or collecting;
2231 remove also for off-screen player if the player is not moving anymore */
2232 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2233 GfxElement[jx][jy] = EL_UNDEFINED;
2235 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2239 if (!IN_LEV_FIELD(jx, jy))
2241 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2242 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2243 printf("DrawPlayerField(): This should never happen!\n");
2248 if (element == EL_EXPLOSION)
2251 action = (player->is_pushing ? ACTION_PUSHING :
2252 player->is_digging ? ACTION_DIGGING :
2253 player->is_collecting ? ACTION_COLLECTING :
2254 player->is_moving ? ACTION_MOVING :
2255 player->is_snapping ? ACTION_SNAPPING :
2256 player->is_dropping ? ACTION_DROPPING :
2257 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2259 if (player->is_waiting)
2260 move_dir = player->dir_waiting;
2262 InitPlayerGfxAnimation(player, action, move_dir);
2264 /* ----------------------------------------------------------------------- */
2265 /* draw things in the field the player is leaving, if needed */
2266 /* ----------------------------------------------------------------------- */
2268 if (player->is_moving)
2270 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2272 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2274 if (last_element == EL_DYNAMITE_ACTIVE ||
2275 last_element == EL_EM_DYNAMITE_ACTIVE ||
2276 last_element == EL_SP_DISK_RED_ACTIVE)
2277 DrawDynamite(last_jx, last_jy);
2279 DrawLevelFieldThruMask(last_jx, last_jy);
2281 else if (last_element == EL_DYNAMITE_ACTIVE ||
2282 last_element == EL_EM_DYNAMITE_ACTIVE ||
2283 last_element == EL_SP_DISK_RED_ACTIVE)
2284 DrawDynamite(last_jx, last_jy);
2286 /* !!! this is not enough to prevent flickering of players which are
2287 moving next to each others without a free tile between them -- this
2288 can only be solved by drawing all players layer by layer (first the
2289 background, then the foreground etc.) !!! => TODO */
2290 else if (!IS_PLAYER(last_jx, last_jy))
2291 DrawLevelField(last_jx, last_jy);
2294 DrawLevelField(last_jx, last_jy);
2297 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2298 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2301 if (!IN_SCR_FIELD(sx, sy))
2304 if (setup.direct_draw)
2305 SetDrawtoField(DRAW_BUFFERED);
2307 /* ----------------------------------------------------------------------- */
2308 /* draw things behind the player, if needed */
2309 /* ----------------------------------------------------------------------- */
2312 DrawLevelElement(jx, jy, Back[jx][jy]);
2313 else if (IS_ACTIVE_BOMB(element))
2314 DrawLevelElement(jx, jy, EL_EMPTY);
2317 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2319 int old_element = GfxElement[jx][jy];
2320 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2321 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2323 if (GFX_CRUMBLED(old_element))
2324 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2326 DrawGraphic(sx, sy, old_graphic, frame);
2328 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2329 player_is_opaque = TRUE;
2333 GfxElement[jx][jy] = EL_UNDEFINED;
2335 /* make sure that pushed elements are drawn with correct frame rate */
2337 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2339 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2340 GfxFrame[jx][jy] = player->StepFrame;
2342 if (player->is_pushing && player->is_moving)
2343 GfxFrame[jx][jy] = player->StepFrame;
2346 DrawLevelField(jx, jy);
2350 /* ----------------------------------------------------------------------- */
2351 /* draw player himself */
2352 /* ----------------------------------------------------------------------- */
2354 graphic = getPlayerGraphic(player, move_dir);
2356 /* in the case of changed player action or direction, prevent the current
2357 animation frame from being restarted for identical animations */
2358 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2359 player->Frame = last_player_frame;
2361 frame = getGraphicAnimationFrame(graphic, player->Frame);
2365 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2366 sxx = player->GfxPos;
2368 syy = player->GfxPos;
2371 if (!setup.soft_scrolling && ScreenMovPos)
2374 if (player_is_opaque)
2375 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2377 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2379 if (SHIELD_ON(player))
2381 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2382 IMG_SHIELD_NORMAL_ACTIVE);
2383 int frame = getGraphicAnimationFrame(graphic, -1);
2385 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2388 /* ----------------------------------------------------------------------- */
2389 /* draw things the player is pushing, if needed */
2390 /* ----------------------------------------------------------------------- */
2393 printf("::: %d, %d [%d, %d] [%d]\n",
2394 player->is_pushing, player_is_moving, player->GfxAction,
2395 player->is_moving, player_is_moving);
2399 if (player->is_pushing && player->is_moving)
2401 int px = SCREENX(jx), py = SCREENY(jy);
2402 int pxx = (TILEX - ABS(sxx)) * dx;
2403 int pyy = (TILEY - ABS(syy)) * dy;
2404 int gfx_frame = GfxFrame[jx][jy];
2410 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2412 element = Feld[next_jx][next_jy];
2413 gfx_frame = GfxFrame[next_jx][next_jy];
2416 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2419 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2420 frame = getGraphicAnimationFrame(graphic, sync_frame);
2422 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2425 /* draw background element under pushed element (like the Sokoban field) */
2426 if (Back[next_jx][next_jy])
2427 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2429 /* masked drawing is needed for EMC style (double) movement graphics */
2430 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2434 /* ----------------------------------------------------------------------- */
2435 /* draw things in front of player (active dynamite or dynabombs) */
2436 /* ----------------------------------------------------------------------- */
2438 if (IS_ACTIVE_BOMB(element))
2440 graphic = el2img(element);
2441 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2443 if (game.emulation == EMU_SUPAPLEX)
2444 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2446 DrawGraphicThruMask(sx, sy, graphic, frame);
2449 if (player_is_moving && last_element == EL_EXPLOSION)
2451 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2452 GfxElement[last_jx][last_jy] : EL_EMPTY);
2453 int graphic = el_act2img(element, ACTION_EXPLODING);
2454 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2455 int phase = ExplodePhase[last_jx][last_jy] - 1;
2456 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2459 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2462 /* ----------------------------------------------------------------------- */
2463 /* draw elements the player is just walking/passing through/under */
2464 /* ----------------------------------------------------------------------- */
2466 if (player_is_moving)
2468 /* handle the field the player is leaving ... */
2469 if (IS_ACCESSIBLE_INSIDE(last_element))
2470 DrawLevelField(last_jx, last_jy);
2471 else if (IS_ACCESSIBLE_UNDER(last_element))
2472 DrawLevelFieldThruMask(last_jx, last_jy);
2475 /* do not redraw accessible elements if the player is just pushing them */
2476 if (!player_is_moving || !player->is_pushing)
2478 /* ... and the field the player is entering */
2479 if (IS_ACCESSIBLE_INSIDE(element))
2480 DrawLevelField(jx, jy);
2481 else if (IS_ACCESSIBLE_UNDER(element))
2482 DrawLevelFieldThruMask(jx, jy);
2485 if (setup.direct_draw)
2487 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2488 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2489 int x_size = TILEX * (1 + ABS(jx - last_jx));
2490 int y_size = TILEY * (1 + ABS(jy - last_jy));
2492 BlitBitmap(drawto_field, window,
2493 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2494 SetDrawtoField(DRAW_DIRECT);
2497 MarkTileDirty(sx, sy);
2500 /* ------------------------------------------------------------------------- */
2502 void WaitForEventToContinue()
2504 boolean still_wait = TRUE;
2506 /* simulate releasing mouse button over last gadget, if still pressed */
2508 HandleGadgets(-1, -1, 0);
2510 button_status = MB_RELEASED;
2526 case EVENT_BUTTONPRESS:
2527 case EVENT_KEYPRESS:
2531 case EVENT_KEYRELEASE:
2532 ClearPlayerAction();
2536 HandleOtherEvents(&event);
2540 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2547 /* don't eat all CPU time */
2552 #define MAX_REQUEST_LINES 13
2553 #define MAX_REQUEST_LINE_FONT1_LEN 7
2554 #define MAX_REQUEST_LINE_FONT2_LEN 10
2556 boolean Request(char *text, unsigned int req_state)
2558 int mx, my, ty, result = -1;
2559 unsigned int old_door_state;
2560 int last_game_status = game_status; /* save current game status */
2561 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2562 int font_nr = FONT_TEXT_2;
2563 int max_word_len = 0;
2566 for (text_ptr = text; *text_ptr; text_ptr++)
2568 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2570 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2572 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2574 font_nr = FONT_TEXT_1;
2576 font_nr = FONT_LEVEL_NUMBER;
2583 if (game_status == GAME_MODE_PLAYING &&
2584 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2585 BlitScreenToBitmap_EM(backbuffer);
2587 /* disable deactivated drawing when quick-loading level tape recording */
2588 if (tape.playing && tape.deactivate_display)
2589 TapeDeactivateDisplayOff(TRUE);
2591 SetMouseCursor(CURSOR_DEFAULT);
2593 #if defined(NETWORK_AVALIABLE)
2594 /* pause network game while waiting for request to answer */
2595 if (options.network &&
2596 game_status == GAME_MODE_PLAYING &&
2597 req_state & REQUEST_WAIT_FOR_INPUT)
2598 SendToServer_PausePlaying();
2601 old_door_state = GetDoorState();
2603 /* simulate releasing mouse button over last gadget, if still pressed */
2605 HandleGadgets(-1, -1, 0);
2609 if (old_door_state & DOOR_OPEN_1)
2611 CloseDoor(DOOR_CLOSE_1);
2613 /* save old door content */
2614 BlitBitmap(bitmap_db_door, bitmap_db_door,
2615 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2616 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2620 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2623 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2625 /* clear door drawing field */
2626 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2628 /* force DOOR font inside door area */
2629 game_status = GAME_MODE_PSEUDO_DOOR;
2631 /* write text for request */
2632 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2634 char text_line[max_request_line_len + 1];
2640 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2643 if (!tc || tc == ' ')
2654 strncpy(text_line, text, tl);
2657 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2658 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2659 text_line, font_nr);
2661 text += tl + (tc == ' ' ? 1 : 0);
2664 game_status = last_game_status; /* restore current game status */
2666 if (req_state & REQ_ASK)
2668 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2669 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2671 else if (req_state & REQ_CONFIRM)
2673 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2675 else if (req_state & REQ_PLAYER)
2677 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2678 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2679 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2680 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2683 /* copy request gadgets to door backbuffer */
2684 BlitBitmap(drawto, bitmap_db_door,
2685 DX, DY, DXSIZE, DYSIZE,
2686 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2688 OpenDoor(DOOR_OPEN_1);
2690 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2692 if (game_status == GAME_MODE_PLAYING)
2694 SetPanelBackground();
2695 SetDrawBackgroundMask(REDRAW_DOOR_1);
2699 SetDrawBackgroundMask(REDRAW_FIELD);
2705 if (game_status != GAME_MODE_MAIN)
2708 button_status = MB_RELEASED;
2710 request_gadget_id = -1;
2712 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2724 case EVENT_BUTTONPRESS:
2725 case EVENT_BUTTONRELEASE:
2726 case EVENT_MOTIONNOTIFY:
2728 if (event.type == EVENT_MOTIONNOTIFY)
2730 if (!PointerInWindow(window))
2731 continue; /* window and pointer are on different screens */
2736 motion_status = TRUE;
2737 mx = ((MotionEvent *) &event)->x;
2738 my = ((MotionEvent *) &event)->y;
2742 motion_status = FALSE;
2743 mx = ((ButtonEvent *) &event)->x;
2744 my = ((ButtonEvent *) &event)->y;
2745 if (event.type == EVENT_BUTTONPRESS)
2746 button_status = ((ButtonEvent *) &event)->button;
2748 button_status = MB_RELEASED;
2751 /* this sets 'request_gadget_id' */
2752 HandleGadgets(mx, my, button_status);
2754 switch (request_gadget_id)
2756 case TOOL_CTRL_ID_YES:
2759 case TOOL_CTRL_ID_NO:
2762 case TOOL_CTRL_ID_CONFIRM:
2763 result = TRUE | FALSE;
2766 case TOOL_CTRL_ID_PLAYER_1:
2769 case TOOL_CTRL_ID_PLAYER_2:
2772 case TOOL_CTRL_ID_PLAYER_3:
2775 case TOOL_CTRL_ID_PLAYER_4:
2786 case EVENT_KEYPRESS:
2787 switch (GetEventKey((KeyEvent *)&event, TRUE))
2800 if (req_state & REQ_PLAYER)
2804 case EVENT_KEYRELEASE:
2805 ClearPlayerAction();
2809 HandleOtherEvents(&event);
2813 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2815 int joy = AnyJoystick();
2817 if (joy & JOY_BUTTON_1)
2819 else if (joy & JOY_BUTTON_2)
2825 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2827 HandleGameActions();
2834 if (!PendingEvent()) /* delay only if no pending events */
2843 if (!PendingEvent()) /* delay only if no pending events */
2846 /* don't eat all CPU time */
2853 if (game_status != GAME_MODE_MAIN)
2858 if (!(req_state & REQ_STAY_OPEN))
2860 CloseDoor(DOOR_CLOSE_1);
2862 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2863 (req_state & REQ_REOPEN))
2864 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2869 if (game_status == GAME_MODE_PLAYING)
2871 SetPanelBackground();
2872 SetDrawBackgroundMask(REDRAW_DOOR_1);
2876 SetDrawBackgroundMask(REDRAW_FIELD);
2879 #if defined(NETWORK_AVALIABLE)
2880 /* continue network game after request */
2881 if (options.network &&
2882 game_status == GAME_MODE_PLAYING &&
2883 req_state & REQUEST_WAIT_FOR_INPUT)
2884 SendToServer_ContinuePlaying();
2887 /* restore deactivated drawing when quick-loading level tape recording */
2888 if (tape.playing && tape.deactivate_display)
2889 TapeDeactivateDisplayOn();
2894 unsigned int OpenDoor(unsigned int door_state)
2896 if (door_state & DOOR_COPY_BACK)
2898 if (door_state & DOOR_OPEN_1)
2899 BlitBitmap(bitmap_db_door, bitmap_db_door,
2900 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2901 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2903 if (door_state & DOOR_OPEN_2)
2904 BlitBitmap(bitmap_db_door, bitmap_db_door,
2905 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2906 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2908 door_state &= ~DOOR_COPY_BACK;
2911 return MoveDoor(door_state);
2914 unsigned int CloseDoor(unsigned int door_state)
2916 unsigned int old_door_state = GetDoorState();
2918 if (!(door_state & DOOR_NO_COPY_BACK))
2920 if (old_door_state & DOOR_OPEN_1)
2921 BlitBitmap(backbuffer, bitmap_db_door,
2922 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2924 if (old_door_state & DOOR_OPEN_2)
2925 BlitBitmap(backbuffer, bitmap_db_door,
2926 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2928 door_state &= ~DOOR_NO_COPY_BACK;
2931 return MoveDoor(door_state);
2934 unsigned int GetDoorState()
2936 return MoveDoor(DOOR_GET_STATE);
2939 unsigned int SetDoorState(unsigned int door_state)
2941 return MoveDoor(door_state | DOOR_SET_STATE);
2944 unsigned int MoveDoor(unsigned int door_state)
2946 static int door1 = DOOR_OPEN_1;
2947 static int door2 = DOOR_CLOSE_2;
2948 unsigned long door_delay = 0;
2949 unsigned long door_delay_value;
2952 if (door_1.width < 0 || door_1.width > DXSIZE)
2953 door_1.width = DXSIZE;
2954 if (door_1.height < 0 || door_1.height > DYSIZE)
2955 door_1.height = DYSIZE;
2956 if (door_2.width < 0 || door_2.width > VXSIZE)
2957 door_2.width = VXSIZE;
2958 if (door_2.height < 0 || door_2.height > VYSIZE)
2959 door_2.height = VYSIZE;
2961 if (door_state == DOOR_GET_STATE)
2962 return (door1 | door2);
2964 if (door_state & DOOR_SET_STATE)
2966 if (door_state & DOOR_ACTION_1)
2967 door1 = door_state & DOOR_ACTION_1;
2968 if (door_state & DOOR_ACTION_2)
2969 door2 = door_state & DOOR_ACTION_2;
2971 return (door1 | door2);
2974 if (!(door_state & DOOR_FORCE_REDRAW))
2976 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2977 door_state &= ~DOOR_OPEN_1;
2978 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2979 door_state &= ~DOOR_CLOSE_1;
2980 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2981 door_state &= ~DOOR_OPEN_2;
2982 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2983 door_state &= ~DOOR_CLOSE_2;
2986 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2989 if (setup.quick_doors)
2991 stepsize = 20; /* must be choosen to always draw last frame */
2992 door_delay_value = 0;
2995 if (global.autoplay_leveldir)
2997 door_state |= DOOR_NO_DELAY;
2998 door_state &= ~DOOR_CLOSE_ALL;
3001 if (door_state & DOOR_ACTION)
3003 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3004 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3005 boolean door_1_done = (!handle_door_1);
3006 boolean door_2_done = (!handle_door_2);
3007 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3008 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3009 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3010 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3011 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3012 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3013 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3014 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3015 int door_skip = max_door_size - door_size;
3016 int end = door_size;
3017 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3020 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3022 /* opening door sound has priority over simultaneously closing door */
3023 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3024 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3025 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3026 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3029 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3032 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3033 GC gc = bitmap->stored_clip_gc;
3035 if (door_state & DOOR_ACTION_1)
3037 int a = MIN(x * door_1.step_offset, end);
3038 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3039 int i = p + door_skip;
3041 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3043 BlitBitmap(bitmap_db_door, drawto,
3044 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3045 DXSIZE, DYSIZE, DX, DY);
3049 BlitBitmap(bitmap_db_door, drawto,
3050 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3051 DXSIZE, DYSIZE - p / 2, DX, DY);
3053 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3056 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3058 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3059 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3060 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3061 int dst2_x = DX, dst2_y = DY;
3062 int width = i, height = DYSIZE;
3064 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3065 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3068 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3069 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3072 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3074 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3075 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3076 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3077 int dst2_x = DX, dst2_y = DY;
3078 int width = DXSIZE, height = i;
3080 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3081 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3084 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3085 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3088 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3090 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3092 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3093 BlitBitmapMasked(bitmap, drawto,
3094 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3095 DX + DXSIZE - i, DY + j);
3096 BlitBitmapMasked(bitmap, drawto,
3097 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3098 DX + DXSIZE - i, DY + 140 + j);
3099 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3100 DY - (DOOR_GFX_PAGEY1 + j));
3101 BlitBitmapMasked(bitmap, drawto,
3102 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3104 BlitBitmapMasked(bitmap, drawto,
3105 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3108 BlitBitmapMasked(bitmap, drawto,
3109 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3111 BlitBitmapMasked(bitmap, drawto,
3112 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3114 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3115 BlitBitmapMasked(bitmap, drawto,
3116 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3117 DX + DXSIZE - i, DY + 77 + j);
3118 BlitBitmapMasked(bitmap, drawto,
3119 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3120 DX + DXSIZE - i, DY + 203 + j);
3123 redraw_mask |= REDRAW_DOOR_1;
3124 door_1_done = (a == end);
3127 if (door_state & DOOR_ACTION_2)
3129 int a = MIN(x * door_2.step_offset, door_size);
3130 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3131 int i = p + door_skip;
3133 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3135 BlitBitmap(bitmap_db_door, drawto,
3136 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3137 VXSIZE, VYSIZE, VX, VY);
3139 else if (x <= VYSIZE)
3141 BlitBitmap(bitmap_db_door, drawto,
3142 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3143 VXSIZE, VYSIZE - p / 2, VX, VY);
3145 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3148 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3150 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3151 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3152 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3153 int dst2_x = VX, dst2_y = VY;
3154 int width = i, height = VYSIZE;
3156 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3157 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3160 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3161 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3164 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3166 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3167 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3168 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3169 int dst2_x = VX, dst2_y = VY;
3170 int width = VXSIZE, height = i;
3172 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3173 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3176 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3177 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3180 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3182 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3184 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3185 BlitBitmapMasked(bitmap, drawto,
3186 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3187 VX + VXSIZE - i, VY + j);
3188 SetClipOrigin(bitmap, gc,
3189 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3190 BlitBitmapMasked(bitmap, drawto,
3191 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3194 BlitBitmapMasked(bitmap, drawto,
3195 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3196 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3197 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3198 BlitBitmapMasked(bitmap, drawto,
3199 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3201 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3204 redraw_mask |= REDRAW_DOOR_2;
3205 door_2_done = (a == VXSIZE);
3208 if (!(door_state & DOOR_NO_DELAY))
3212 if (game_status == GAME_MODE_MAIN)
3215 WaitUntilDelayReached(&door_delay, door_delay_value);
3220 if (door_state & DOOR_ACTION_1)
3221 door1 = door_state & DOOR_ACTION_1;
3222 if (door_state & DOOR_ACTION_2)
3223 door2 = door_state & DOOR_ACTION_2;
3225 return (door1 | door2);
3228 void DrawSpecialEditorDoor()
3230 /* draw bigger toolbox window */
3231 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3232 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3234 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3235 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3238 redraw_mask |= REDRAW_ALL;
3241 void UndrawSpecialEditorDoor()
3243 /* draw normal tape recorder window */
3244 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3245 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3248 redraw_mask |= REDRAW_ALL;
3252 /* ---------- new tool button stuff ---------------------------------------- */
3254 /* graphic position values for tool buttons */
3255 #define TOOL_BUTTON_YES_XPOS 2
3256 #define TOOL_BUTTON_YES_YPOS 250
3257 #define TOOL_BUTTON_YES_GFX_YPOS 0
3258 #define TOOL_BUTTON_YES_XSIZE 46
3259 #define TOOL_BUTTON_YES_YSIZE 28
3260 #define TOOL_BUTTON_NO_XPOS 52
3261 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3262 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3263 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3264 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3265 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3266 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3267 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3268 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3269 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3270 #define TOOL_BUTTON_PLAYER_XSIZE 30
3271 #define TOOL_BUTTON_PLAYER_YSIZE 30
3272 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3273 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3274 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3275 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3276 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3277 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3278 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3279 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3280 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3281 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3282 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3283 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3284 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3285 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3286 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3287 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3288 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3289 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3290 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3291 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3300 } toolbutton_info[NUM_TOOL_BUTTONS] =
3303 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3304 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3305 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3310 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3311 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3312 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3317 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3318 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3319 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3320 TOOL_CTRL_ID_CONFIRM,
3324 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3325 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3326 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3327 TOOL_CTRL_ID_PLAYER_1,
3331 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3332 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3333 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3334 TOOL_CTRL_ID_PLAYER_2,
3338 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3339 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3340 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3341 TOOL_CTRL_ID_PLAYER_3,
3345 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3346 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3347 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3348 TOOL_CTRL_ID_PLAYER_4,
3353 void CreateToolButtons()
3357 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3359 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3360 Bitmap *deco_bitmap = None;
3361 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3362 struct GadgetInfo *gi;
3363 unsigned long event_mask;
3364 int gd_xoffset, gd_yoffset;
3365 int gd_x1, gd_x2, gd_y;
3368 event_mask = GD_EVENT_RELEASED;
3370 gd_xoffset = toolbutton_info[i].xpos;
3371 gd_yoffset = toolbutton_info[i].ypos;
3372 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3373 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3374 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3376 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3378 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3380 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3381 &deco_bitmap, &deco_x, &deco_y);
3382 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3383 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3386 gi = CreateGadget(GDI_CUSTOM_ID, id,
3387 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3388 GDI_X, DX + toolbutton_info[i].x,
3389 GDI_Y, DY + toolbutton_info[i].y,
3390 GDI_WIDTH, toolbutton_info[i].width,
3391 GDI_HEIGHT, toolbutton_info[i].height,
3392 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3393 GDI_STATE, GD_BUTTON_UNPRESSED,
3394 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3395 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3396 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3397 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3398 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3399 GDI_DECORATION_SHIFTING, 1, 1,
3400 GDI_DIRECT_DRAW, FALSE,
3401 GDI_EVENT_MASK, event_mask,
3402 GDI_CALLBACK_ACTION, HandleToolButtons,
3406 Error(ERR_EXIT, "cannot create gadget");
3408 tool_gadget[id] = gi;
3412 void FreeToolButtons()
3416 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3417 FreeGadget(tool_gadget[i]);
3420 static void UnmapToolButtons()
3424 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3425 UnmapGadget(tool_gadget[i]);
3428 static void HandleToolButtons(struct GadgetInfo *gi)
3430 request_gadget_id = gi->custom_id;
3433 static struct Mapping_EM_to_RND_object
3436 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3437 boolean is_backside; /* backside of moving element */
3443 em_object_mapping_list[] =
3446 Xblank, TRUE, FALSE,
3450 Yacid_splash_eB, FALSE, FALSE,
3451 EL_ACID_SPLASH_RIGHT, -1, -1
3454 Yacid_splash_wB, FALSE, FALSE,
3455 EL_ACID_SPLASH_LEFT, -1, -1
3458 #ifdef EM_ENGINE_BAD_ROLL
3460 Xstone_force_e, FALSE, FALSE,
3461 EL_ROCK, -1, MV_BIT_RIGHT
3464 Xstone_force_w, FALSE, FALSE,
3465 EL_ROCK, -1, MV_BIT_LEFT
3468 Xnut_force_e, FALSE, FALSE,
3469 EL_NUT, -1, MV_BIT_RIGHT
3472 Xnut_force_w, FALSE, FALSE,
3473 EL_NUT, -1, MV_BIT_LEFT
3476 Xspring_force_e, FALSE, FALSE,
3477 EL_SPRING, -1, MV_BIT_RIGHT
3480 Xspring_force_w, FALSE, FALSE,
3481 EL_SPRING, -1, MV_BIT_LEFT
3484 Xemerald_force_e, FALSE, FALSE,
3485 EL_EMERALD, -1, MV_BIT_RIGHT
3488 Xemerald_force_w, FALSE, FALSE,
3489 EL_EMERALD, -1, MV_BIT_LEFT
3492 Xdiamond_force_e, FALSE, FALSE,
3493 EL_DIAMOND, -1, MV_BIT_RIGHT
3496 Xdiamond_force_w, FALSE, FALSE,
3497 EL_DIAMOND, -1, MV_BIT_LEFT
3500 Xbomb_force_e, FALSE, FALSE,
3501 EL_BOMB, -1, MV_BIT_RIGHT
3504 Xbomb_force_w, FALSE, FALSE,
3505 EL_BOMB, -1, MV_BIT_LEFT
3507 #endif /* EM_ENGINE_BAD_ROLL */
3510 Xstone, TRUE, FALSE,
3514 Xstone_pause, FALSE, FALSE,
3518 Xstone_fall, FALSE, FALSE,
3522 Ystone_s, FALSE, FALSE,
3523 EL_ROCK, ACTION_FALLING, -1
3526 Ystone_sB, FALSE, TRUE,
3527 EL_ROCK, ACTION_FALLING, -1
3530 Ystone_e, FALSE, FALSE,
3531 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3534 Ystone_eB, FALSE, TRUE,
3535 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3538 Ystone_w, FALSE, FALSE,
3539 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3542 Ystone_wB, FALSE, TRUE,
3543 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3550 Xnut_pause, FALSE, FALSE,
3554 Xnut_fall, FALSE, FALSE,
3558 Ynut_s, FALSE, FALSE,
3559 EL_NUT, ACTION_FALLING, -1
3562 Ynut_sB, FALSE, TRUE,
3563 EL_NUT, ACTION_FALLING, -1
3566 Ynut_e, FALSE, FALSE,
3567 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3570 Ynut_eB, FALSE, TRUE,
3571 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3574 Ynut_w, FALSE, FALSE,
3575 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3578 Ynut_wB, FALSE, TRUE,
3579 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3582 Xbug_n, TRUE, FALSE,
3586 Xbug_e, TRUE, FALSE,
3587 EL_BUG_RIGHT, -1, -1
3590 Xbug_s, TRUE, FALSE,
3594 Xbug_w, TRUE, FALSE,
3598 Xbug_gon, FALSE, FALSE,
3602 Xbug_goe, FALSE, FALSE,
3603 EL_BUG_RIGHT, -1, -1
3606 Xbug_gos, FALSE, FALSE,
3610 Xbug_gow, FALSE, FALSE,
3614 Ybug_n, FALSE, FALSE,
3615 EL_BUG, ACTION_MOVING, MV_BIT_UP
3618 Ybug_nB, FALSE, TRUE,
3619 EL_BUG, ACTION_MOVING, MV_BIT_UP
3622 Ybug_e, FALSE, FALSE,
3623 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3626 Ybug_eB, FALSE, TRUE,
3627 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3630 Ybug_s, FALSE, FALSE,
3631 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3634 Ybug_sB, FALSE, TRUE,
3635 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3638 Ybug_w, FALSE, FALSE,
3639 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3642 Ybug_wB, FALSE, TRUE,
3643 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3646 Ybug_w_n, FALSE, FALSE,
3647 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3650 Ybug_n_e, FALSE, FALSE,
3651 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3654 Ybug_e_s, FALSE, FALSE,
3655 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3658 Ybug_s_w, FALSE, FALSE,
3659 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3662 Ybug_e_n, FALSE, FALSE,
3663 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3666 Ybug_s_e, FALSE, FALSE,
3667 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3670 Ybug_w_s, FALSE, FALSE,
3671 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3674 Ybug_n_w, FALSE, FALSE,
3675 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3678 Ybug_stone, FALSE, FALSE,
3679 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3682 Ybug_spring, FALSE, FALSE,
3683 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3686 Xtank_n, TRUE, FALSE,
3687 EL_SPACESHIP_UP, -1, -1
3690 Xtank_e, TRUE, FALSE,
3691 EL_SPACESHIP_RIGHT, -1, -1
3694 Xtank_s, TRUE, FALSE,
3695 EL_SPACESHIP_DOWN, -1, -1
3698 Xtank_w, TRUE, FALSE,
3699 EL_SPACESHIP_LEFT, -1, -1
3702 Xtank_gon, FALSE, FALSE,
3703 EL_SPACESHIP_UP, -1, -1
3706 Xtank_goe, FALSE, FALSE,
3707 EL_SPACESHIP_RIGHT, -1, -1
3710 Xtank_gos, FALSE, FALSE,
3711 EL_SPACESHIP_DOWN, -1, -1
3714 Xtank_gow, FALSE, FALSE,
3715 EL_SPACESHIP_LEFT, -1, -1
3718 Ytank_n, FALSE, FALSE,
3719 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3722 Ytank_nB, FALSE, TRUE,
3723 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3726 Ytank_e, FALSE, FALSE,
3727 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3730 Ytank_eB, FALSE, TRUE,
3731 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3734 Ytank_s, FALSE, FALSE,
3735 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3738 Ytank_sB, FALSE, TRUE,
3739 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3742 Ytank_w, FALSE, FALSE,
3743 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3746 Ytank_wB, FALSE, TRUE,
3747 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3750 Ytank_w_n, FALSE, FALSE,
3751 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3754 Ytank_n_e, FALSE, FALSE,
3755 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3758 Ytank_e_s, FALSE, FALSE,
3759 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3762 Ytank_s_w, FALSE, FALSE,
3763 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3766 Ytank_e_n, FALSE, FALSE,
3767 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3770 Ytank_s_e, FALSE, FALSE,
3771 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3774 Ytank_w_s, FALSE, FALSE,
3775 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3778 Ytank_n_w, FALSE, FALSE,
3779 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3782 Ytank_stone, FALSE, FALSE,
3783 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3786 Ytank_spring, FALSE, FALSE,
3787 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3790 Xandroid, TRUE, FALSE,
3791 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3794 Xandroid_1_n, FALSE, FALSE,
3795 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3798 Xandroid_2_n, FALSE, FALSE,
3799 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3802 Xandroid_1_e, FALSE, FALSE,
3803 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3806 Xandroid_2_e, FALSE, FALSE,
3807 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3810 Xandroid_1_w, FALSE, FALSE,
3811 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3814 Xandroid_2_w, FALSE, FALSE,
3815 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3818 Xandroid_1_s, FALSE, FALSE,
3819 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3822 Xandroid_2_s, FALSE, FALSE,
3823 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3826 Yandroid_n, FALSE, FALSE,
3827 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3830 Yandroid_nB, FALSE, TRUE,
3831 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3834 Yandroid_ne, FALSE, FALSE,
3835 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3838 Yandroid_neB, FALSE, TRUE,
3839 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3842 Yandroid_e, FALSE, FALSE,
3843 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3846 Yandroid_eB, FALSE, TRUE,
3847 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3850 Yandroid_se, FALSE, FALSE,
3851 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3854 Yandroid_seB, FALSE, TRUE,
3855 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3858 Yandroid_s, FALSE, FALSE,
3859 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3862 Yandroid_sB, FALSE, TRUE,
3863 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3866 Yandroid_sw, FALSE, FALSE,
3867 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3870 Yandroid_swB, FALSE, TRUE,
3871 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3874 Yandroid_w, FALSE, FALSE,
3875 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3878 Yandroid_wB, FALSE, TRUE,
3879 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3882 Yandroid_nw, FALSE, FALSE,
3883 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3886 Yandroid_nwB, FALSE, TRUE,
3887 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3890 Xspring, TRUE, FALSE,
3894 Xspring_pause, FALSE, FALSE,
3898 Xspring_e, FALSE, FALSE,
3902 Xspring_w, FALSE, FALSE,
3906 Xspring_fall, FALSE, FALSE,
3910 Yspring_s, FALSE, FALSE,
3911 EL_SPRING, ACTION_FALLING, -1
3914 Yspring_sB, FALSE, TRUE,
3915 EL_SPRING, ACTION_FALLING, -1
3918 Yspring_e, FALSE, FALSE,
3919 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3922 Yspring_eB, FALSE, TRUE,
3923 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3926 Yspring_w, FALSE, FALSE,
3927 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3930 Yspring_wB, FALSE, TRUE,
3931 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3934 Yspring_kill_e, FALSE, FALSE,
3935 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3938 Yspring_kill_eB, FALSE, TRUE,
3939 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3942 Yspring_kill_w, FALSE, FALSE,
3943 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3946 Yspring_kill_wB, FALSE, TRUE,
3947 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3950 Xeater_n, TRUE, FALSE,
3951 EL_YAMYAM_UP, -1, -1
3954 Xeater_e, TRUE, FALSE,
3955 EL_YAMYAM_RIGHT, -1, -1
3958 Xeater_w, TRUE, FALSE,
3959 EL_YAMYAM_LEFT, -1, -1
3962 Xeater_s, TRUE, FALSE,
3963 EL_YAMYAM_DOWN, -1, -1
3966 Yeater_n, FALSE, FALSE,
3967 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3970 Yeater_nB, FALSE, TRUE,
3971 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3974 Yeater_e, FALSE, FALSE,
3975 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3978 Yeater_eB, FALSE, TRUE,
3979 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3982 Yeater_s, FALSE, FALSE,
3983 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3986 Yeater_sB, FALSE, TRUE,
3987 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3990 Yeater_w, FALSE, FALSE,
3991 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3994 Yeater_wB, FALSE, TRUE,
3995 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3998 Yeater_stone, FALSE, FALSE,
3999 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4002 Yeater_spring, FALSE, FALSE,
4003 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4006 Xalien, TRUE, FALSE,
4010 Xalien_pause, FALSE, FALSE,
4014 Yalien_n, FALSE, FALSE,
4015 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4018 Yalien_nB, FALSE, TRUE,
4019 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4022 Yalien_e, FALSE, FALSE,
4023 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4026 Yalien_eB, FALSE, TRUE,
4027 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4030 Yalien_s, FALSE, FALSE,
4031 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4034 Yalien_sB, FALSE, TRUE,
4035 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4038 Yalien_w, FALSE, FALSE,
4039 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4042 Yalien_wB, FALSE, TRUE,
4043 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4046 Yalien_stone, FALSE, FALSE,
4047 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4050 Yalien_spring, FALSE, FALSE,
4051 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4054 Xemerald, TRUE, FALSE,
4058 Xemerald_pause, FALSE, FALSE,
4062 Xemerald_fall, FALSE, FALSE,
4066 Xemerald_shine, FALSE, FALSE,
4067 EL_EMERALD, ACTION_TWINKLING, -1
4070 Yemerald_s, FALSE, FALSE,
4071 EL_EMERALD, ACTION_FALLING, -1
4074 Yemerald_sB, FALSE, TRUE,
4075 EL_EMERALD, ACTION_FALLING, -1
4078 Yemerald_e, FALSE, FALSE,
4079 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4082 Yemerald_eB, FALSE, TRUE,
4083 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4086 Yemerald_w, FALSE, FALSE,
4087 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4090 Yemerald_wB, FALSE, TRUE,
4091 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4094 Yemerald_eat, FALSE, FALSE,
4095 EL_EMERALD, ACTION_COLLECTING, -1
4098 Yemerald_stone, FALSE, FALSE,
4099 EL_NUT, ACTION_BREAKING, -1
4102 Xdiamond, TRUE, FALSE,
4106 Xdiamond_pause, FALSE, FALSE,
4110 Xdiamond_fall, FALSE, FALSE,
4114 Xdiamond_shine, FALSE, FALSE,
4115 EL_DIAMOND, ACTION_TWINKLING, -1
4118 Ydiamond_s, FALSE, FALSE,
4119 EL_DIAMOND, ACTION_FALLING, -1
4122 Ydiamond_sB, FALSE, TRUE,
4123 EL_DIAMOND, ACTION_FALLING, -1
4126 Ydiamond_e, FALSE, FALSE,
4127 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4130 Ydiamond_eB, FALSE, TRUE,
4131 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4134 Ydiamond_w, FALSE, FALSE,
4135 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4138 Ydiamond_wB, FALSE, TRUE,
4139 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4142 Ydiamond_eat, FALSE, FALSE,
4143 EL_DIAMOND, ACTION_COLLECTING, -1
4146 Ydiamond_stone, FALSE, FALSE,
4147 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4150 Xdrip_fall, TRUE, FALSE,
4151 EL_AMOEBA_DROP, -1, -1
4154 Xdrip_stretch, FALSE, FALSE,
4155 EL_AMOEBA_DROP, ACTION_FALLING, -1
4158 Xdrip_stretchB, FALSE, TRUE,
4159 EL_AMOEBA_DROP, ACTION_FALLING, -1
4162 Xdrip_eat, FALSE, FALSE,
4163 EL_AMOEBA_DROP, ACTION_GROWING, -1
4166 Ydrip_s1, FALSE, FALSE,
4167 EL_AMOEBA_DROP, ACTION_FALLING, -1
4170 Ydrip_s1B, FALSE, TRUE,
4171 EL_AMOEBA_DROP, ACTION_FALLING, -1
4174 Ydrip_s2, FALSE, FALSE,
4175 EL_AMOEBA_DROP, ACTION_FALLING, -1
4178 Ydrip_s2B, FALSE, TRUE,
4179 EL_AMOEBA_DROP, ACTION_FALLING, -1
4186 Xbomb_pause, FALSE, FALSE,
4190 Xbomb_fall, FALSE, FALSE,
4194 Ybomb_s, FALSE, FALSE,
4195 EL_BOMB, ACTION_FALLING, -1
4198 Ybomb_sB, FALSE, TRUE,
4199 EL_BOMB, ACTION_FALLING, -1
4202 Ybomb_e, FALSE, FALSE,
4203 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4206 Ybomb_eB, FALSE, TRUE,
4207 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4210 Ybomb_w, FALSE, FALSE,
4211 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4214 Ybomb_wB, FALSE, TRUE,
4215 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4218 Ybomb_eat, FALSE, FALSE,
4219 EL_BOMB, ACTION_ACTIVATING, -1
4222 Xballoon, TRUE, FALSE,
4226 Yballoon_n, FALSE, FALSE,
4227 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4230 Yballoon_nB, FALSE, TRUE,
4231 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4234 Yballoon_e, FALSE, FALSE,
4235 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4238 Yballoon_eB, FALSE, TRUE,
4239 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4242 Yballoon_s, FALSE, FALSE,
4243 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4246 Yballoon_sB, FALSE, TRUE,
4247 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4250 Yballoon_w, FALSE, FALSE,
4251 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4254 Yballoon_wB, FALSE, TRUE,
4255 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4258 Xgrass, TRUE, FALSE,
4259 EL_EMC_GRASS, -1, -1
4262 Ygrass_nB, FALSE, FALSE,
4263 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4266 Ygrass_eB, FALSE, FALSE,
4267 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4270 Ygrass_sB, FALSE, FALSE,
4271 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4274 Ygrass_wB, FALSE, FALSE,
4275 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4282 Ydirt_nB, FALSE, FALSE,
4283 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4286 Ydirt_eB, FALSE, FALSE,
4287 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4290 Ydirt_sB, FALSE, FALSE,
4291 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4294 Ydirt_wB, FALSE, FALSE,
4295 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4298 Xacid_ne, TRUE, FALSE,
4299 EL_ACID_POOL_TOPRIGHT, -1, -1
4302 Xacid_se, TRUE, FALSE,
4303 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4306 Xacid_s, TRUE, FALSE,
4307 EL_ACID_POOL_BOTTOM, -1, -1
4310 Xacid_sw, TRUE, FALSE,
4311 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4314 Xacid_nw, TRUE, FALSE,
4315 EL_ACID_POOL_TOPLEFT, -1, -1
4318 Xacid_1, TRUE, FALSE,
4322 Xacid_2, FALSE, FALSE,
4326 Xacid_3, FALSE, FALSE,
4330 Xacid_4, FALSE, FALSE,
4334 Xacid_5, FALSE, FALSE,
4338 Xacid_6, FALSE, FALSE,
4342 Xacid_7, FALSE, FALSE,
4346 Xacid_8, FALSE, FALSE,
4350 Xball_1, TRUE, FALSE,
4351 EL_EMC_MAGIC_BALL, -1, -1
4354 Xball_1B, FALSE, FALSE,
4355 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4358 Xball_2, FALSE, FALSE,
4359 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4362 Xball_2B, FALSE, FALSE,
4363 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4366 Yball_eat, FALSE, FALSE,
4367 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4370 Ykey_1_eat, FALSE, FALSE,
4371 EL_EM_KEY_1, ACTION_COLLECTING, -1
4374 Ykey_2_eat, FALSE, FALSE,
4375 EL_EM_KEY_2, ACTION_COLLECTING, -1
4378 Ykey_3_eat, FALSE, FALSE,
4379 EL_EM_KEY_3, ACTION_COLLECTING, -1
4382 Ykey_4_eat, FALSE, FALSE,
4383 EL_EM_KEY_4, ACTION_COLLECTING, -1
4386 Ykey_5_eat, FALSE, FALSE,
4387 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4390 Ykey_6_eat, FALSE, FALSE,
4391 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4394 Ykey_7_eat, FALSE, FALSE,
4395 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4398 Ykey_8_eat, FALSE, FALSE,
4399 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4402 Ylenses_eat, FALSE, FALSE,
4403 EL_EMC_LENSES, ACTION_COLLECTING, -1
4406 Ymagnify_eat, FALSE, FALSE,
4407 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4410 Ygrass_eat, FALSE, FALSE,
4411 EL_EMC_GRASS, ACTION_SNAPPING, -1
4414 Ydirt_eat, FALSE, FALSE,
4415 EL_SAND, ACTION_SNAPPING, -1
4418 Xgrow_ns, TRUE, FALSE,
4419 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4422 Ygrow_ns_eat, FALSE, FALSE,
4423 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4426 Xgrow_ew, TRUE, FALSE,
4427 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4430 Ygrow_ew_eat, FALSE, FALSE,
4431 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4434 Xwonderwall, TRUE, FALSE,
4435 EL_MAGIC_WALL, -1, -1
4438 XwonderwallB, FALSE, FALSE,
4439 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4442 Xamoeba_1, TRUE, FALSE,
4443 EL_AMOEBA_DRY, ACTION_OTHER, -1
4446 Xamoeba_2, FALSE, FALSE,
4447 EL_AMOEBA_DRY, ACTION_OTHER, -1
4450 Xamoeba_3, FALSE, FALSE,
4451 EL_AMOEBA_DRY, ACTION_OTHER, -1
4454 Xamoeba_4, FALSE, FALSE,
4455 EL_AMOEBA_DRY, ACTION_OTHER, -1
4458 Xamoeba_5, TRUE, FALSE,
4459 EL_AMOEBA_WET, ACTION_OTHER, -1
4462 Xamoeba_6, FALSE, FALSE,
4463 EL_AMOEBA_WET, ACTION_OTHER, -1
4466 Xamoeba_7, FALSE, FALSE,
4467 EL_AMOEBA_WET, ACTION_OTHER, -1
4470 Xamoeba_8, FALSE, FALSE,
4471 EL_AMOEBA_WET, ACTION_OTHER, -1
4474 Xdoor_1, TRUE, FALSE,
4475 EL_EM_GATE_1, -1, -1
4478 Xdoor_2, TRUE, FALSE,
4479 EL_EM_GATE_2, -1, -1
4482 Xdoor_3, TRUE, FALSE,
4483 EL_EM_GATE_3, -1, -1
4486 Xdoor_4, TRUE, FALSE,
4487 EL_EM_GATE_4, -1, -1
4490 Xdoor_5, TRUE, FALSE,
4491 EL_EMC_GATE_5, -1, -1
4494 Xdoor_6, TRUE, FALSE,
4495 EL_EMC_GATE_6, -1, -1
4498 Xdoor_7, TRUE, FALSE,
4499 EL_EMC_GATE_7, -1, -1
4502 Xdoor_8, TRUE, FALSE,
4503 EL_EMC_GATE_8, -1, -1
4506 Xkey_1, TRUE, FALSE,
4510 Xkey_2, TRUE, FALSE,
4514 Xkey_3, TRUE, FALSE,
4518 Xkey_4, TRUE, FALSE,
4522 Xkey_5, TRUE, FALSE,
4523 EL_EMC_KEY_5, -1, -1
4526 Xkey_6, TRUE, FALSE,
4527 EL_EMC_KEY_6, -1, -1
4530 Xkey_7, TRUE, FALSE,
4531 EL_EMC_KEY_7, -1, -1
4534 Xkey_8, TRUE, FALSE,
4535 EL_EMC_KEY_8, -1, -1
4538 Xwind_n, TRUE, FALSE,
4539 EL_BALLOON_SWITCH_UP, -1, -1
4542 Xwind_e, TRUE, FALSE,
4543 EL_BALLOON_SWITCH_RIGHT, -1, -1
4546 Xwind_s, TRUE, FALSE,
4547 EL_BALLOON_SWITCH_DOWN, -1, -1
4550 Xwind_w, TRUE, FALSE,
4551 EL_BALLOON_SWITCH_LEFT, -1, -1
4554 Xwind_nesw, TRUE, FALSE,
4555 EL_BALLOON_SWITCH_ANY, -1, -1
4558 Xwind_stop, TRUE, FALSE,
4559 EL_BALLOON_SWITCH_NONE, -1, -1
4563 EL_EM_EXIT_CLOSED, -1, -1
4566 Xexit_1, TRUE, FALSE,
4567 EL_EM_EXIT_OPEN, -1, -1
4570 Xexit_2, FALSE, FALSE,
4571 EL_EM_EXIT_OPEN, -1, -1
4574 Xexit_3, FALSE, FALSE,
4575 EL_EM_EXIT_OPEN, -1, -1
4578 Xdynamite, TRUE, FALSE,
4579 EL_EM_DYNAMITE, -1, -1
4582 Ydynamite_eat, FALSE, FALSE,
4583 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4586 Xdynamite_1, TRUE, FALSE,
4587 EL_EM_DYNAMITE_ACTIVE, -1, -1
4590 Xdynamite_2, FALSE, FALSE,
4591 EL_EM_DYNAMITE_ACTIVE, -1, -1
4594 Xdynamite_3, FALSE, FALSE,
4595 EL_EM_DYNAMITE_ACTIVE, -1, -1
4598 Xdynamite_4, FALSE, FALSE,
4599 EL_EM_DYNAMITE_ACTIVE, -1, -1
4602 Xbumper, TRUE, FALSE,
4603 EL_EMC_SPRING_BUMPER, -1, -1
4606 XbumperB, FALSE, FALSE,
4607 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4610 Xwheel, TRUE, FALSE,
4611 EL_ROBOT_WHEEL, -1, -1
4614 XwheelB, FALSE, FALSE,
4615 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4618 Xswitch, TRUE, FALSE,
4619 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4622 XswitchB, FALSE, FALSE,
4623 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4627 EL_QUICKSAND_EMPTY, -1, -1
4630 Xsand_stone, TRUE, FALSE,
4631 EL_QUICKSAND_FULL, -1, -1
4634 Xsand_stonein_1, FALSE, TRUE,
4635 EL_ROCK, ACTION_FILLING, -1
4638 Xsand_stonein_2, FALSE, TRUE,
4639 EL_ROCK, ACTION_FILLING, -1
4642 Xsand_stonein_3, FALSE, TRUE,
4643 EL_ROCK, ACTION_FILLING, -1
4646 Xsand_stonein_4, FALSE, TRUE,
4647 EL_ROCK, ACTION_FILLING, -1
4650 Xsand_stonesand_1, FALSE, FALSE,
4651 EL_QUICKSAND_FULL, -1, -1
4654 Xsand_stonesand_2, FALSE, FALSE,
4655 EL_QUICKSAND_FULL, -1, -1
4658 Xsand_stonesand_3, FALSE, FALSE,
4659 EL_QUICKSAND_FULL, -1, -1
4662 Xsand_stonesand_4, FALSE, FALSE,
4663 EL_QUICKSAND_FULL, -1, -1
4666 Xsand_stoneout_1, FALSE, FALSE,
4667 EL_ROCK, ACTION_EMPTYING, -1
4670 Xsand_stoneout_2, FALSE, FALSE,
4671 EL_ROCK, ACTION_EMPTYING, -1
4674 Xsand_sandstone_1, FALSE, FALSE,
4675 EL_QUICKSAND_FULL, -1, -1
4678 Xsand_sandstone_2, FALSE, FALSE,
4679 EL_QUICKSAND_FULL, -1, -1
4682 Xsand_sandstone_3, FALSE, FALSE,
4683 EL_QUICKSAND_FULL, -1, -1
4686 Xsand_sandstone_4, FALSE, FALSE,
4687 EL_QUICKSAND_FULL, -1, -1
4690 Xplant, TRUE, FALSE,
4691 EL_EMC_PLANT, -1, -1
4694 Yplant, FALSE, FALSE,
4695 EL_EMC_PLANT, -1, -1
4698 Xlenses, TRUE, FALSE,
4699 EL_EMC_LENSES, -1, -1
4702 Xmagnify, TRUE, FALSE,
4703 EL_EMC_MAGNIFIER, -1, -1
4706 Xdripper, TRUE, FALSE,
4707 EL_EMC_DRIPPER, -1, -1
4710 XdripperB, FALSE, FALSE,
4711 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4714 Xfake_blank, TRUE, FALSE,
4715 EL_INVISIBLE_WALL, -1, -1
4718 Xfake_blankB, FALSE, FALSE,
4719 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4722 Xfake_grass, TRUE, FALSE,
4723 EL_EMC_FAKE_GRASS, -1, -1
4726 Xfake_grassB, FALSE, FALSE,
4727 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4730 Xfake_door_1, TRUE, FALSE,
4731 EL_EM_GATE_1_GRAY, -1, -1
4734 Xfake_door_2, TRUE, FALSE,
4735 EL_EM_GATE_2_GRAY, -1, -1
4738 Xfake_door_3, TRUE, FALSE,
4739 EL_EM_GATE_3_GRAY, -1, -1
4742 Xfake_door_4, TRUE, FALSE,
4743 EL_EM_GATE_4_GRAY, -1, -1
4746 Xfake_door_5, TRUE, FALSE,
4747 EL_EMC_GATE_5_GRAY, -1, -1
4750 Xfake_door_6, TRUE, FALSE,
4751 EL_EMC_GATE_6_GRAY, -1, -1
4754 Xfake_door_7, TRUE, FALSE,
4755 EL_EMC_GATE_7_GRAY, -1, -1
4758 Xfake_door_8, TRUE, FALSE,
4759 EL_EMC_GATE_8_GRAY, -1, -1
4762 Xfake_acid_1, TRUE, FALSE,
4763 EL_EMC_FAKE_ACID, -1, -1
4766 Xfake_acid_2, FALSE, FALSE,
4767 EL_EMC_FAKE_ACID, -1, -1
4770 Xfake_acid_3, FALSE, FALSE,
4771 EL_EMC_FAKE_ACID, -1, -1
4774 Xfake_acid_4, FALSE, FALSE,
4775 EL_EMC_FAKE_ACID, -1, -1
4778 Xfake_acid_5, FALSE, FALSE,
4779 EL_EMC_FAKE_ACID, -1, -1
4782 Xfake_acid_6, FALSE, FALSE,
4783 EL_EMC_FAKE_ACID, -1, -1
4786 Xfake_acid_7, FALSE, FALSE,
4787 EL_EMC_FAKE_ACID, -1, -1
4790 Xfake_acid_8, FALSE, FALSE,
4791 EL_EMC_FAKE_ACID, -1, -1
4794 Xsteel_1, TRUE, FALSE,
4795 EL_STEELWALL, -1, -1
4798 Xsteel_2, TRUE, FALSE,
4799 EL_EMC_STEELWALL_2, -1, -1
4802 Xsteel_3, TRUE, FALSE,
4803 EL_EMC_STEELWALL_3, -1, -1
4806 Xsteel_4, TRUE, FALSE,
4807 EL_EMC_STEELWALL_4, -1, -1
4810 Xwall_1, TRUE, FALSE,
4814 Xwall_2, TRUE, FALSE,
4815 EL_EMC_WALL_14, -1, -1
4818 Xwall_3, TRUE, FALSE,
4819 EL_EMC_WALL_15, -1, -1
4822 Xwall_4, TRUE, FALSE,
4823 EL_EMC_WALL_16, -1, -1
4826 Xround_wall_1, TRUE, FALSE,
4827 EL_WALL_SLIPPERY, -1, -1
4830 Xround_wall_2, TRUE, FALSE,
4831 EL_EMC_WALL_SLIPPERY_2, -1, -1
4834 Xround_wall_3, TRUE, FALSE,
4835 EL_EMC_WALL_SLIPPERY_3, -1, -1
4838 Xround_wall_4, TRUE, FALSE,
4839 EL_EMC_WALL_SLIPPERY_4, -1, -1
4842 Xdecor_1, TRUE, FALSE,
4843 EL_EMC_WALL_8, -1, -1
4846 Xdecor_2, TRUE, FALSE,
4847 EL_EMC_WALL_6, -1, -1
4850 Xdecor_3, TRUE, FALSE,
4851 EL_EMC_WALL_4, -1, -1
4854 Xdecor_4, TRUE, FALSE,
4855 EL_EMC_WALL_7, -1, -1
4858 Xdecor_5, TRUE, FALSE,
4859 EL_EMC_WALL_5, -1, -1
4862 Xdecor_6, TRUE, FALSE,
4863 EL_EMC_WALL_9, -1, -1
4866 Xdecor_7, TRUE, FALSE,
4867 EL_EMC_WALL_10, -1, -1
4870 Xdecor_8, TRUE, FALSE,
4871 EL_EMC_WALL_1, -1, -1
4874 Xdecor_9, TRUE, FALSE,
4875 EL_EMC_WALL_2, -1, -1
4878 Xdecor_10, TRUE, FALSE,
4879 EL_EMC_WALL_3, -1, -1
4882 Xdecor_11, TRUE, FALSE,
4883 EL_EMC_WALL_11, -1, -1
4886 Xdecor_12, TRUE, FALSE,
4887 EL_EMC_WALL_12, -1, -1
4890 Xalpha_0, TRUE, FALSE,
4891 EL_CHAR('0'), -1, -1
4894 Xalpha_1, TRUE, FALSE,
4895 EL_CHAR('1'), -1, -1
4898 Xalpha_2, TRUE, FALSE,
4899 EL_CHAR('2'), -1, -1
4902 Xalpha_3, TRUE, FALSE,
4903 EL_CHAR('3'), -1, -1
4906 Xalpha_4, TRUE, FALSE,
4907 EL_CHAR('4'), -1, -1
4910 Xalpha_5, TRUE, FALSE,
4911 EL_CHAR('5'), -1, -1
4914 Xalpha_6, TRUE, FALSE,
4915 EL_CHAR('6'), -1, -1
4918 Xalpha_7, TRUE, FALSE,
4919 EL_CHAR('7'), -1, -1
4922 Xalpha_8, TRUE, FALSE,
4923 EL_CHAR('8'), -1, -1
4926 Xalpha_9, TRUE, FALSE,
4927 EL_CHAR('9'), -1, -1
4930 Xalpha_excla, TRUE, FALSE,
4931 EL_CHAR('!'), -1, -1
4934 Xalpha_quote, TRUE, FALSE,
4935 EL_CHAR('"'), -1, -1
4938 Xalpha_comma, TRUE, FALSE,
4939 EL_CHAR(','), -1, -1
4942 Xalpha_minus, TRUE, FALSE,
4943 EL_CHAR('-'), -1, -1
4946 Xalpha_perio, TRUE, FALSE,
4947 EL_CHAR('.'), -1, -1
4950 Xalpha_colon, TRUE, FALSE,
4951 EL_CHAR(':'), -1, -1
4954 Xalpha_quest, TRUE, FALSE,
4955 EL_CHAR('?'), -1, -1
4958 Xalpha_a, TRUE, FALSE,
4959 EL_CHAR('A'), -1, -1
4962 Xalpha_b, TRUE, FALSE,
4963 EL_CHAR('B'), -1, -1
4966 Xalpha_c, TRUE, FALSE,
4967 EL_CHAR('C'), -1, -1
4970 Xalpha_d, TRUE, FALSE,
4971 EL_CHAR('D'), -1, -1
4974 Xalpha_e, TRUE, FALSE,
4975 EL_CHAR('E'), -1, -1
4978 Xalpha_f, TRUE, FALSE,
4979 EL_CHAR('F'), -1, -1
4982 Xalpha_g, TRUE, FALSE,
4983 EL_CHAR('G'), -1, -1
4986 Xalpha_h, TRUE, FALSE,
4987 EL_CHAR('H'), -1, -1
4990 Xalpha_i, TRUE, FALSE,
4991 EL_CHAR('I'), -1, -1
4994 Xalpha_j, TRUE, FALSE,
4995 EL_CHAR('J'), -1, -1
4998 Xalpha_k, TRUE, FALSE,
4999 EL_CHAR('K'), -1, -1
5002 Xalpha_l, TRUE, FALSE,
5003 EL_CHAR('L'), -1, -1
5006 Xalpha_m, TRUE, FALSE,
5007 EL_CHAR('M'), -1, -1
5010 Xalpha_n, TRUE, FALSE,
5011 EL_CHAR('N'), -1, -1
5014 Xalpha_o, TRUE, FALSE,
5015 EL_CHAR('O'), -1, -1
5018 Xalpha_p, TRUE, FALSE,
5019 EL_CHAR('P'), -1, -1
5022 Xalpha_q, TRUE, FALSE,
5023 EL_CHAR('Q'), -1, -1
5026 Xalpha_r, TRUE, FALSE,
5027 EL_CHAR('R'), -1, -1
5030 Xalpha_s, TRUE, FALSE,
5031 EL_CHAR('S'), -1, -1
5034 Xalpha_t, TRUE, FALSE,
5035 EL_CHAR('T'), -1, -1
5038 Xalpha_u, TRUE, FALSE,
5039 EL_CHAR('U'), -1, -1
5042 Xalpha_v, TRUE, FALSE,
5043 EL_CHAR('V'), -1, -1
5046 Xalpha_w, TRUE, FALSE,
5047 EL_CHAR('W'), -1, -1
5050 Xalpha_x, TRUE, FALSE,
5051 EL_CHAR('X'), -1, -1
5054 Xalpha_y, TRUE, FALSE,
5055 EL_CHAR('Y'), -1, -1
5058 Xalpha_z, TRUE, FALSE,
5059 EL_CHAR('Z'), -1, -1
5062 Xalpha_arrow_e, TRUE, FALSE,
5063 EL_CHAR('>'), -1, -1
5066 Xalpha_arrow_w, TRUE, FALSE,
5067 EL_CHAR('<'), -1, -1
5070 Xalpha_copyr, TRUE, FALSE,
5071 EL_CHAR('©'), -1, -1
5075 Xboom_bug, FALSE, FALSE,
5076 EL_BUG, ACTION_EXPLODING, -1
5079 Xboom_bomb, FALSE, FALSE,
5080 EL_BOMB, ACTION_EXPLODING, -1
5083 Xboom_android, FALSE, FALSE,
5084 EL_EMC_ANDROID, ACTION_OTHER, -1
5087 Xboom_1, FALSE, FALSE,
5088 EL_DEFAULT, ACTION_EXPLODING, -1
5091 Xboom_2, FALSE, FALSE,
5092 EL_DEFAULT, ACTION_EXPLODING, -1
5095 Znormal, FALSE, FALSE,
5099 Zdynamite, FALSE, FALSE,
5103 Zplayer, FALSE, FALSE,
5107 ZBORDER, FALSE, FALSE,
5117 static struct Mapping_EM_to_RND_player
5126 em_player_mapping_list[] =
5130 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5134 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5138 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5142 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5146 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5150 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5154 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5158 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5162 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5166 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5170 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5174 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5178 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5182 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5186 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5190 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5194 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5198 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5202 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5206 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5210 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5214 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5218 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5222 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5226 EL_PLAYER_1, ACTION_DEFAULT, -1,
5230 EL_PLAYER_2, ACTION_DEFAULT, -1,
5234 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5238 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5242 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5246 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5250 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5254 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5258 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5262 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5266 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5270 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5274 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5278 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5282 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5286 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5290 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5294 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5298 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5302 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5306 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5310 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5314 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5318 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5322 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5326 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5330 EL_PLAYER_3, ACTION_DEFAULT, -1,
5334 EL_PLAYER_4, ACTION_DEFAULT, -1,
5343 int map_element_RND_to_EM(int element_rnd)
5345 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5346 static boolean mapping_initialized = FALSE;
5348 if (!mapping_initialized)
5352 /* return "Xalpha_quest" for all undefined elements in mapping array */
5353 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5354 mapping_RND_to_EM[i] = Xalpha_quest;
5356 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5357 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5358 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5359 em_object_mapping_list[i].element_em;
5361 mapping_initialized = TRUE;
5364 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5365 return mapping_RND_to_EM[element_rnd];
5367 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5372 int map_element_EM_to_RND(int element_em)
5374 static unsigned short mapping_EM_to_RND[TILE_MAX];
5375 static boolean mapping_initialized = FALSE;
5377 if (!mapping_initialized)
5381 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5382 for (i = 0; i < TILE_MAX; i++)
5383 mapping_EM_to_RND[i] = EL_UNKNOWN;
5385 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5386 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5387 em_object_mapping_list[i].element_rnd;
5389 mapping_initialized = TRUE;
5392 if (element_em >= 0 && element_em < TILE_MAX)
5393 return mapping_EM_to_RND[element_em];
5395 Error(ERR_WARN, "invalid EM level element %d", element_em);
5400 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5402 struct LevelInfo_EM *level_em = level->native_em_level;
5403 struct LEVEL *lev = level_em->lev;
5406 for (i = 0; i < TILE_MAX; i++)
5407 lev->android_array[i] = Xblank;
5409 for (i = 0; i < level->num_android_clone_elements; i++)
5411 int element_rnd = level->android_clone_element[i];
5412 int element_em = map_element_RND_to_EM(element_rnd);
5414 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5415 if (em_object_mapping_list[j].element_rnd == element_rnd)
5416 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5420 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5422 struct LevelInfo_EM *level_em = level->native_em_level;
5423 struct LEVEL *lev = level_em->lev;
5426 level->num_android_clone_elements = 0;
5428 for (i = 0; i < TILE_MAX; i++)
5430 int element_em = lev->android_array[i];
5432 boolean element_found = FALSE;
5434 if (element_em == Xblank)
5437 element_rnd = map_element_EM_to_RND(element_em);
5439 for (j = 0; j < level->num_android_clone_elements; j++)
5440 if (level->android_clone_element[j] == element_rnd)
5441 element_found = TRUE;
5445 level->android_clone_element[level->num_android_clone_elements++] =
5448 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5453 if (level->num_android_clone_elements == 0)
5455 level->num_android_clone_elements = 1;
5456 level->android_clone_element[0] = EL_EMPTY;
5460 int map_direction_RND_to_EM(int direction)
5462 return (direction == MV_UP ? 0 :
5463 direction == MV_RIGHT ? 1 :
5464 direction == MV_DOWN ? 2 :
5465 direction == MV_LEFT ? 3 :
5469 int map_direction_EM_to_RND(int direction)
5471 return (direction == 0 ? MV_UP :
5472 direction == 1 ? MV_RIGHT :
5473 direction == 2 ? MV_DOWN :
5474 direction == 3 ? MV_LEFT :
5478 int get_next_element(int element)
5482 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5483 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5484 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5485 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5486 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5487 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5488 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5489 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5490 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5491 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5492 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5494 default: return element;
5499 int el_act_dir2img(int element, int action, int direction)
5501 element = GFX_ELEMENT(element);
5503 if (direction == MV_NONE)
5504 return element_info[element].graphic[action];
5506 direction = MV_DIR_TO_BIT(direction);
5508 return element_info[element].direction_graphic[action][direction];
5511 int el_act_dir2img(int element, int action, int direction)
5513 element = GFX_ELEMENT(element);
5514 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5516 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5517 return element_info[element].direction_graphic[action][direction];
5522 static int el_act_dir2crm(int element, int action, int direction)
5524 element = GFX_ELEMENT(element);
5526 if (direction == MV_NONE)
5527 return element_info[element].crumbled[action];
5529 direction = MV_DIR_TO_BIT(direction);
5531 return element_info[element].direction_crumbled[action][direction];
5534 static int el_act_dir2crm(int element, int action, int direction)
5536 element = GFX_ELEMENT(element);
5537 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5539 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5540 return element_info[element].direction_crumbled[action][direction];
5544 int el_act2img(int element, int action)
5546 element = GFX_ELEMENT(element);
5548 return element_info[element].graphic[action];
5551 int el_act2crm(int element, int action)
5553 element = GFX_ELEMENT(element);
5555 return element_info[element].crumbled[action];
5558 int el_dir2img(int element, int direction)
5560 element = GFX_ELEMENT(element);
5562 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5565 int el2baseimg(int element)
5567 return element_info[element].graphic[ACTION_DEFAULT];
5570 int el2img(int element)
5572 element = GFX_ELEMENT(element);
5574 return element_info[element].graphic[ACTION_DEFAULT];
5577 int el2edimg(int element)
5579 element = GFX_ELEMENT(element);
5581 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5584 int el2preimg(int element)
5586 element = GFX_ELEMENT(element);
5588 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5591 int font2baseimg(int font_nr)
5593 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5596 int getBeltNrFromBeltElement(int element)
5598 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5599 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5600 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5603 int getBeltNrFromBeltActiveElement(int element)
5605 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5606 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5607 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5610 int getBeltNrFromBeltSwitchElement(int element)
5612 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5613 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5614 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5617 int getBeltDirNrFromBeltElement(int element)
5619 static int belt_base_element[4] =
5621 EL_CONVEYOR_BELT_1_LEFT,
5622 EL_CONVEYOR_BELT_2_LEFT,
5623 EL_CONVEYOR_BELT_3_LEFT,
5624 EL_CONVEYOR_BELT_4_LEFT
5627 int belt_nr = getBeltNrFromBeltElement(element);
5628 int belt_dir_nr = element - belt_base_element[belt_nr];
5630 return (belt_dir_nr % 3);
5633 int getBeltDirNrFromBeltSwitchElement(int element)
5635 static int belt_base_element[4] =
5637 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5638 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5639 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5640 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5643 int belt_nr = getBeltNrFromBeltSwitchElement(element);
5644 int belt_dir_nr = element - belt_base_element[belt_nr];
5646 return (belt_dir_nr % 3);
5649 int getBeltDirFromBeltElement(int element)
5651 static int belt_move_dir[3] =
5658 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5660 return belt_move_dir[belt_dir_nr];
5663 int getBeltDirFromBeltSwitchElement(int element)
5665 static int belt_move_dir[3] =
5672 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5674 return belt_move_dir[belt_dir_nr];
5677 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5679 static int belt_base_element[4] =
5681 EL_CONVEYOR_BELT_1_LEFT,
5682 EL_CONVEYOR_BELT_2_LEFT,
5683 EL_CONVEYOR_BELT_3_LEFT,
5684 EL_CONVEYOR_BELT_4_LEFT
5686 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5688 return belt_base_element[belt_nr] + belt_dir_nr;
5691 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5693 static int belt_base_element[4] =
5695 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5696 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5697 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5698 EL_CONVEYOR_BELT_4_SWITCH_LEFT
5700 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5702 return belt_base_element[belt_nr] + belt_dir_nr;
5705 int getNumActivePlayers_EM()
5707 int num_players = 0;
5713 for (i = 0; i < MAX_PLAYERS; i++)
5714 if (tape.player_participates[i])
5720 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5722 int game_frame_delay_value;
5724 game_frame_delay_value =
5725 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5726 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5729 if (tape.playing && tape.warp_forward && !tape.pausing)
5730 game_frame_delay_value = 0;
5732 return game_frame_delay_value;
5735 unsigned int InitRND(long seed)
5737 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5738 return InitEngineRandom_EM(seed);
5740 return InitEngineRandom_RND(seed);
5744 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5745 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5748 void ResetGfxAnimation_EM(int x, int y, int tile)
5753 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5754 Bitmap **src_bitmap, int *src_x, int *src_y,
5757 int element = object_mapping[tile].element_rnd;
5758 int action = object_mapping[tile].action;
5759 int direction = object_mapping[tile].direction;
5760 boolean is_backside = object_mapping[tile].is_backside;
5761 boolean action_removing = (action == ACTION_DIGGING ||
5762 action == ACTION_SNAPPING ||
5763 action == ACTION_COLLECTING);
5764 int effective_element = (frame_em > 0 ? element :
5765 is_backside ? EL_EMPTY :
5766 action_removing ? EL_EMPTY :
5768 int graphic = (direction == MV_NONE ?
5769 el_act2img(effective_element, action) :
5770 el_act_dir2img(effective_element, action, direction));
5771 struct GraphicInfo *g = &graphic_info[graphic];
5774 if (graphic_info[graphic].anim_global_sync)
5775 sync_frame = FrameCounter;
5777 sync_frame = 7 - frame_em;
5779 SetRandomAnimationValue(x, y);
5781 int frame = getAnimationFrame(g->anim_frames,
5784 g->anim_start_frame,
5787 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5790 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
5791 Bitmap **src_bitmap, int *src_x, int *src_y)
5793 int element = player_mapping[player_nr][anim].element_rnd;
5794 int action = player_mapping[player_nr][anim].action;
5795 int direction = player_mapping[player_nr][anim].direction;
5796 int graphic = (direction == MV_NONE ?
5797 el_act2img(element, action) :
5798 el_act_dir2img(element, action, direction));
5799 struct GraphicInfo *g = &graphic_info[graphic];
5802 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
5804 stored_player[player_nr].StepFrame = 7 - frame_em;
5806 sync_frame = stored_player[player_nr].Frame;
5809 printf("::: %d: %d, %d [%d]\n",
5811 stored_player[player_nr].Frame,
5812 stored_player[player_nr].StepFrame,
5816 int frame = getAnimationFrame(g->anim_frames,
5819 g->anim_start_frame,
5822 getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5825 void InitGraphicInfo_EM(void)
5828 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5829 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5834 int num_em_gfx_errors = 0;
5836 if (graphic_info_em_object[0][0].bitmap == NULL)
5838 /* EM graphics not yet initialized in em_open_all() */
5843 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5846 /* always start with reliable default values */
5847 for (i = 0; i < TILE_MAX; i++)
5849 object_mapping[i].element_rnd = EL_UNKNOWN;
5850 object_mapping[i].is_backside = FALSE;
5851 object_mapping[i].action = ACTION_DEFAULT;
5852 object_mapping[i].direction = MV_NONE;
5855 /* always start with reliable default values */
5856 for (p = 0; p < MAX_PLAYERS; p++)
5858 for (i = 0; i < SPR_MAX; i++)
5860 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5861 player_mapping[p][i].action = ACTION_DEFAULT;
5862 player_mapping[p][i].direction = MV_NONE;
5866 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5868 int e = em_object_mapping_list[i].element_em;
5870 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5871 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5873 if (em_object_mapping_list[i].action != -1)
5874 object_mapping[e].action = em_object_mapping_list[i].action;
5876 if (em_object_mapping_list[i].direction != -1)
5877 object_mapping[e].direction =
5878 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5881 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5883 int a = em_player_mapping_list[i].action_em;
5884 int p = em_player_mapping_list[i].player_nr;
5886 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5888 if (em_player_mapping_list[i].action != -1)
5889 player_mapping[p][a].action = em_player_mapping_list[i].action;
5891 if (em_player_mapping_list[i].direction != -1)
5892 player_mapping[p][a].direction =
5893 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5896 for (i = 0; i < TILE_MAX; i++)
5898 int element = object_mapping[i].element_rnd;
5899 int action = object_mapping[i].action;
5900 int direction = object_mapping[i].direction;
5901 boolean is_backside = object_mapping[i].is_backside;
5902 boolean action_removing = (action == ACTION_DIGGING ||
5903 action == ACTION_SNAPPING ||
5904 action == ACTION_COLLECTING);
5905 boolean action_exploding = ((action == ACTION_EXPLODING ||
5906 action == ACTION_SMASHED_BY_ROCK ||
5907 action == ACTION_SMASHED_BY_SPRING) &&
5908 element != EL_DIAMOND);
5909 boolean action_active = (action == ACTION_ACTIVE);
5910 boolean action_other = (action == ACTION_OTHER);
5912 for (j = 0; j < 8; j++)
5914 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5915 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5917 i == Xdrip_stretch ? element :
5918 i == Xdrip_stretchB ? element :
5919 i == Ydrip_s1 ? element :
5920 i == Ydrip_s1B ? element :
5921 i == Xball_1B ? element :
5922 i == Xball_2 ? element :
5923 i == Xball_2B ? element :
5924 i == Yball_eat ? element :
5925 i == Ykey_1_eat ? element :
5926 i == Ykey_2_eat ? element :
5927 i == Ykey_3_eat ? element :
5928 i == Ykey_4_eat ? element :
5929 i == Ykey_5_eat ? element :
5930 i == Ykey_6_eat ? element :
5931 i == Ykey_7_eat ? element :
5932 i == Ykey_8_eat ? element :
5933 i == Ylenses_eat ? element :
5934 i == Ymagnify_eat ? element :
5935 i == Ygrass_eat ? element :
5936 i == Ydirt_eat ? element :
5937 i == Yemerald_stone ? EL_EMERALD :
5938 i == Ydiamond_stone ? EL_ROCK :
5939 i == Xsand_stonein_1 ? element :
5940 i == Xsand_stonein_2 ? element :
5941 i == Xsand_stonein_3 ? element :
5942 i == Xsand_stonein_4 ? element :
5943 is_backside ? EL_EMPTY :
5944 action_removing ? EL_EMPTY :
5946 int effective_action = (j < 7 ? action :
5947 i == Xdrip_stretch ? action :
5948 i == Xdrip_stretchB ? action :
5949 i == Ydrip_s1 ? action :
5950 i == Ydrip_s1B ? action :
5951 i == Xball_1B ? action :
5952 i == Xball_2 ? action :
5953 i == Xball_2B ? action :
5954 i == Yball_eat ? action :
5955 i == Ykey_1_eat ? action :
5956 i == Ykey_2_eat ? action :
5957 i == Ykey_3_eat ? action :
5958 i == Ykey_4_eat ? action :
5959 i == Ykey_5_eat ? action :
5960 i == Ykey_6_eat ? action :
5961 i == Ykey_7_eat ? action :
5962 i == Ykey_8_eat ? action :
5963 i == Ylenses_eat ? action :
5964 i == Ymagnify_eat ? action :
5965 i == Ygrass_eat ? action :
5966 i == Ydirt_eat ? action :
5967 i == Xsand_stonein_1 ? action :
5968 i == Xsand_stonein_2 ? action :
5969 i == Xsand_stonein_3 ? action :
5970 i == Xsand_stonein_4 ? action :
5971 i == Xsand_stoneout_1 ? action :
5972 i == Xsand_stoneout_2 ? action :
5973 i == Xboom_android ? ACTION_EXPLODING :
5974 action_exploding ? ACTION_EXPLODING :
5975 action_active ? action :
5976 action_other ? action :
5978 int graphic = (el_act_dir2img(effective_element, effective_action,
5980 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5982 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5983 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5984 boolean has_action_graphics = (graphic != base_graphic);
5985 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5986 struct GraphicInfo *g = &graphic_info[graphic];
5987 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5990 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5991 boolean special_animation = (action != ACTION_DEFAULT &&
5992 g->anim_frames == 3 &&
5993 g->anim_delay == 2 &&
5994 g->anim_mode & ANIM_LINEAR);
5995 int sync_frame = (i == Xdrip_stretch ? 7 :
5996 i == Xdrip_stretchB ? 7 :
5997 i == Ydrip_s2 ? j + 8 :
5998 i == Ydrip_s2B ? j + 8 :
6007 i == Xfake_acid_1 ? 0 :
6008 i == Xfake_acid_2 ? 10 :
6009 i == Xfake_acid_3 ? 20 :
6010 i == Xfake_acid_4 ? 30 :
6011 i == Xfake_acid_5 ? 40 :
6012 i == Xfake_acid_6 ? 50 :
6013 i == Xfake_acid_7 ? 60 :
6014 i == Xfake_acid_8 ? 70 :
6016 i == Xball_2B ? j + 8 :
6017 i == Yball_eat ? j + 1 :
6018 i == Ykey_1_eat ? j + 1 :
6019 i == Ykey_2_eat ? j + 1 :
6020 i == Ykey_3_eat ? j + 1 :
6021 i == Ykey_4_eat ? j + 1 :
6022 i == Ykey_5_eat ? j + 1 :
6023 i == Ykey_6_eat ? j + 1 :
6024 i == Ykey_7_eat ? j + 1 :
6025 i == Ykey_8_eat ? j + 1 :
6026 i == Ylenses_eat ? j + 1 :
6027 i == Ymagnify_eat ? j + 1 :
6028 i == Ygrass_eat ? j + 1 :
6029 i == Ydirt_eat ? j + 1 :
6030 i == Xamoeba_1 ? 0 :
6031 i == Xamoeba_2 ? 1 :
6032 i == Xamoeba_3 ? 2 :
6033 i == Xamoeba_4 ? 3 :
6034 i == Xamoeba_5 ? 0 :
6035 i == Xamoeba_6 ? 1 :
6036 i == Xamoeba_7 ? 2 :
6037 i == Xamoeba_8 ? 3 :
6038 i == Xexit_2 ? j + 8 :
6039 i == Xexit_3 ? j + 16 :
6040 i == Xdynamite_1 ? 0 :
6041 i == Xdynamite_2 ? 8 :
6042 i == Xdynamite_3 ? 16 :
6043 i == Xdynamite_4 ? 24 :
6044 i == Xsand_stonein_1 ? j + 1 :
6045 i == Xsand_stonein_2 ? j + 9 :
6046 i == Xsand_stonein_3 ? j + 17 :
6047 i == Xsand_stonein_4 ? j + 25 :
6048 i == Xsand_stoneout_1 && j == 0 ? 0 :
6049 i == Xsand_stoneout_1 && j == 1 ? 0 :
6050 i == Xsand_stoneout_1 && j == 2 ? 1 :
6051 i == Xsand_stoneout_1 && j == 3 ? 2 :
6052 i == Xsand_stoneout_1 && j == 4 ? 2 :
6053 i == Xsand_stoneout_1 && j == 5 ? 3 :
6054 i == Xsand_stoneout_1 && j == 6 ? 4 :
6055 i == Xsand_stoneout_1 && j == 7 ? 4 :
6056 i == Xsand_stoneout_2 && j == 0 ? 5 :
6057 i == Xsand_stoneout_2 && j == 1 ? 6 :
6058 i == Xsand_stoneout_2 && j == 2 ? 7 :
6059 i == Xsand_stoneout_2 && j == 3 ? 8 :
6060 i == Xsand_stoneout_2 && j == 4 ? 9 :
6061 i == Xsand_stoneout_2 && j == 5 ? 11 :
6062 i == Xsand_stoneout_2 && j == 6 ? 13 :
6063 i == Xsand_stoneout_2 && j == 7 ? 15 :
6064 i == Xboom_bug && j == 1 ? 2 :
6065 i == Xboom_bug && j == 2 ? 2 :
6066 i == Xboom_bug && j == 3 ? 4 :
6067 i == Xboom_bug && j == 4 ? 4 :
6068 i == Xboom_bug && j == 5 ? 2 :
6069 i == Xboom_bug && j == 6 ? 2 :
6070 i == Xboom_bug && j == 7 ? 0 :
6071 i == Xboom_bomb && j == 1 ? 2 :
6072 i == Xboom_bomb && j == 2 ? 2 :
6073 i == Xboom_bomb && j == 3 ? 4 :
6074 i == Xboom_bomb && j == 4 ? 4 :
6075 i == Xboom_bomb && j == 5 ? 2 :
6076 i == Xboom_bomb && j == 6 ? 2 :
6077 i == Xboom_bomb && j == 7 ? 0 :
6078 i == Xboom_android && j == 7 ? 6 :
6079 i == Xboom_1 && j == 1 ? 2 :
6080 i == Xboom_1 && j == 2 ? 2 :
6081 i == Xboom_1 && j == 3 ? 4 :
6082 i == Xboom_1 && j == 4 ? 4 :
6083 i == Xboom_1 && j == 5 ? 6 :
6084 i == Xboom_1 && j == 6 ? 6 :
6085 i == Xboom_1 && j == 7 ? 8 :
6086 i == Xboom_2 && j == 0 ? 8 :
6087 i == Xboom_2 && j == 1 ? 8 :
6088 i == Xboom_2 && j == 2 ? 10 :
6089 i == Xboom_2 && j == 3 ? 10 :
6090 i == Xboom_2 && j == 4 ? 10 :
6091 i == Xboom_2 && j == 5 ? 12 :
6092 i == Xboom_2 && j == 6 ? 12 :
6093 i == Xboom_2 && j == 7 ? 12 :
6094 special_animation && j == 4 ? 3 :
6095 effective_action != action ? 0 :
6099 Bitmap *debug_bitmap = g_em->bitmap;
6100 int debug_src_x = g_em->src_x;
6101 int debug_src_y = g_em->src_y;
6104 int frame = getAnimationFrame(g->anim_frames,
6107 g->anim_start_frame,
6110 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6111 g->double_movement && is_backside);
6113 g_em->bitmap = src_bitmap;
6114 g_em->src_x = src_x;
6115 g_em->src_y = src_y;
6116 g_em->src_offset_x = 0;
6117 g_em->src_offset_y = 0;
6118 g_em->dst_offset_x = 0;
6119 g_em->dst_offset_y = 0;
6120 g_em->width = TILEX;
6121 g_em->height = TILEY;
6123 g_em->crumbled_bitmap = NULL;
6124 g_em->crumbled_src_x = 0;
6125 g_em->crumbled_src_y = 0;
6126 g_em->crumbled_border_size = 0;
6128 g_em->has_crumbled_graphics = FALSE;
6129 g_em->preserve_background = FALSE;
6132 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6133 printf("::: empty crumbled: %d [%s], %d, %d\n",
6134 effective_element, element_info[effective_element].token_name,
6135 effective_action, direction);
6138 /* if element can be crumbled, but certain action graphics are just empty
6139 space (like snapping sand with the original R'n'D graphics), do not
6140 treat these empty space graphics as crumbled graphics in EMC engine */
6141 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6143 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6145 g_em->has_crumbled_graphics = TRUE;
6146 g_em->crumbled_bitmap = src_bitmap;
6147 g_em->crumbled_src_x = src_x;
6148 g_em->crumbled_src_y = src_y;
6149 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6153 if (element == EL_ROCK &&
6154 effective_action == ACTION_FILLING)
6155 printf("::: has_action_graphics == %d\n", has_action_graphics);
6158 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6159 effective_action == ACTION_MOVING ||
6160 effective_action == ACTION_PUSHING ||
6161 effective_action == ACTION_EATING)) ||
6162 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6163 effective_action == ACTION_EMPTYING)))
6166 (effective_action == ACTION_FALLING ||
6167 effective_action == ACTION_FILLING ||
6168 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6169 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6170 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6171 int num_steps = (i == Ydrip_s1 ? 16 :
6172 i == Ydrip_s1B ? 16 :
6173 i == Ydrip_s2 ? 16 :
6174 i == Ydrip_s2B ? 16 :
6175 i == Xsand_stonein_1 ? 32 :
6176 i == Xsand_stonein_2 ? 32 :
6177 i == Xsand_stonein_3 ? 32 :
6178 i == Xsand_stonein_4 ? 32 :
6179 i == Xsand_stoneout_1 ? 16 :
6180 i == Xsand_stoneout_2 ? 16 : 8);
6181 int cx = ABS(dx) * (TILEX / num_steps);
6182 int cy = ABS(dy) * (TILEY / num_steps);
6183 int step_frame = (i == Ydrip_s2 ? j + 8 :
6184 i == Ydrip_s2B ? j + 8 :
6185 i == Xsand_stonein_2 ? j + 8 :
6186 i == Xsand_stonein_3 ? j + 16 :
6187 i == Xsand_stonein_4 ? j + 24 :
6188 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6189 int step = (is_backside ? step_frame : num_steps - step_frame);
6191 if (is_backside) /* tile where movement starts */
6193 if (dx < 0 || dy < 0)
6195 g_em->src_offset_x = cx * step;
6196 g_em->src_offset_y = cy * step;
6200 g_em->dst_offset_x = cx * step;
6201 g_em->dst_offset_y = cy * step;
6204 else /* tile where movement ends */
6206 if (dx < 0 || dy < 0)
6208 g_em->dst_offset_x = cx * step;
6209 g_em->dst_offset_y = cy * step;
6213 g_em->src_offset_x = cx * step;
6214 g_em->src_offset_y = cy * step;
6218 g_em->width = TILEX - cx * step;
6219 g_em->height = TILEY - cy * step;
6222 /* create unique graphic identifier to decide if tile must be redrawn */
6223 /* bit 31 - 16 (16 bit): EM style graphic
6224 bit 15 - 12 ( 4 bit): EM style frame
6225 bit 11 - 6 ( 6 bit): graphic width
6226 bit 5 - 0 ( 6 bit): graphic height */
6227 g_em->unique_identifier =
6228 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6232 /* skip check for EMC elements not contained in original EMC artwork */
6233 if (element == EL_EMC_FAKE_ACID)
6236 if (g_em->bitmap != debug_bitmap ||
6237 g_em->src_x != debug_src_x ||
6238 g_em->src_y != debug_src_y ||
6239 g_em->src_offset_x != 0 ||
6240 g_em->src_offset_y != 0 ||
6241 g_em->dst_offset_x != 0 ||
6242 g_em->dst_offset_y != 0 ||
6243 g_em->width != TILEX ||
6244 g_em->height != TILEY)
6246 static int last_i = -1;
6254 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6255 i, element, element_info[element].token_name,
6256 element_action_info[effective_action].suffix, direction);
6258 if (element != effective_element)
6259 printf(" [%d ('%s')]",
6261 element_info[effective_element].token_name);
6265 if (g_em->bitmap != debug_bitmap)
6266 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6267 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6269 if (g_em->src_x != debug_src_x ||
6270 g_em->src_y != debug_src_y)
6271 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6272 j, (is_backside ? 'B' : 'F'),
6273 g_em->src_x, g_em->src_y,
6274 g_em->src_x / 32, g_em->src_y / 32,
6275 debug_src_x, debug_src_y,
6276 debug_src_x / 32, debug_src_y / 32);
6278 if (g_em->src_offset_x != 0 ||
6279 g_em->src_offset_y != 0 ||
6280 g_em->dst_offset_x != 0 ||
6281 g_em->dst_offset_y != 0)
6282 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6284 g_em->src_offset_x, g_em->src_offset_y,
6285 g_em->dst_offset_x, g_em->dst_offset_y);
6287 if (g_em->width != TILEX ||
6288 g_em->height != TILEY)
6289 printf(" %d (%d): size %d,%d should be %d,%d\n",
6291 g_em->width, g_em->height, TILEX, TILEY);
6293 num_em_gfx_errors++;
6300 for (i = 0; i < TILE_MAX; i++)
6302 for (j = 0; j < 8; j++)
6304 int element = object_mapping[i].element_rnd;
6305 int action = object_mapping[i].action;
6306 int direction = object_mapping[i].direction;
6307 boolean is_backside = object_mapping[i].is_backside;
6308 int graphic_action = el_act_dir2img(element, action, direction);
6309 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6311 if ((action == ACTION_SMASHED_BY_ROCK ||
6312 action == ACTION_SMASHED_BY_SPRING ||
6313 action == ACTION_EATING) &&
6314 graphic_action == graphic_default)
6316 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
6317 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6318 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6319 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6322 /* no separate animation for "smashed by rock" -- use rock instead */
6323 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6324 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6326 g_em->bitmap = g_xx->bitmap;
6327 g_em->src_x = g_xx->src_x;
6328 g_em->src_y = g_xx->src_y;
6329 g_em->src_offset_x = g_xx->src_offset_x;
6330 g_em->src_offset_y = g_xx->src_offset_y;
6331 g_em->dst_offset_x = g_xx->dst_offset_x;
6332 g_em->dst_offset_y = g_xx->dst_offset_y;
6333 g_em->width = g_xx->width;
6334 g_em->height = g_xx->height;
6335 g_em->unique_identifier = g_xx->unique_identifier;
6338 g_em->preserve_background = TRUE;
6343 for (p = 0; p < MAX_PLAYERS; p++)
6345 for (i = 0; i < SPR_MAX; i++)
6347 int element = player_mapping[p][i].element_rnd;
6348 int action = player_mapping[p][i].action;
6349 int direction = player_mapping[p][i].direction;
6351 for (j = 0; j < 8; j++)
6353 int effective_element = element;
6354 int effective_action = action;
6355 int graphic = (direction == MV_NONE ?
6356 el_act2img(effective_element, effective_action) :
6357 el_act_dir2img(effective_element, effective_action,
6359 struct GraphicInfo *g = &graphic_info[graphic];
6360 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6366 Bitmap *debug_bitmap = g_em->bitmap;
6367 int debug_src_x = g_em->src_x;
6368 int debug_src_y = g_em->src_y;
6371 int frame = getAnimationFrame(g->anim_frames,
6374 g->anim_start_frame,
6377 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6379 g_em->bitmap = src_bitmap;
6380 g_em->src_x = src_x;
6381 g_em->src_y = src_y;
6382 g_em->src_offset_x = 0;
6383 g_em->src_offset_y = 0;
6384 g_em->dst_offset_x = 0;
6385 g_em->dst_offset_y = 0;
6386 g_em->width = TILEX;
6387 g_em->height = TILEY;
6391 /* skip check for EMC elements not contained in original EMC artwork */
6392 if (element == EL_PLAYER_3 ||
6393 element == EL_PLAYER_4)
6396 if (g_em->bitmap != debug_bitmap ||
6397 g_em->src_x != debug_src_x ||
6398 g_em->src_y != debug_src_y)
6400 static int last_i = -1;
6408 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6409 p, i, element, element_info[element].token_name,
6410 element_action_info[effective_action].suffix, direction);
6412 if (element != effective_element)
6413 printf(" [%d ('%s')]",
6415 element_info[effective_element].token_name);
6419 if (g_em->bitmap != debug_bitmap)
6420 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6421 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6423 if (g_em->src_x != debug_src_x ||
6424 g_em->src_y != debug_src_y)
6425 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6427 g_em->src_x, g_em->src_y,
6428 g_em->src_x / 32, g_em->src_y / 32,
6429 debug_src_x, debug_src_y,
6430 debug_src_x / 32, debug_src_y / 32);
6432 num_em_gfx_errors++;
6442 printf("::: [%d errors found]\n", num_em_gfx_errors);
6448 void PlayMenuSoundExt(int sound)
6450 if (sound == SND_UNDEFINED)
6453 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6454 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6457 if (IS_LOOP_SOUND(sound))
6458 PlaySoundLoop(sound);
6463 void PlayMenuSound()
6465 PlayMenuSoundExt(menu.sound[game_status]);
6468 void PlayMenuSoundStereo(int sound, int stereo_position)
6470 if (sound == SND_UNDEFINED)
6473 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6474 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6477 if (IS_LOOP_SOUND(sound))
6478 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6480 PlaySoundStereo(sound, stereo_position);
6483 void PlayMenuSoundIfLoopExt(int sound)
6485 if (sound == SND_UNDEFINED)
6488 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6489 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6492 if (IS_LOOP_SOUND(sound))
6493 PlaySoundLoop(sound);
6496 void PlayMenuSoundIfLoop()
6498 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6501 void PlayMenuMusicExt(int music)
6503 if (music == MUS_UNDEFINED)
6506 if (!setup.sound_music)
6512 void PlayMenuMusic()
6514 PlayMenuMusicExt(menu.music[game_status]);
6517 void PlaySoundActivating()
6520 PlaySound(SND_MENU_ITEM_ACTIVATING);
6524 void PlaySoundSelecting()
6527 PlaySound(SND_MENU_ITEM_SELECTING);
6531 void ToggleFullscreenIfNeeded()
6533 boolean change_fullscreen = (setup.fullscreen !=
6534 video.fullscreen_enabled);
6535 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6536 !strEqual(setup.fullscreen_mode,
6537 video.fullscreen_mode_current));
6539 if (!video.fullscreen_available)
6543 if (change_fullscreen || change_fullscreen_mode)
6545 if (setup.fullscreen != video.fullscreen_enabled ||
6546 setup.fullscreen_mode != video.fullscreen_mode_current)
6549 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6551 /* save backbuffer content which gets lost when toggling fullscreen mode */
6552 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6555 if (change_fullscreen_mode)
6557 if (setup.fullscreen && video.fullscreen_enabled)
6560 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6562 /* (this is now set in sdl.c) */
6564 video.fullscreen_mode_current = setup.fullscreen_mode;
6566 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6569 /* toggle fullscreen */
6570 ChangeVideoModeIfNeeded(setup.fullscreen);
6572 setup.fullscreen = video.fullscreen_enabled;
6574 /* restore backbuffer content from temporary backbuffer backup bitmap */
6575 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6577 FreeBitmap(tmp_backbuffer);
6580 /* update visible window/screen */
6581 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6583 redraw_mask = REDRAW_ALL;