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"
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX 0
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES 0
29 #define TOOL_CTRL_ID_NO 1
30 #define TOOL_CTRL_ID_CONFIRM 2
31 #define TOOL_CTRL_ID_PLAYER_1 3
32 #define TOOL_CTRL_ID_PLAYER_2 4
33 #define TOOL_CTRL_ID_PLAYER_3 5
34 #define TOOL_CTRL_ID_PLAYER_4 6
36 #define NUM_TOOL_BUTTONS 7
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
47 static char *print_if_not_empty(int element)
49 static char *s = NULL;
50 char *token_name = element_info[element].token_name;
55 s = checked_malloc(strlen(token_name) + 10 + 1);
57 if (element != EL_EMPTY)
58 sprintf(s, "%d\t['%s']", element, token_name);
60 sprintf(s, "%d", element);
65 void DumpTile(int x, int y)
70 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
77 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80 if (!IN_LEV_FIELD(x, y))
82 printf("(not in level field)\n");
88 printf(" Feld: %d\t['%s']\n", Feld[x][y],
89 element_info[Feld[x][y]].token_name);
90 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
91 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
92 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
93 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94 printf(" MovPos: %d\n", MovPos[x][y]);
95 printf(" MovDir: %d\n", MovDir[x][y]);
96 printf(" MovDelay: %d\n", MovDelay[x][y]);
97 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
98 printf(" CustomValue: %d\n", CustomValue[x][y]);
99 printf(" GfxElement: %d\n", GfxElement[x][y]);
100 printf(" GfxAction: %d\n", GfxAction[x][y]);
101 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
105 void SetDrawtoField(int mode)
107 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
118 drawto_field = fieldbuffer;
120 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
126 BX2 = SCR_FIELDX - 1;
127 BY2 = SCR_FIELDY - 1;
131 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 if (game_status == GAME_MODE_PLAYING &&
138 level.game_engine_type == GAME_ENGINE_TYPE_EM)
140 /* currently there is no partial redraw -- always redraw whole playfield */
141 RedrawPlayfield_EM(TRUE);
143 /* blit playfield from scroll buffer to normal back buffer for fading in */
144 BlitScreenToBitmap_EM(backbuffer);
146 else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
152 width = gfx.sxsize + 2 * TILEX;
153 height = gfx.sysize + 2 * TILEY;
156 if (force_redraw || setup.direct_draw)
159 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
160 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
162 if (setup.direct_draw)
163 SetDrawtoField(DRAW_BACKBUFFER);
165 for (xx = BX1; xx <= BX2; xx++)
166 for (yy = BY1; yy <= BY2; yy++)
167 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
168 DrawScreenField(xx, yy);
171 if (setup.direct_draw)
172 SetDrawtoField(DRAW_DIRECT);
175 if (setup.soft_scrolling)
177 int fx = FX, fy = FY;
179 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
180 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
182 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
194 BlitBitmap(drawto, window, x, y, width, height, x, y);
197 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
199 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
201 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
202 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
205 void DrawMaskedBorder_FIELD()
207 if (game_status >= GAME_MODE_TITLE &&
208 game_status <= GAME_MODE_PLAYING &&
209 border.draw_masked[game_status])
210 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
213 void DrawMaskedBorder_DOOR_1()
215 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
216 (game_status != GAME_MODE_EDITOR ||
217 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
218 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
221 void DrawMaskedBorder_DOOR_2()
223 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
224 game_status != GAME_MODE_EDITOR)
225 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
228 void DrawMaskedBorder_DOOR_3()
230 /* currently not available */
233 void DrawMaskedBorder_ALL()
235 DrawMaskedBorder_FIELD();
236 DrawMaskedBorder_DOOR_1();
237 DrawMaskedBorder_DOOR_2();
238 DrawMaskedBorder_DOOR_3();
241 void DrawMaskedBorder(int redraw_mask)
243 if (redraw_mask & REDRAW_ALL)
244 DrawMaskedBorder_ALL();
247 if (redraw_mask & REDRAW_FIELD)
248 DrawMaskedBorder_FIELD();
249 if (redraw_mask & REDRAW_DOOR_1)
250 DrawMaskedBorder_DOOR_1();
251 if (redraw_mask & REDRAW_DOOR_2)
252 DrawMaskedBorder_DOOR_2();
253 if (redraw_mask & REDRAW_DOOR_3)
254 DrawMaskedBorder_DOOR_3();
261 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
263 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
264 redraw_mask &= ~REDRAW_MAIN;
266 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
267 redraw_mask |= REDRAW_FIELD;
269 if (redraw_mask & REDRAW_FIELD)
270 redraw_mask &= ~REDRAW_TILES;
272 if (redraw_mask == REDRAW_NONE)
275 if (redraw_mask & REDRAW_TILES &&
276 game_status == GAME_MODE_PLAYING &&
277 border.draw_masked[GAME_MODE_PLAYING])
278 redraw_mask |= REDRAW_FIELD;
280 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
282 static boolean last_frame_skipped = FALSE;
283 boolean skip_even_when_not_scrolling = TRUE;
284 boolean just_scrolling = (ScreenMovDir != 0);
285 boolean verbose = FALSE;
287 if (global.fps_slowdown_factor > 1 &&
288 (FrameCounter % global.fps_slowdown_factor) &&
289 (just_scrolling || skip_even_when_not_scrolling))
291 redraw_mask &= ~REDRAW_MAIN;
293 last_frame_skipped = TRUE;
296 printf("FRAME SKIPPED\n");
300 if (last_frame_skipped)
301 redraw_mask |= REDRAW_FIELD;
303 last_frame_skipped = FALSE;
306 printf("frame not skipped\n");
310 /* synchronize X11 graphics at this point; if we would synchronize the
311 display immediately after the buffer switching (after the XFlush),
312 this could mean that we have to wait for the graphics to complete,
313 although we could go on doing calculations for the next frame */
317 /* prevent drawing masked border to backbuffer when using playfield buffer */
318 if (game_status != GAME_MODE_PLAYING ||
319 redraw_mask & REDRAW_FROM_BACKBUFFER ||
320 buffer == backbuffer)
321 DrawMaskedBorder(redraw_mask);
323 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
325 if (redraw_mask & REDRAW_ALL)
327 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
329 redraw_mask = REDRAW_NONE;
332 if (redraw_mask & REDRAW_FIELD)
334 if (game_status != GAME_MODE_PLAYING ||
335 redraw_mask & REDRAW_FROM_BACKBUFFER)
337 BlitBitmap(backbuffer, window,
338 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
342 int fx = FX, fy = FY;
344 if (setup.soft_scrolling)
346 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
347 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
350 if (setup.soft_scrolling ||
351 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
352 ABS(ScreenMovPos) == ScrollStepSize ||
353 redraw_tiles > REDRAWTILES_THRESHOLD)
355 if (border.draw_masked[GAME_MODE_PLAYING])
357 if (buffer != backbuffer)
359 /* copy playfield buffer to backbuffer to add masked border */
360 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
361 DrawMaskedBorder(REDRAW_FIELD);
364 BlitBitmap(backbuffer, window,
365 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
370 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
375 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
377 (setup.soft_scrolling ?
378 "setup.soft_scrolling" :
379 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
380 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
381 ABS(ScreenGfxPos) == ScrollStepSize ?
382 "ABS(ScreenGfxPos) == ScrollStepSize" :
383 "redraw_tiles > REDRAWTILES_THRESHOLD"));
389 redraw_mask &= ~REDRAW_MAIN;
392 if (redraw_mask & REDRAW_DOORS)
394 if (redraw_mask & REDRAW_DOOR_1)
395 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
397 if (redraw_mask & REDRAW_DOOR_2)
398 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
400 if (redraw_mask & REDRAW_DOOR_3)
401 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
403 redraw_mask &= ~REDRAW_DOORS;
406 if (redraw_mask & REDRAW_MICROLEVEL)
408 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
409 SX, SY + 10 * TILEY);
411 redraw_mask &= ~REDRAW_MICROLEVEL;
414 if (redraw_mask & REDRAW_TILES)
416 for (x = 0; x < SCR_FIELDX; x++)
417 for (y = 0 ; y < SCR_FIELDY; y++)
418 if (redraw[redraw_x1 + x][redraw_y1 + y])
419 BlitBitmap(buffer, window,
420 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
421 SX + x * TILEX, SY + y * TILEY);
424 if (redraw_mask & REDRAW_FPS) /* display frames per second */
429 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
430 if (!global.fps_slowdown)
433 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
434 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
439 for (x = 0; x < MAX_BUF_XSIZE; x++)
440 for (y = 0; y < MAX_BUF_YSIZE; y++)
443 redraw_mask = REDRAW_NONE;
449 long fading_delay = 300;
451 if (setup.fading && (redraw_mask & REDRAW_FIELD))
458 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
461 for (i = 0; i < 2 * FULL_SYSIZE; i++)
463 for (y = 0; y < FULL_SYSIZE; y++)
465 BlitBitmap(backbuffer, window,
466 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
474 for (i = 1; i < FULL_SYSIZE; i+=2)
475 BlitBitmap(backbuffer, window,
476 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
482 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
483 BlitBitmapMasked(backbuffer, window,
484 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
489 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
490 BlitBitmapMasked(backbuffer, window,
491 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
496 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
497 BlitBitmapMasked(backbuffer, window,
498 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
503 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
504 BlitBitmapMasked(backbuffer, window,
505 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
510 redraw_mask &= ~REDRAW_MAIN;
517 void FadeExt(int fade_mask, int fade_mode)
519 void (*draw_border_function)(void) = NULL;
520 Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
521 int x, y, width, height;
522 int fade_delay, post_delay;
524 if (fade_mask & REDRAW_FIELD)
529 height = FULL_SYSIZE;
531 fade_delay = menu.fade_delay;
532 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
534 draw_border_function = DrawMaskedBorder_FIELD;
536 else /* REDRAW_ALL */
543 fade_delay = title.fade_delay_final;
544 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? title.post_delay_final : 0);
547 redraw_mask |= fade_mask;
549 if (!setup.fade_screens || fade_delay == 0)
551 if (fade_mode == FADE_MODE_FADE_OUT)
552 ClearRectangle(backbuffer, x, y, width, height);
559 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
560 draw_border_function);
562 redraw_mask &= ~fade_mask;
565 void FadeIn(int fade_mask)
567 FadeExt(fade_mask, FADE_MODE_FADE_IN);
570 void FadeOut(int fade_mask)
572 FadeExt(fade_mask, FADE_MODE_FADE_OUT);
575 void FadeCross(int fade_mask)
577 FadeExt(fade_mask, FADE_MODE_CROSSFADE);
580 void FadeCrossSaveBackbuffer()
582 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
585 void SetMainBackgroundImageIfDefined(int graphic)
587 if (graphic_info[graphic].bitmap)
588 SetMainBackgroundImage(graphic);
591 void SetMainBackgroundImage(int graphic)
593 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
594 graphic_info[graphic].bitmap ?
595 graphic_info[graphic].bitmap :
596 graphic_info[IMG_BACKGROUND].bitmap);
599 void SetDoorBackgroundImage(int graphic)
601 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
602 graphic_info[graphic].bitmap ?
603 graphic_info[graphic].bitmap :
604 graphic_info[IMG_BACKGROUND].bitmap);
607 void SetPanelBackground()
609 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
610 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
612 SetDoorBackgroundBitmap(bitmap_db_panel);
615 void DrawBackground(int x, int y, int width, int height)
617 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
618 /* (when entering hall of fame after playing) */
620 ClearRectangleOnBackground(drawto, x, y, width, height);
622 ClearRectangleOnBackground(backbuffer, x, y, width, height);
625 redraw_mask |= REDRAW_FIELD;
628 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
630 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
632 if (font->bitmap == NULL)
635 DrawBackground(x, y, width, height);
638 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
640 struct GraphicInfo *g = &graphic_info[graphic];
642 if (g->bitmap == NULL)
645 DrawBackground(x, y, width, height);
650 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
651 /* (when entering hall of fame after playing) */
652 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
654 /* !!! maybe this should be done before clearing the background !!! */
655 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
657 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
658 SetDrawtoField(DRAW_BUFFERED);
661 SetDrawtoField(DRAW_BACKBUFFER);
663 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
665 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
666 SetDrawtoField(DRAW_DIRECT);
670 void MarkTileDirty(int x, int y)
672 int xx = redraw_x1 + x;
673 int yy = redraw_y1 + y;
678 redraw[xx][yy] = TRUE;
679 redraw_mask |= REDRAW_TILES;
682 void SetBorderElement()
686 BorderElement = EL_EMPTY;
688 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
690 for (x = 0; x < lev_fieldx; x++)
692 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
693 BorderElement = EL_STEELWALL;
695 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
701 void SetRandomAnimationValue(int x, int y)
703 gfx.anim_random_frame = GfxRandom[x][y];
706 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
708 /* animation synchronized with global frame counter, not move position */
709 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
710 sync_frame = FrameCounter;
712 return getAnimationFrame(graphic_info[graphic].anim_frames,
713 graphic_info[graphic].anim_delay,
714 graphic_info[graphic].anim_mode,
715 graphic_info[graphic].anim_start_frame,
719 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
720 int *x, int *y, boolean get_backside)
722 struct GraphicInfo *g = &graphic_info[graphic];
723 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
724 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
728 if (g->offset_y == 0) /* frames are ordered horizontally */
730 int max_width = g->anim_frames_per_line * g->width;
731 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
733 *x = pos % max_width;
734 *y = src_y % g->height + pos / max_width * g->height;
736 else if (g->offset_x == 0) /* frames are ordered vertically */
738 int max_height = g->anim_frames_per_line * g->height;
739 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
741 *x = src_x % g->width + pos / max_height * g->width;
742 *y = pos % max_height;
744 else /* frames are ordered diagonally */
746 *x = src_x + frame * g->offset_x;
747 *y = src_y + frame * g->offset_y;
751 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
753 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
756 void DrawGraphic(int x, int y, int graphic, int frame)
759 if (!IN_SCR_FIELD(x, y))
761 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
762 printf("DrawGraphic(): This should never happen!\n");
767 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
771 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
777 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
778 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
781 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
784 if (!IN_SCR_FIELD(x, y))
786 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
787 printf("DrawGraphicThruMask(): This should never happen!\n");
792 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
797 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
803 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
805 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
806 dst_x - src_x, dst_y - src_y);
807 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
810 void DrawMiniGraphic(int x, int y, int graphic)
812 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
813 MarkTileDirty(x / 2, y / 2);
816 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
818 struct GraphicInfo *g = &graphic_info[graphic];
820 int mini_starty = g->bitmap->height * 2 / 3;
823 *x = mini_startx + g->src_x / 2;
824 *y = mini_starty + g->src_y / 2;
827 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
832 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
833 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
836 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
837 int graphic, int frame,
838 int cut_mode, int mask_mode)
843 int width = TILEX, height = TILEY;
846 if (dx || dy) /* shifted graphic */
848 if (x < BX1) /* object enters playfield from the left */
855 else if (x > BX2) /* object enters playfield from the right */
861 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
867 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
869 else if (dx) /* general horizontal movement */
870 MarkTileDirty(x + SIGN(dx), y);
872 if (y < BY1) /* object enters playfield from the top */
874 if (cut_mode==CUT_BELOW) /* object completely above top border */
882 else if (y > BY2) /* object enters playfield from the bottom */
888 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
894 else if (dy > 0 && cut_mode == CUT_ABOVE)
896 if (y == BY2) /* object completely above bottom border */
902 MarkTileDirty(x, y + 1);
903 } /* object leaves playfield to the bottom */
904 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
906 else if (dy) /* general vertical movement */
907 MarkTileDirty(x, y + SIGN(dy));
911 if (!IN_SCR_FIELD(x, y))
913 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
914 printf("DrawGraphicShifted(): This should never happen!\n");
919 if (width > 0 && height > 0)
921 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
926 dst_x = FX + x * TILEX + dx;
927 dst_y = FY + y * TILEY + dy;
929 if (mask_mode == USE_MASKING)
931 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
932 dst_x - src_x, dst_y - src_y);
933 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
937 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
944 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
945 int graphic, int frame,
946 int cut_mode, int mask_mode)
951 int width = TILEX, height = TILEY;
954 int x2 = x + SIGN(dx);
955 int y2 = y + SIGN(dy);
956 int anim_frames = graphic_info[graphic].anim_frames;
957 int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
958 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
959 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
961 /* re-calculate animation frame for two-tile movement animation */
962 frame = getGraphicAnimationFrame(graphic, sync_frame);
964 /* check if movement start graphic inside screen area and should be drawn */
965 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
967 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
969 dst_x = FX + x1 * TILEX;
970 dst_y = FY + y1 * TILEY;
972 if (mask_mode == USE_MASKING)
974 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
975 dst_x - src_x, dst_y - src_y);
976 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
980 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
983 MarkTileDirty(x1, y1);
986 /* check if movement end graphic inside screen area and should be drawn */
987 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
989 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
991 dst_x = FX + x2 * TILEX;
992 dst_y = FY + y2 * TILEY;
994 if (mask_mode == USE_MASKING)
996 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
997 dst_x - src_x, dst_y - src_y);
998 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1002 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1005 MarkTileDirty(x2, y2);
1009 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1010 int graphic, int frame,
1011 int cut_mode, int mask_mode)
1015 DrawGraphic(x, y, graphic, frame);
1020 if (graphic_info[graphic].double_movement) /* EM style movement images */
1021 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1023 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1026 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1027 int frame, int cut_mode)
1029 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1032 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1033 int cut_mode, int mask_mode)
1035 int lx = LEVELX(x), ly = LEVELY(y);
1039 if (IN_LEV_FIELD(lx, ly))
1041 SetRandomAnimationValue(lx, ly);
1043 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1044 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1046 /* do not use double (EM style) movement graphic when not moving */
1047 if (graphic_info[graphic].double_movement && !dx && !dy)
1049 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1050 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1053 else /* border element */
1055 graphic = el2img(element);
1056 frame = getGraphicAnimationFrame(graphic, -1);
1059 if (element == EL_EXPANDABLE_WALL)
1061 boolean left_stopped = FALSE, right_stopped = FALSE;
1063 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1064 left_stopped = TRUE;
1065 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1066 right_stopped = TRUE;
1068 if (left_stopped && right_stopped)
1070 else if (left_stopped)
1072 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1073 frame = graphic_info[graphic].anim_frames - 1;
1075 else if (right_stopped)
1077 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1078 frame = graphic_info[graphic].anim_frames - 1;
1083 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1084 else if (mask_mode == USE_MASKING)
1085 DrawGraphicThruMask(x, y, graphic, frame);
1087 DrawGraphic(x, y, graphic, frame);
1090 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1091 int cut_mode, int mask_mode)
1093 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1094 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1095 cut_mode, mask_mode);
1098 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1101 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1104 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1107 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1110 void DrawLevelElementThruMask(int x, int y, int element)
1112 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1115 void DrawLevelFieldThruMask(int x, int y)
1117 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1120 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1124 int sx = SCREENX(x), sy = SCREENY(y);
1126 int width, height, cx, cy, i;
1127 int crumbled_border_size = graphic_info[graphic].border_size;
1128 static int xy[4][2] =
1136 if (!IN_LEV_FIELD(x, y))
1139 element = TILE_GFX_ELEMENT(x, y);
1141 /* crumble field itself */
1142 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1144 if (!IN_SCR_FIELD(sx, sy))
1147 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1149 for (i = 0; i < 4; i++)
1151 int xx = x + xy[i][0];
1152 int yy = y + xy[i][1];
1154 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1157 /* check if neighbour field is of same type */
1158 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1161 if (i == 1 || i == 2)
1163 width = crumbled_border_size;
1165 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1171 height = crumbled_border_size;
1173 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1176 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1177 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1180 MarkTileDirty(sx, sy);
1182 else /* crumble neighbour fields */
1184 for (i = 0; i < 4; i++)
1186 int xx = x + xy[i][0];
1187 int yy = y + xy[i][1];
1188 int sxx = sx + xy[i][0];
1189 int syy = sy + xy[i][1];
1191 if (!IN_LEV_FIELD(xx, yy) ||
1192 !IN_SCR_FIELD(sxx, syy) ||
1196 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1199 element = TILE_GFX_ELEMENT(xx, yy);
1201 if (!GFX_CRUMBLED(element))
1204 graphic = el_act2crm(element, ACTION_DEFAULT);
1205 crumbled_border_size = graphic_info[graphic].border_size;
1207 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1209 if (i == 1 || i == 2)
1211 width = crumbled_border_size;
1213 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1219 height = crumbled_border_size;
1221 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1224 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1225 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1227 MarkTileDirty(sxx, syy);
1232 void DrawLevelFieldCrumbledSand(int x, int y)
1236 if (!IN_LEV_FIELD(x, y))
1240 /* !!! CHECK THIS !!! */
1243 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1244 GFX_CRUMBLED(GfxElement[x][y]))
1247 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1248 GfxElement[x][y] != EL_UNDEFINED &&
1249 GFX_CRUMBLED(GfxElement[x][y]))
1251 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1258 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1260 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1263 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1266 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1269 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1270 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1271 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1272 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1273 int sx = SCREENX(x), sy = SCREENY(y);
1275 DrawGraphic(sx, sy, graphic1, frame1);
1276 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1279 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1281 int sx = SCREENX(x), sy = SCREENY(y);
1282 static int xy[4][2] =
1291 for (i = 0; i < 4; i++)
1293 int xx = x + xy[i][0];
1294 int yy = y + xy[i][1];
1295 int sxx = sx + xy[i][0];
1296 int syy = sy + xy[i][1];
1298 if (!IN_LEV_FIELD(xx, yy) ||
1299 !IN_SCR_FIELD(sxx, syy) ||
1300 !GFX_CRUMBLED(Feld[xx][yy]) ||
1304 DrawLevelField(xx, yy);
1308 static int getBorderElement(int x, int y)
1312 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1313 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1314 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1315 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1316 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1317 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1318 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1320 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1321 int steel_position = (x == -1 && y == -1 ? 0 :
1322 x == lev_fieldx && y == -1 ? 1 :
1323 x == -1 && y == lev_fieldy ? 2 :
1324 x == lev_fieldx && y == lev_fieldy ? 3 :
1325 x == -1 || x == lev_fieldx ? 4 :
1326 y == -1 || y == lev_fieldy ? 5 : 6);
1328 return border[steel_position][steel_type];
1331 void DrawScreenElement(int x, int y, int element)
1333 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1334 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1337 void DrawLevelElement(int x, int y, int element)
1339 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1340 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1343 void DrawScreenField(int x, int y)
1345 int lx = LEVELX(x), ly = LEVELY(y);
1346 int element, content;
1348 if (!IN_LEV_FIELD(lx, ly))
1350 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1353 element = getBorderElement(lx, ly);
1355 DrawScreenElement(x, y, element);
1359 element = Feld[lx][ly];
1360 content = Store[lx][ly];
1362 if (IS_MOVING(lx, ly))
1364 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1365 boolean cut_mode = NO_CUTTING;
1367 if (element == EL_QUICKSAND_EMPTYING ||
1368 element == EL_MAGIC_WALL_EMPTYING ||
1369 element == EL_BD_MAGIC_WALL_EMPTYING ||
1370 element == EL_AMOEBA_DROPPING)
1371 cut_mode = CUT_ABOVE;
1372 else if (element == EL_QUICKSAND_FILLING ||
1373 element == EL_MAGIC_WALL_FILLING ||
1374 element == EL_BD_MAGIC_WALL_FILLING)
1375 cut_mode = CUT_BELOW;
1377 if (cut_mode == CUT_ABOVE)
1378 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1380 DrawScreenElement(x, y, EL_EMPTY);
1383 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1384 else if (cut_mode == NO_CUTTING)
1385 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1387 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1389 if (content == EL_ACID)
1391 int dir = MovDir[lx][ly];
1392 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1393 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1395 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1398 else if (IS_BLOCKED(lx, ly))
1403 boolean cut_mode = NO_CUTTING;
1404 int element_old, content_old;
1406 Blocked2Moving(lx, ly, &oldx, &oldy);
1409 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1410 MovDir[oldx][oldy] == MV_RIGHT);
1412 element_old = Feld[oldx][oldy];
1413 content_old = Store[oldx][oldy];
1415 if (element_old == EL_QUICKSAND_EMPTYING ||
1416 element_old == EL_MAGIC_WALL_EMPTYING ||
1417 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1418 element_old == EL_AMOEBA_DROPPING)
1419 cut_mode = CUT_ABOVE;
1421 DrawScreenElement(x, y, EL_EMPTY);
1424 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1426 else if (cut_mode == NO_CUTTING)
1427 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1430 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1433 else if (IS_DRAWABLE(element))
1434 DrawScreenElement(x, y, element);
1436 DrawScreenElement(x, y, EL_EMPTY);
1439 void DrawLevelField(int x, int y)
1441 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1442 DrawScreenField(SCREENX(x), SCREENY(y));
1443 else if (IS_MOVING(x, y))
1447 Moving2Blocked(x, y, &newx, &newy);
1448 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1449 DrawScreenField(SCREENX(newx), SCREENY(newy));
1451 else if (IS_BLOCKED(x, y))
1455 Blocked2Moving(x, y, &oldx, &oldy);
1456 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1457 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1461 void DrawMiniElement(int x, int y, int element)
1465 graphic = el2edimg(element);
1466 DrawMiniGraphic(x, y, graphic);
1469 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1471 int x = sx + scroll_x, y = sy + scroll_y;
1473 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1474 DrawMiniElement(sx, sy, EL_EMPTY);
1475 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1476 DrawMiniElement(sx, sy, Feld[x][y]);
1478 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1481 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1482 int x, int y, int xsize, int ysize, int font_nr)
1484 int font_width = getFontWidth(font_nr);
1485 int font_height = getFontHeight(font_nr);
1486 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1489 int dst_x = SX + startx + x * font_width;
1490 int dst_y = SY + starty + y * font_height;
1491 int width = graphic_info[graphic].width;
1492 int height = graphic_info[graphic].height;
1493 int inner_width = MAX(width - 2 * font_width, font_width);
1494 int inner_height = MAX(height - 2 * font_height, font_height);
1495 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1496 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1497 boolean draw_masked = graphic_info[graphic].draw_masked;
1499 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1501 if (src_bitmap == NULL || width < font_width || height < font_height)
1503 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1507 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1508 inner_sx + (x - 1) * font_width % inner_width);
1509 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1510 inner_sy + (y - 1) * font_height % inner_height);
1514 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1515 dst_x - src_x, dst_y - src_y);
1516 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1520 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1524 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1526 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1527 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1528 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1529 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1530 boolean no_delay = (tape.warp_forward);
1531 unsigned long anim_delay = 0;
1532 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1533 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1534 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1535 int font_width = getFontWidth(font_nr);
1536 int font_height = getFontHeight(font_nr);
1537 int max_xsize = level.envelope[envelope_nr].xsize;
1538 int max_ysize = level.envelope[envelope_nr].ysize;
1539 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1540 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1541 int xend = max_xsize;
1542 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1543 int xstep = (xstart < xend ? 1 : 0);
1544 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1547 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1549 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1550 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1551 int sx = (SXSIZE - xsize * font_width) / 2;
1552 int sy = (SYSIZE - ysize * font_height) / 2;
1555 SetDrawtoField(DRAW_BUFFERED);
1557 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1559 SetDrawtoField(DRAW_BACKBUFFER);
1561 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1562 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1564 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1565 level.envelope[envelope_nr].text, font_nr, max_xsize,
1566 xsize - 2, ysize - 2, mask_mode);
1568 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1571 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1575 void ShowEnvelope(int envelope_nr)
1577 int element = EL_ENVELOPE_1 + envelope_nr;
1578 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1579 int sound_opening = element_info[element].sound[ACTION_OPENING];
1580 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1581 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1582 boolean no_delay = (tape.warp_forward);
1583 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1584 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1585 int anim_mode = graphic_info[graphic].anim_mode;
1586 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1587 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1589 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1591 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1593 if (anim_mode == ANIM_DEFAULT)
1594 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1596 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1599 Delay(wait_delay_value);
1601 WaitForEventToContinue();
1603 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1605 if (anim_mode != ANIM_NONE)
1606 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1608 if (anim_mode == ANIM_DEFAULT)
1609 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1611 game.envelope_active = FALSE;
1613 SetDrawtoField(DRAW_BUFFERED);
1615 redraw_mask |= REDRAW_FIELD;
1619 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1624 int width_mult, width_div;
1625 int height_mult, height_div;
1633 int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1634 5 - log_2(tilesize));
1635 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1636 int width_mult = offset_calc[offset_calc_pos].width_mult;
1637 int width_div = offset_calc[offset_calc_pos].width_div;
1638 int height_mult = offset_calc[offset_calc_pos].height_mult;
1639 int height_div = offset_calc[offset_calc_pos].height_div;
1640 int mini_startx = src_bitmap->width * width_mult / width_div;
1641 int mini_starty = src_bitmap->height * height_mult / height_div;
1642 int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1643 int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1645 *bitmap = src_bitmap;
1650 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1654 int graphic = el2preimg(element);
1656 getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1657 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1664 SetDrawBackgroundMask(REDRAW_NONE);
1667 for (x = BX1; x <= BX2; x++)
1668 for (y = BY1; y <= BY2; y++)
1669 DrawScreenField(x, y);
1671 redraw_mask |= REDRAW_FIELD;
1674 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1678 for (x = 0; x < size_x; x++)
1679 for (y = 0; y < size_y; y++)
1680 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1682 redraw_mask |= REDRAW_FIELD;
1685 static void DrawPreviewLevelExt(int from_x, int from_y)
1687 boolean show_level_border = (BorderElement != EL_EMPTY);
1688 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1689 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1690 int tile_size = preview.tile_size;
1691 int preview_width = preview.xsize * tile_size;
1692 int preview_height = preview.ysize * tile_size;
1693 int real_preview_xsize = MIN(level_xsize, preview.xsize);
1694 int real_preview_ysize = MIN(level_ysize, preview.ysize);
1695 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1696 int dst_y = SY + preview.y;
1699 DrawBackground(dst_x, dst_y, preview_width, preview_height);
1701 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
1702 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1704 for (x = 0; x < real_preview_xsize; x++)
1706 for (y = 0; y < real_preview_ysize; y++)
1708 int lx = from_x + x + (show_level_border ? -1 : 0);
1709 int ly = from_y + y + (show_level_border ? -1 : 0);
1710 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1711 getBorderElement(lx, ly));
1713 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1714 element, tile_size);
1718 redraw_mask |= REDRAW_MICROLEVEL;
1721 #define MICROLABEL_EMPTY 0
1722 #define MICROLABEL_LEVEL_NAME 1
1723 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
1724 #define MICROLABEL_LEVEL_AUTHOR 3
1725 #define MICROLABEL_IMPORTED_FROM_HEAD 4
1726 #define MICROLABEL_IMPORTED_FROM 5
1727 #define MICROLABEL_IMPORTED_BY_HEAD 6
1728 #define MICROLABEL_IMPORTED_BY 7
1730 static int getMaxTextLength(struct MenuPosInfo *pos, int font_nr)
1732 int max_text_width = SXSIZE;
1733 int font_width = getFontWidth(font_nr);
1735 if (pos->align == ALIGN_CENTER)
1736 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1737 else if (pos->align == ALIGN_RIGHT)
1738 max_text_width = pos->x;
1740 max_text_width = SXSIZE - pos->x;
1742 return max_text_width / font_width;
1745 static void DrawPreviewLevelLabelExt(int mode)
1747 struct MenuPosInfo *pos = &menu.main.text.level_info_2;
1748 char label_text[MAX_OUTPUT_LINESIZE + 1];
1749 int max_len_label_text;
1750 int font_nr = FONT_TEXT_2;
1753 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1754 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1755 mode == MICROLABEL_IMPORTED_BY_HEAD)
1756 font_nr = FONT_TEXT_3;
1759 max_len_label_text = getMaxTextLength(pos, font_nr);
1761 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1764 for (i = 0; i < max_len_label_text; i++)
1765 label_text[i] = ' ';
1766 label_text[max_len_label_text] = '\0';
1768 if (strlen(label_text) > 0)
1771 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1773 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1774 int lypos = MICROLABEL2_YPOS;
1776 DrawText(lxpos, lypos, label_text, font_nr);
1781 (mode == MICROLABEL_LEVEL_NAME ? level.name :
1782 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1783 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1784 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1785 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1786 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1787 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1788 max_len_label_text);
1789 label_text[max_len_label_text] = '\0';
1791 if (strlen(label_text) > 0)
1794 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1796 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1797 int lypos = MICROLABEL2_YPOS;
1799 DrawText(lxpos, lypos, label_text, font_nr);
1803 redraw_mask |= REDRAW_MICROLEVEL;
1806 void DrawPreviewLevel(boolean restart)
1808 static unsigned long scroll_delay = 0;
1809 static unsigned long label_delay = 0;
1810 static int from_x, from_y, scroll_direction;
1811 static int label_state, label_counter;
1812 unsigned long scroll_delay_value = preview.step_delay;
1813 boolean show_level_border = (BorderElement != EL_EMPTY);
1814 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1815 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1816 int last_game_status = game_status; /* save current game status */
1818 /* force PREVIEW font on preview level */
1819 game_status = GAME_MODE_PSEUDO_PREVIEW;
1826 if (preview.anim_mode == ANIM_CENTERED)
1828 if (level_xsize > preview.xsize)
1829 from_x = (level_xsize - preview.xsize) / 2;
1830 if (level_ysize > preview.ysize)
1831 from_y = (level_ysize - preview.ysize) / 2;
1834 from_x += preview.xoffset;
1835 from_y += preview.yoffset;
1837 scroll_direction = MV_RIGHT;
1841 DrawPreviewLevelExt(from_x, from_y);
1842 DrawPreviewLevelLabelExt(label_state);
1844 /* initialize delay counters */
1845 DelayReached(&scroll_delay, 0);
1846 DelayReached(&label_delay, 0);
1848 if (leveldir_current->name)
1850 struct MenuPosInfo *pos = &menu.main.text.level_info_1;
1851 char label_text[MAX_OUTPUT_LINESIZE + 1];
1852 int font_nr = FONT_TEXT_1;
1854 int max_len_label_text = getMaxTextLength(pos, font_nr);
1856 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1863 strncpy(label_text, leveldir_current->name, max_len_label_text);
1864 label_text[max_len_label_text] = '\0';
1867 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1869 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1870 lypos = SY + MICROLABEL1_YPOS;
1872 DrawText(lxpos, lypos, label_text, font_nr);
1876 game_status = last_game_status; /* restore current game status */
1881 /* scroll preview level, if needed */
1882 if (preview.anim_mode != ANIM_NONE &&
1883 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1884 DelayReached(&scroll_delay, scroll_delay_value))
1886 switch (scroll_direction)
1891 from_x -= preview.step_offset;
1892 from_x = (from_x < 0 ? 0 : from_x);
1895 scroll_direction = MV_UP;
1899 if (from_x < level_xsize - preview.xsize)
1901 from_x += preview.step_offset;
1902 from_x = (from_x > level_xsize - preview.xsize ?
1903 level_xsize - preview.xsize : from_x);
1906 scroll_direction = MV_DOWN;
1912 from_y -= preview.step_offset;
1913 from_y = (from_y < 0 ? 0 : from_y);
1916 scroll_direction = MV_RIGHT;
1920 if (from_y < level_ysize - preview.ysize)
1922 from_y += preview.step_offset;
1923 from_y = (from_y > level_ysize - preview.ysize ?
1924 level_ysize - preview.ysize : from_y);
1927 scroll_direction = MV_LEFT;
1934 DrawPreviewLevelExt(from_x, from_y);
1937 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1938 /* redraw micro level label, if needed */
1939 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1940 !strEqual(level.author, ANONYMOUS_NAME) &&
1941 !strEqual(level.author, leveldir_current->name) &&
1942 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1944 int max_label_counter = 23;
1946 if (leveldir_current->imported_from != NULL &&
1947 strlen(leveldir_current->imported_from) > 0)
1948 max_label_counter += 14;
1949 if (leveldir_current->imported_by != NULL &&
1950 strlen(leveldir_current->imported_by) > 0)
1951 max_label_counter += 14;
1953 label_counter = (label_counter + 1) % max_label_counter;
1954 label_state = (label_counter >= 0 && label_counter <= 7 ?
1955 MICROLABEL_LEVEL_NAME :
1956 label_counter >= 9 && label_counter <= 12 ?
1957 MICROLABEL_LEVEL_AUTHOR_HEAD :
1958 label_counter >= 14 && label_counter <= 21 ?
1959 MICROLABEL_LEVEL_AUTHOR :
1960 label_counter >= 23 && label_counter <= 26 ?
1961 MICROLABEL_IMPORTED_FROM_HEAD :
1962 label_counter >= 28 && label_counter <= 35 ?
1963 MICROLABEL_IMPORTED_FROM :
1964 label_counter >= 37 && label_counter <= 40 ?
1965 MICROLABEL_IMPORTED_BY_HEAD :
1966 label_counter >= 42 && label_counter <= 49 ?
1967 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1969 if (leveldir_current->imported_from == NULL &&
1970 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1971 label_state == MICROLABEL_IMPORTED_FROM))
1972 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1973 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1975 DrawPreviewLevelLabelExt(label_state);
1978 game_status = last_game_status; /* restore current game status */
1981 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1982 int graphic, int sync_frame, int mask_mode)
1984 int frame = getGraphicAnimationFrame(graphic, sync_frame);
1986 if (mask_mode == USE_MASKING)
1987 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1989 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1992 inline void DrawGraphicAnimation(int x, int y, int graphic)
1994 int lx = LEVELX(x), ly = LEVELY(y);
1996 if (!IN_SCR_FIELD(x, y))
1999 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2000 graphic, GfxFrame[lx][ly], NO_MASKING);
2001 MarkTileDirty(x, y);
2004 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2006 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2009 void DrawLevelElementAnimation(int x, int y, int element)
2011 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2013 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2016 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2018 int sx = SCREENX(x), sy = SCREENY(y);
2020 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2023 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2026 DrawGraphicAnimation(sx, sy, graphic);
2029 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2030 DrawLevelFieldCrumbledSand(x, y);
2032 if (GFX_CRUMBLED(Feld[x][y]))
2033 DrawLevelFieldCrumbledSand(x, y);
2037 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2039 int sx = SCREENX(x), sy = SCREENY(y);
2042 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2045 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2047 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2050 DrawGraphicAnimation(sx, sy, graphic);
2052 if (GFX_CRUMBLED(element))
2053 DrawLevelFieldCrumbledSand(x, y);
2056 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2058 if (player->use_murphy)
2060 /* this works only because currently only one player can be "murphy" ... */
2061 static int last_horizontal_dir = MV_LEFT;
2062 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2064 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2065 last_horizontal_dir = move_dir;
2067 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2069 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2071 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2077 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2080 static boolean equalGraphics(int graphic1, int graphic2)
2082 struct GraphicInfo *g1 = &graphic_info[graphic1];
2083 struct GraphicInfo *g2 = &graphic_info[graphic2];
2085 return (g1->bitmap == g2->bitmap &&
2086 g1->src_x == g2->src_x &&
2087 g1->src_y == g2->src_y &&
2088 g1->anim_frames == g2->anim_frames &&
2089 g1->anim_delay == g2->anim_delay &&
2090 g1->anim_mode == g2->anim_mode);
2093 void DrawAllPlayers()
2097 for (i = 0; i < MAX_PLAYERS; i++)
2098 if (stored_player[i].active)
2099 DrawPlayer(&stored_player[i]);
2102 void DrawPlayerField(int x, int y)
2104 if (!IS_PLAYER(x, y))
2107 DrawPlayer(PLAYERINFO(x, y));
2110 void DrawPlayer(struct PlayerInfo *player)
2112 int jx = player->jx;
2113 int jy = player->jy;
2114 int move_dir = player->MovDir;
2115 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2116 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2117 int last_jx = (player->is_moving ? jx - dx : jx);
2118 int last_jy = (player->is_moving ? jy - dy : jy);
2119 int next_jx = jx + dx;
2120 int next_jy = jy + dy;
2121 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2122 boolean player_is_opaque = FALSE;
2123 int sx = SCREENX(jx), sy = SCREENY(jy);
2124 int sxx = 0, syy = 0;
2125 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2127 int action = ACTION_DEFAULT;
2128 int last_player_graphic = getPlayerGraphic(player, move_dir);
2129 int last_player_frame = player->Frame;
2132 /* GfxElement[][] is set to the element the player is digging or collecting;
2133 remove also for off-screen player if the player is not moving anymore */
2134 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2135 GfxElement[jx][jy] = EL_UNDEFINED;
2137 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2141 if (!IN_LEV_FIELD(jx, jy))
2143 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2144 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2145 printf("DrawPlayerField(): This should never happen!\n");
2150 if (element == EL_EXPLOSION)
2153 action = (player->is_pushing ? ACTION_PUSHING :
2154 player->is_digging ? ACTION_DIGGING :
2155 player->is_collecting ? ACTION_COLLECTING :
2156 player->is_moving ? ACTION_MOVING :
2157 player->is_snapping ? ACTION_SNAPPING :
2158 player->is_dropping ? ACTION_DROPPING :
2159 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2161 if (player->is_waiting)
2162 move_dir = player->dir_waiting;
2164 InitPlayerGfxAnimation(player, action, move_dir);
2166 /* ----------------------------------------------------------------------- */
2167 /* draw things in the field the player is leaving, if needed */
2168 /* ----------------------------------------------------------------------- */
2170 if (player->is_moving)
2172 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2174 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2176 if (last_element == EL_DYNAMITE_ACTIVE ||
2177 last_element == EL_EM_DYNAMITE_ACTIVE ||
2178 last_element == EL_SP_DISK_RED_ACTIVE)
2179 DrawDynamite(last_jx, last_jy);
2181 DrawLevelFieldThruMask(last_jx, last_jy);
2183 else if (last_element == EL_DYNAMITE_ACTIVE ||
2184 last_element == EL_EM_DYNAMITE_ACTIVE ||
2185 last_element == EL_SP_DISK_RED_ACTIVE)
2186 DrawDynamite(last_jx, last_jy);
2188 /* !!! this is not enough to prevent flickering of players which are
2189 moving next to each others without a free tile between them -- this
2190 can only be solved by drawing all players layer by layer (first the
2191 background, then the foreground etc.) !!! => TODO */
2192 else if (!IS_PLAYER(last_jx, last_jy))
2193 DrawLevelField(last_jx, last_jy);
2196 DrawLevelField(last_jx, last_jy);
2199 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2200 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2203 if (!IN_SCR_FIELD(sx, sy))
2206 if (setup.direct_draw)
2207 SetDrawtoField(DRAW_BUFFERED);
2209 /* ----------------------------------------------------------------------- */
2210 /* draw things behind the player, if needed */
2211 /* ----------------------------------------------------------------------- */
2214 DrawLevelElement(jx, jy, Back[jx][jy]);
2215 else if (IS_ACTIVE_BOMB(element))
2216 DrawLevelElement(jx, jy, EL_EMPTY);
2219 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2221 int old_element = GfxElement[jx][jy];
2222 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2223 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2225 if (GFX_CRUMBLED(old_element))
2226 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2228 DrawGraphic(sx, sy, old_graphic, frame);
2230 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2231 player_is_opaque = TRUE;
2235 GfxElement[jx][jy] = EL_UNDEFINED;
2237 /* make sure that pushed elements are drawn with correct frame rate */
2239 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2241 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2242 GfxFrame[jx][jy] = player->StepFrame;
2244 if (player->is_pushing && player->is_moving)
2245 GfxFrame[jx][jy] = player->StepFrame;
2248 DrawLevelField(jx, jy);
2252 /* ----------------------------------------------------------------------- */
2253 /* draw player himself */
2254 /* ----------------------------------------------------------------------- */
2256 graphic = getPlayerGraphic(player, move_dir);
2258 /* in the case of changed player action or direction, prevent the current
2259 animation frame from being restarted for identical animations */
2260 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2261 player->Frame = last_player_frame;
2263 frame = getGraphicAnimationFrame(graphic, player->Frame);
2267 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2268 sxx = player->GfxPos;
2270 syy = player->GfxPos;
2273 if (!setup.soft_scrolling && ScreenMovPos)
2276 if (player_is_opaque)
2277 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2279 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2281 if (SHIELD_ON(player))
2283 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2284 IMG_SHIELD_NORMAL_ACTIVE);
2285 int frame = getGraphicAnimationFrame(graphic, -1);
2287 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2290 /* ----------------------------------------------------------------------- */
2291 /* draw things the player is pushing, if needed */
2292 /* ----------------------------------------------------------------------- */
2295 printf("::: %d, %d [%d, %d] [%d]\n",
2296 player->is_pushing, player_is_moving, player->GfxAction,
2297 player->is_moving, player_is_moving);
2301 if (player->is_pushing && player->is_moving)
2303 int px = SCREENX(jx), py = SCREENY(jy);
2304 int pxx = (TILEX - ABS(sxx)) * dx;
2305 int pyy = (TILEY - ABS(syy)) * dy;
2306 int gfx_frame = GfxFrame[jx][jy];
2312 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2314 element = Feld[next_jx][next_jy];
2315 gfx_frame = GfxFrame[next_jx][next_jy];
2318 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2321 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2322 frame = getGraphicAnimationFrame(graphic, sync_frame);
2324 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2327 /* draw background element under pushed element (like the Sokoban field) */
2328 if (Back[next_jx][next_jy])
2329 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2331 /* masked drawing is needed for EMC style (double) movement graphics */
2332 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2336 /* ----------------------------------------------------------------------- */
2337 /* draw things in front of player (active dynamite or dynabombs) */
2338 /* ----------------------------------------------------------------------- */
2340 if (IS_ACTIVE_BOMB(element))
2342 graphic = el2img(element);
2343 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2345 if (game.emulation == EMU_SUPAPLEX)
2346 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2348 DrawGraphicThruMask(sx, sy, graphic, frame);
2351 if (player_is_moving && last_element == EL_EXPLOSION)
2353 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2354 GfxElement[last_jx][last_jy] : EL_EMPTY);
2355 int graphic = el_act2img(element, ACTION_EXPLODING);
2356 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2357 int phase = ExplodePhase[last_jx][last_jy] - 1;
2358 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2361 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2364 /* ----------------------------------------------------------------------- */
2365 /* draw elements the player is just walking/passing through/under */
2366 /* ----------------------------------------------------------------------- */
2368 if (player_is_moving)
2370 /* handle the field the player is leaving ... */
2371 if (IS_ACCESSIBLE_INSIDE(last_element))
2372 DrawLevelField(last_jx, last_jy);
2373 else if (IS_ACCESSIBLE_UNDER(last_element))
2374 DrawLevelFieldThruMask(last_jx, last_jy);
2377 /* do not redraw accessible elements if the player is just pushing them */
2378 if (!player_is_moving || !player->is_pushing)
2380 /* ... and the field the player is entering */
2381 if (IS_ACCESSIBLE_INSIDE(element))
2382 DrawLevelField(jx, jy);
2383 else if (IS_ACCESSIBLE_UNDER(element))
2384 DrawLevelFieldThruMask(jx, jy);
2387 if (setup.direct_draw)
2389 int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2390 int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2391 int x_size = TILEX * (1 + ABS(jx - last_jx));
2392 int y_size = TILEY * (1 + ABS(jy - last_jy));
2394 BlitBitmap(drawto_field, window,
2395 dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2396 SetDrawtoField(DRAW_DIRECT);
2399 MarkTileDirty(sx, sy);
2402 /* ------------------------------------------------------------------------- */
2404 void WaitForEventToContinue()
2406 boolean still_wait = TRUE;
2408 /* simulate releasing mouse button over last gadget, if still pressed */
2410 HandleGadgets(-1, -1, 0);
2412 button_status = MB_RELEASED;
2428 case EVENT_BUTTONPRESS:
2429 case EVENT_KEYPRESS:
2433 case EVENT_KEYRELEASE:
2434 ClearPlayerAction();
2438 HandleOtherEvents(&event);
2442 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2449 /* don't eat all CPU time */
2454 #define MAX_REQUEST_LINES 13
2455 #define MAX_REQUEST_LINE_FONT1_LEN 7
2456 #define MAX_REQUEST_LINE_FONT2_LEN 10
2458 boolean Request(char *text, unsigned int req_state)
2460 int mx, my, ty, result = -1;
2461 unsigned int old_door_state;
2462 int last_game_status = game_status; /* save current game status */
2463 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2464 int font_nr = FONT_TEXT_2;
2465 int max_word_len = 0;
2468 for (text_ptr = text; *text_ptr; text_ptr++)
2470 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2472 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2474 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2475 font_nr = FONT_LEVEL_NUMBER;
2481 if (game_status == GAME_MODE_PLAYING &&
2482 level.game_engine_type == GAME_ENGINE_TYPE_EM)
2483 BlitScreenToBitmap_EM(backbuffer);
2485 /* disable deactivated drawing when quick-loading level tape recording */
2486 if (tape.playing && tape.deactivate_display)
2487 TapeDeactivateDisplayOff(TRUE);
2489 SetMouseCursor(CURSOR_DEFAULT);
2491 #if defined(NETWORK_AVALIABLE)
2492 /* pause network game while waiting for request to answer */
2493 if (options.network &&
2494 game_status == GAME_MODE_PLAYING &&
2495 req_state & REQUEST_WAIT_FOR_INPUT)
2496 SendToServer_PausePlaying();
2499 old_door_state = GetDoorState();
2501 /* simulate releasing mouse button over last gadget, if still pressed */
2503 HandleGadgets(-1, -1, 0);
2507 if (old_door_state & DOOR_OPEN_1)
2509 CloseDoor(DOOR_CLOSE_1);
2511 /* save old door content */
2512 BlitBitmap(bitmap_db_door, bitmap_db_door,
2513 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2514 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2518 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2521 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2523 /* clear door drawing field */
2524 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2526 /* force DOOR font on preview level */
2527 game_status = GAME_MODE_PSEUDO_DOOR;
2529 /* write text for request */
2530 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2532 char text_line[max_request_line_len + 1];
2538 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2541 if (!tc || tc == ' ')
2552 strncpy(text_line, text, tl);
2555 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2556 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2557 text_line, font_nr);
2559 text += tl + (tc == ' ' ? 1 : 0);
2562 game_status = last_game_status; /* restore current game status */
2564 if (req_state & REQ_ASK)
2566 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2567 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2569 else if (req_state & REQ_CONFIRM)
2571 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2573 else if (req_state & REQ_PLAYER)
2575 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2576 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2577 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2578 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2581 /* copy request gadgets to door backbuffer */
2582 BlitBitmap(drawto, bitmap_db_door,
2583 DX, DY, DXSIZE, DYSIZE,
2584 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2586 OpenDoor(DOOR_OPEN_1);
2588 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2590 if (game_status == GAME_MODE_PLAYING)
2592 SetPanelBackground();
2593 SetDrawBackgroundMask(REDRAW_DOOR_1);
2597 SetDrawBackgroundMask(REDRAW_FIELD);
2603 if (game_status != GAME_MODE_MAIN)
2606 button_status = MB_RELEASED;
2608 request_gadget_id = -1;
2610 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2622 case EVENT_BUTTONPRESS:
2623 case EVENT_BUTTONRELEASE:
2624 case EVENT_MOTIONNOTIFY:
2626 if (event.type == EVENT_MOTIONNOTIFY)
2628 if (!PointerInWindow(window))
2629 continue; /* window and pointer are on different screens */
2634 motion_status = TRUE;
2635 mx = ((MotionEvent *) &event)->x;
2636 my = ((MotionEvent *) &event)->y;
2640 motion_status = FALSE;
2641 mx = ((ButtonEvent *) &event)->x;
2642 my = ((ButtonEvent *) &event)->y;
2643 if (event.type == EVENT_BUTTONPRESS)
2644 button_status = ((ButtonEvent *) &event)->button;
2646 button_status = MB_RELEASED;
2649 /* this sets 'request_gadget_id' */
2650 HandleGadgets(mx, my, button_status);
2652 switch (request_gadget_id)
2654 case TOOL_CTRL_ID_YES:
2657 case TOOL_CTRL_ID_NO:
2660 case TOOL_CTRL_ID_CONFIRM:
2661 result = TRUE | FALSE;
2664 case TOOL_CTRL_ID_PLAYER_1:
2667 case TOOL_CTRL_ID_PLAYER_2:
2670 case TOOL_CTRL_ID_PLAYER_3:
2673 case TOOL_CTRL_ID_PLAYER_4:
2684 case EVENT_KEYPRESS:
2685 switch (GetEventKey((KeyEvent *)&event, TRUE))
2698 if (req_state & REQ_PLAYER)
2702 case EVENT_KEYRELEASE:
2703 ClearPlayerAction();
2707 HandleOtherEvents(&event);
2711 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2713 int joy = AnyJoystick();
2715 if (joy & JOY_BUTTON_1)
2717 else if (joy & JOY_BUTTON_2)
2724 if (!PendingEvent()) /* delay only if no pending events */
2727 /* don't eat all CPU time */
2732 if (game_status != GAME_MODE_MAIN)
2737 if (!(req_state & REQ_STAY_OPEN))
2739 CloseDoor(DOOR_CLOSE_1);
2741 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2742 (req_state & REQ_REOPEN))
2743 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2748 if (game_status == GAME_MODE_PLAYING)
2750 SetPanelBackground();
2751 SetDrawBackgroundMask(REDRAW_DOOR_1);
2755 SetDrawBackgroundMask(REDRAW_FIELD);
2758 #if defined(NETWORK_AVALIABLE)
2759 /* continue network game after request */
2760 if (options.network &&
2761 game_status == GAME_MODE_PLAYING &&
2762 req_state & REQUEST_WAIT_FOR_INPUT)
2763 SendToServer_ContinuePlaying();
2766 /* restore deactivated drawing when quick-loading level tape recording */
2767 if (tape.playing && tape.deactivate_display)
2768 TapeDeactivateDisplayOn();
2773 unsigned int OpenDoor(unsigned int door_state)
2775 if (door_state & DOOR_COPY_BACK)
2777 if (door_state & DOOR_OPEN_1)
2778 BlitBitmap(bitmap_db_door, bitmap_db_door,
2779 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2780 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2782 if (door_state & DOOR_OPEN_2)
2783 BlitBitmap(bitmap_db_door, bitmap_db_door,
2784 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2785 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2787 door_state &= ~DOOR_COPY_BACK;
2790 return MoveDoor(door_state);
2793 unsigned int CloseDoor(unsigned int door_state)
2795 unsigned int old_door_state = GetDoorState();
2797 if (!(door_state & DOOR_NO_COPY_BACK))
2799 if (old_door_state & DOOR_OPEN_1)
2800 BlitBitmap(backbuffer, bitmap_db_door,
2801 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2803 if (old_door_state & DOOR_OPEN_2)
2804 BlitBitmap(backbuffer, bitmap_db_door,
2805 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2807 door_state &= ~DOOR_NO_COPY_BACK;
2810 return MoveDoor(door_state);
2813 unsigned int GetDoorState()
2815 return MoveDoor(DOOR_GET_STATE);
2818 unsigned int SetDoorState(unsigned int door_state)
2820 return MoveDoor(door_state | DOOR_SET_STATE);
2823 unsigned int MoveDoor(unsigned int door_state)
2825 static int door1 = DOOR_OPEN_1;
2826 static int door2 = DOOR_CLOSE_2;
2827 unsigned long door_delay = 0;
2828 unsigned long door_delay_value;
2831 if (door_1.width < 0 || door_1.width > DXSIZE)
2832 door_1.width = DXSIZE;
2833 if (door_1.height < 0 || door_1.height > DYSIZE)
2834 door_1.height = DYSIZE;
2835 if (door_2.width < 0 || door_2.width > VXSIZE)
2836 door_2.width = VXSIZE;
2837 if (door_2.height < 0 || door_2.height > VYSIZE)
2838 door_2.height = VYSIZE;
2840 if (door_state == DOOR_GET_STATE)
2841 return (door1 | door2);
2843 if (door_state & DOOR_SET_STATE)
2845 if (door_state & DOOR_ACTION_1)
2846 door1 = door_state & DOOR_ACTION_1;
2847 if (door_state & DOOR_ACTION_2)
2848 door2 = door_state & DOOR_ACTION_2;
2850 return (door1 | door2);
2853 if (!(door_state & DOOR_FORCE_REDRAW))
2855 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2856 door_state &= ~DOOR_OPEN_1;
2857 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2858 door_state &= ~DOOR_CLOSE_1;
2859 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2860 door_state &= ~DOOR_OPEN_2;
2861 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2862 door_state &= ~DOOR_CLOSE_2;
2865 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2868 if (setup.quick_doors)
2870 stepsize = 20; /* must be choosen to always draw last frame */
2871 door_delay_value = 0;
2874 if (global.autoplay_leveldir)
2876 door_state |= DOOR_NO_DELAY;
2877 door_state &= ~DOOR_CLOSE_ALL;
2880 if (door_state & DOOR_ACTION)
2882 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2883 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2884 boolean door_1_done = (!handle_door_1);
2885 boolean door_2_done = (!handle_door_2);
2886 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2887 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2888 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2889 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2890 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2891 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2892 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
2893 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2894 int door_skip = max_door_size - door_size;
2895 int end = door_size;
2896 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2899 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2901 /* opening door sound has priority over simultaneously closing door */
2902 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2903 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2904 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2905 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2908 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2911 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2912 GC gc = bitmap->stored_clip_gc;
2914 if (door_state & DOOR_ACTION_1)
2916 int a = MIN(x * door_1.step_offset, end);
2917 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2918 int i = p + door_skip;
2920 if (door_1.anim_mode & ANIM_STATIC_PANEL)
2922 BlitBitmap(bitmap_db_door, drawto,
2923 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2924 DXSIZE, DYSIZE, DX, DY);
2928 BlitBitmap(bitmap_db_door, drawto,
2929 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2930 DXSIZE, DYSIZE - p / 2, DX, DY);
2932 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2935 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2937 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2938 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2939 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2940 int dst2_x = DX, dst2_y = DY;
2941 int width = i, height = DYSIZE;
2943 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2944 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2947 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2948 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2951 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2953 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2954 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2955 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2956 int dst2_x = DX, dst2_y = DY;
2957 int width = DXSIZE, height = i;
2959 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2960 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2963 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2964 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2967 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2969 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2971 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2972 BlitBitmapMasked(bitmap, drawto,
2973 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2974 DX + DXSIZE - i, DY + j);
2975 BlitBitmapMasked(bitmap, drawto,
2976 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2977 DX + DXSIZE - i, DY + 140 + j);
2978 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2979 DY - (DOOR_GFX_PAGEY1 + j));
2980 BlitBitmapMasked(bitmap, drawto,
2981 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2983 BlitBitmapMasked(bitmap, drawto,
2984 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2987 BlitBitmapMasked(bitmap, drawto,
2988 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2990 BlitBitmapMasked(bitmap, drawto,
2991 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2993 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2994 BlitBitmapMasked(bitmap, drawto,
2995 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2996 DX + DXSIZE - i, DY + 77 + j);
2997 BlitBitmapMasked(bitmap, drawto,
2998 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2999 DX + DXSIZE - i, DY + 203 + j);
3002 redraw_mask |= REDRAW_DOOR_1;
3003 door_1_done = (a == end);
3006 if (door_state & DOOR_ACTION_2)
3008 int a = MIN(x * door_2.step_offset, door_size);
3009 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3010 int i = p + door_skip;
3012 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3014 BlitBitmap(bitmap_db_door, drawto,
3015 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3016 VXSIZE, VYSIZE, VX, VY);
3018 else if (x <= VYSIZE)
3020 BlitBitmap(bitmap_db_door, drawto,
3021 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3022 VXSIZE, VYSIZE - p / 2, VX, VY);
3024 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3027 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3029 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3030 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3031 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3032 int dst2_x = VX, dst2_y = VY;
3033 int width = i, height = VYSIZE;
3035 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3036 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3039 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3040 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3043 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3045 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3046 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3047 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3048 int dst2_x = VX, dst2_y = VY;
3049 int width = VXSIZE, height = i;
3051 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3052 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3055 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3056 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3059 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3061 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3063 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3064 BlitBitmapMasked(bitmap, drawto,
3065 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3066 VX + VXSIZE - i, VY + j);
3067 SetClipOrigin(bitmap, gc,
3068 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3069 BlitBitmapMasked(bitmap, drawto,
3070 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3073 BlitBitmapMasked(bitmap, drawto,
3074 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3075 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3076 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3077 BlitBitmapMasked(bitmap, drawto,
3078 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3080 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3083 redraw_mask |= REDRAW_DOOR_2;
3084 door_2_done = (a == VXSIZE);
3087 if (!(door_state & DOOR_NO_DELAY))
3091 if (game_status == GAME_MODE_MAIN)
3094 WaitUntilDelayReached(&door_delay, door_delay_value);
3099 if (door_state & DOOR_ACTION_1)
3100 door1 = door_state & DOOR_ACTION_1;
3101 if (door_state & DOOR_ACTION_2)
3102 door2 = door_state & DOOR_ACTION_2;
3104 return (door1 | door2);
3107 void DrawSpecialEditorDoor()
3109 /* draw bigger toolbox window */
3110 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3111 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3113 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3114 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3117 redraw_mask |= REDRAW_ALL;
3120 void UndrawSpecialEditorDoor()
3122 /* draw normal tape recorder window */
3123 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3124 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3127 redraw_mask |= REDRAW_ALL;
3131 /* ---------- new tool button stuff ---------------------------------------- */
3133 /* graphic position values for tool buttons */
3134 #define TOOL_BUTTON_YES_XPOS 2
3135 #define TOOL_BUTTON_YES_YPOS 250
3136 #define TOOL_BUTTON_YES_GFX_YPOS 0
3137 #define TOOL_BUTTON_YES_XSIZE 46
3138 #define TOOL_BUTTON_YES_YSIZE 28
3139 #define TOOL_BUTTON_NO_XPOS 52
3140 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3141 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3142 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3143 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3144 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3145 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3146 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3147 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3148 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3149 #define TOOL_BUTTON_PLAYER_XSIZE 30
3150 #define TOOL_BUTTON_PLAYER_YSIZE 30
3151 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3152 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3153 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3154 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3155 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3156 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3157 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3158 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3159 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3160 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3161 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3162 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3163 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3164 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3165 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3166 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3167 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3168 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3169 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3170 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3179 } toolbutton_info[NUM_TOOL_BUTTONS] =
3182 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3183 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3184 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3189 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3190 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3191 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3196 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3197 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3198 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3199 TOOL_CTRL_ID_CONFIRM,
3203 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3204 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3205 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3206 TOOL_CTRL_ID_PLAYER_1,
3210 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3211 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3212 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3213 TOOL_CTRL_ID_PLAYER_2,
3217 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3218 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3219 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3220 TOOL_CTRL_ID_PLAYER_3,
3224 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3225 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3226 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3227 TOOL_CTRL_ID_PLAYER_4,
3232 void CreateToolButtons()
3236 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3238 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3239 Bitmap *deco_bitmap = None;
3240 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3241 struct GadgetInfo *gi;
3242 unsigned long event_mask;
3243 int gd_xoffset, gd_yoffset;
3244 int gd_x1, gd_x2, gd_y;
3247 event_mask = GD_EVENT_RELEASED;
3249 gd_xoffset = toolbutton_info[i].xpos;
3250 gd_yoffset = toolbutton_info[i].ypos;
3251 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3252 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3253 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3255 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3257 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3259 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3260 &deco_bitmap, &deco_x, &deco_y);
3261 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3262 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3265 gi = CreateGadget(GDI_CUSTOM_ID, id,
3266 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3267 GDI_X, DX + toolbutton_info[i].x,
3268 GDI_Y, DY + toolbutton_info[i].y,
3269 GDI_WIDTH, toolbutton_info[i].width,
3270 GDI_HEIGHT, toolbutton_info[i].height,
3271 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3272 GDI_STATE, GD_BUTTON_UNPRESSED,
3273 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3274 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3275 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3276 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3277 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3278 GDI_DECORATION_SHIFTING, 1, 1,
3279 GDI_DIRECT_DRAW, FALSE,
3280 GDI_EVENT_MASK, event_mask,
3281 GDI_CALLBACK_ACTION, HandleToolButtons,
3285 Error(ERR_EXIT, "cannot create gadget");
3287 tool_gadget[id] = gi;
3291 void FreeToolButtons()
3295 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3296 FreeGadget(tool_gadget[i]);
3299 static void UnmapToolButtons()
3303 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3304 UnmapGadget(tool_gadget[i]);
3307 static void HandleToolButtons(struct GadgetInfo *gi)
3309 request_gadget_id = gi->custom_id;
3312 static struct Mapping_EM_to_RND_object
3315 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3316 boolean is_backside; /* backside of moving element */
3322 em_object_mapping_list[] =
3325 Xblank, TRUE, FALSE,
3329 Yacid_splash_eB, FALSE, FALSE,
3330 EL_ACID_SPLASH_RIGHT, -1, -1
3333 Yacid_splash_wB, FALSE, FALSE,
3334 EL_ACID_SPLASH_LEFT, -1, -1
3337 #ifdef EM_ENGINE_BAD_ROLL
3339 Xstone_force_e, FALSE, FALSE,
3340 EL_ROCK, -1, MV_BIT_RIGHT
3343 Xstone_force_w, FALSE, FALSE,
3344 EL_ROCK, -1, MV_BIT_LEFT
3347 Xnut_force_e, FALSE, FALSE,
3348 EL_NUT, -1, MV_BIT_RIGHT
3351 Xnut_force_w, FALSE, FALSE,
3352 EL_NUT, -1, MV_BIT_LEFT
3355 Xspring_force_e, FALSE, FALSE,
3356 EL_SPRING, -1, MV_BIT_RIGHT
3359 Xspring_force_w, FALSE, FALSE,
3360 EL_SPRING, -1, MV_BIT_LEFT
3363 Xemerald_force_e, FALSE, FALSE,
3364 EL_EMERALD, -1, MV_BIT_RIGHT
3367 Xemerald_force_w, FALSE, FALSE,
3368 EL_EMERALD, -1, MV_BIT_LEFT
3371 Xdiamond_force_e, FALSE, FALSE,
3372 EL_DIAMOND, -1, MV_BIT_RIGHT
3375 Xdiamond_force_w, FALSE, FALSE,
3376 EL_DIAMOND, -1, MV_BIT_LEFT
3379 Xbomb_force_e, FALSE, FALSE,
3380 EL_BOMB, -1, MV_BIT_RIGHT
3383 Xbomb_force_w, FALSE, FALSE,
3384 EL_BOMB, -1, MV_BIT_LEFT
3386 #endif /* EM_ENGINE_BAD_ROLL */
3389 Xstone, TRUE, FALSE,
3393 Xstone_pause, FALSE, FALSE,
3397 Xstone_fall, FALSE, FALSE,
3401 Ystone_s, FALSE, FALSE,
3402 EL_ROCK, ACTION_FALLING, -1
3405 Ystone_sB, FALSE, TRUE,
3406 EL_ROCK, ACTION_FALLING, -1
3409 Ystone_e, FALSE, FALSE,
3410 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3413 Ystone_eB, FALSE, TRUE,
3414 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3417 Ystone_w, FALSE, FALSE,
3418 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3421 Ystone_wB, FALSE, TRUE,
3422 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3429 Xnut_pause, FALSE, FALSE,
3433 Xnut_fall, FALSE, FALSE,
3437 Ynut_s, FALSE, FALSE,
3438 EL_NUT, ACTION_FALLING, -1
3441 Ynut_sB, FALSE, TRUE,
3442 EL_NUT, ACTION_FALLING, -1
3445 Ynut_e, FALSE, FALSE,
3446 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3449 Ynut_eB, FALSE, TRUE,
3450 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3453 Ynut_w, FALSE, FALSE,
3454 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3457 Ynut_wB, FALSE, TRUE,
3458 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3461 Xbug_n, TRUE, FALSE,
3465 Xbug_e, TRUE, FALSE,
3466 EL_BUG_RIGHT, -1, -1
3469 Xbug_s, TRUE, FALSE,
3473 Xbug_w, TRUE, FALSE,
3477 Xbug_gon, FALSE, FALSE,
3481 Xbug_goe, FALSE, FALSE,
3482 EL_BUG_RIGHT, -1, -1
3485 Xbug_gos, FALSE, FALSE,
3489 Xbug_gow, FALSE, FALSE,
3493 Ybug_n, FALSE, FALSE,
3494 EL_BUG, ACTION_MOVING, MV_BIT_UP
3497 Ybug_nB, FALSE, TRUE,
3498 EL_BUG, ACTION_MOVING, MV_BIT_UP
3501 Ybug_e, FALSE, FALSE,
3502 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3505 Ybug_eB, FALSE, TRUE,
3506 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3509 Ybug_s, FALSE, FALSE,
3510 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3513 Ybug_sB, FALSE, TRUE,
3514 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3517 Ybug_w, FALSE, FALSE,
3518 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3521 Ybug_wB, FALSE, TRUE,
3522 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
3525 Ybug_w_n, FALSE, FALSE,
3526 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3529 Ybug_n_e, FALSE, FALSE,
3530 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3533 Ybug_e_s, FALSE, FALSE,
3534 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3537 Ybug_s_w, FALSE, FALSE,
3538 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3541 Ybug_e_n, FALSE, FALSE,
3542 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3545 Ybug_s_e, FALSE, FALSE,
3546 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3549 Ybug_w_s, FALSE, FALSE,
3550 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3553 Ybug_n_w, FALSE, FALSE,
3554 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3557 Ybug_stone, FALSE, FALSE,
3558 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
3561 Ybug_spring, FALSE, FALSE,
3562 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
3565 Xtank_n, TRUE, FALSE,
3566 EL_SPACESHIP_UP, -1, -1
3569 Xtank_e, TRUE, FALSE,
3570 EL_SPACESHIP_RIGHT, -1, -1
3573 Xtank_s, TRUE, FALSE,
3574 EL_SPACESHIP_DOWN, -1, -1
3577 Xtank_w, TRUE, FALSE,
3578 EL_SPACESHIP_LEFT, -1, -1
3581 Xtank_gon, FALSE, FALSE,
3582 EL_SPACESHIP_UP, -1, -1
3585 Xtank_goe, FALSE, FALSE,
3586 EL_SPACESHIP_RIGHT, -1, -1
3589 Xtank_gos, FALSE, FALSE,
3590 EL_SPACESHIP_DOWN, -1, -1
3593 Xtank_gow, FALSE, FALSE,
3594 EL_SPACESHIP_LEFT, -1, -1
3597 Ytank_n, FALSE, FALSE,
3598 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3601 Ytank_nB, FALSE, TRUE,
3602 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
3605 Ytank_e, FALSE, FALSE,
3606 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3609 Ytank_eB, FALSE, TRUE,
3610 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
3613 Ytank_s, FALSE, FALSE,
3614 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3617 Ytank_sB, FALSE, TRUE,
3618 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
3621 Ytank_w, FALSE, FALSE,
3622 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3625 Ytank_wB, FALSE, TRUE,
3626 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
3629 Ytank_w_n, FALSE, FALSE,
3630 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3633 Ytank_n_e, FALSE, FALSE,
3634 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3637 Ytank_e_s, FALSE, FALSE,
3638 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3641 Ytank_s_w, FALSE, FALSE,
3642 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3645 Ytank_e_n, FALSE, FALSE,
3646 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3649 Ytank_s_e, FALSE, FALSE,
3650 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3653 Ytank_w_s, FALSE, FALSE,
3654 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3657 Ytank_n_w, FALSE, FALSE,
3658 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3661 Ytank_stone, FALSE, FALSE,
3662 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
3665 Ytank_spring, FALSE, FALSE,
3666 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
3669 Xandroid, TRUE, FALSE,
3670 EL_EMC_ANDROID, ACTION_ACTIVE, -1
3673 Xandroid_1_n, FALSE, FALSE,
3674 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3677 Xandroid_2_n, FALSE, FALSE,
3678 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
3681 Xandroid_1_e, FALSE, FALSE,
3682 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3685 Xandroid_2_e, FALSE, FALSE,
3686 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
3689 Xandroid_1_w, FALSE, FALSE,
3690 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3693 Xandroid_2_w, FALSE, FALSE,
3694 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
3697 Xandroid_1_s, FALSE, FALSE,
3698 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3701 Xandroid_2_s, FALSE, FALSE,
3702 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
3705 Yandroid_n, FALSE, FALSE,
3706 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3709 Yandroid_nB, FALSE, TRUE,
3710 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
3713 Yandroid_ne, FALSE, FALSE,
3714 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
3717 Yandroid_neB, FALSE, TRUE,
3718 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
3721 Yandroid_e, FALSE, FALSE,
3722 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3725 Yandroid_eB, FALSE, TRUE,
3726 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
3729 Yandroid_se, FALSE, FALSE,
3730 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
3733 Yandroid_seB, FALSE, TRUE,
3734 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3737 Yandroid_s, FALSE, FALSE,
3738 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3741 Yandroid_sB, FALSE, TRUE,
3742 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
3745 Yandroid_sw, FALSE, FALSE,
3746 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
3749 Yandroid_swB, FALSE, TRUE,
3750 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
3753 Yandroid_w, FALSE, FALSE,
3754 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3757 Yandroid_wB, FALSE, TRUE,
3758 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
3761 Yandroid_nw, FALSE, FALSE,
3762 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
3765 Yandroid_nwB, FALSE, TRUE,
3766 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
3769 Xspring, TRUE, FALSE,
3773 Xspring_pause, FALSE, FALSE,
3777 Xspring_e, FALSE, FALSE,
3781 Xspring_w, FALSE, FALSE,
3785 Xspring_fall, FALSE, FALSE,
3789 Yspring_s, FALSE, FALSE,
3790 EL_SPRING, ACTION_FALLING, -1
3793 Yspring_sB, FALSE, TRUE,
3794 EL_SPRING, ACTION_FALLING, -1
3797 Yspring_e, FALSE, FALSE,
3798 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3801 Yspring_eB, FALSE, TRUE,
3802 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3805 Yspring_w, FALSE, FALSE,
3806 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3809 Yspring_wB, FALSE, TRUE,
3810 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3813 Yspring_kill_e, FALSE, FALSE,
3814 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3817 Yspring_kill_eB, FALSE, TRUE,
3818 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
3821 Yspring_kill_w, FALSE, FALSE,
3822 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3825 Yspring_kill_wB, FALSE, TRUE,
3826 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
3829 Xeater_n, TRUE, FALSE,
3830 EL_YAMYAM_UP, -1, -1
3833 Xeater_e, TRUE, FALSE,
3834 EL_YAMYAM_RIGHT, -1, -1
3837 Xeater_w, TRUE, FALSE,
3838 EL_YAMYAM_LEFT, -1, -1
3841 Xeater_s, TRUE, FALSE,
3842 EL_YAMYAM_DOWN, -1, -1
3845 Yeater_n, FALSE, FALSE,
3846 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3849 Yeater_nB, FALSE, TRUE,
3850 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3853 Yeater_e, FALSE, FALSE,
3854 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3857 Yeater_eB, FALSE, TRUE,
3858 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3861 Yeater_s, FALSE, FALSE,
3862 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3865 Yeater_sB, FALSE, TRUE,
3866 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3869 Yeater_w, FALSE, FALSE,
3870 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3873 Yeater_wB, FALSE, TRUE,
3874 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3877 Yeater_stone, FALSE, FALSE,
3878 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
3881 Yeater_spring, FALSE, FALSE,
3882 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
3885 Xalien, TRUE, FALSE,
3889 Xalien_pause, FALSE, FALSE,
3893 Yalien_n, FALSE, FALSE,
3894 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3897 Yalien_nB, FALSE, TRUE,
3898 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3901 Yalien_e, FALSE, FALSE,
3902 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3905 Yalien_eB, FALSE, TRUE,
3906 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3909 Yalien_s, FALSE, FALSE,
3910 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3913 Yalien_sB, FALSE, TRUE,
3914 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3917 Yalien_w, FALSE, FALSE,
3918 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3921 Yalien_wB, FALSE, TRUE,
3922 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3925 Yalien_stone, FALSE, FALSE,
3926 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
3929 Yalien_spring, FALSE, FALSE,
3930 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
3933 Xemerald, TRUE, FALSE,
3937 Xemerald_pause, FALSE, FALSE,
3941 Xemerald_fall, FALSE, FALSE,
3945 Xemerald_shine, FALSE, FALSE,
3946 EL_EMERALD, ACTION_TWINKLING, -1
3949 Yemerald_s, FALSE, FALSE,
3950 EL_EMERALD, ACTION_FALLING, -1
3953 Yemerald_sB, FALSE, TRUE,
3954 EL_EMERALD, ACTION_FALLING, -1
3957 Yemerald_e, FALSE, FALSE,
3958 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3961 Yemerald_eB, FALSE, TRUE,
3962 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3965 Yemerald_w, FALSE, FALSE,
3966 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3969 Yemerald_wB, FALSE, TRUE,
3970 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3973 Yemerald_eat, FALSE, FALSE,
3974 EL_EMERALD, ACTION_COLLECTING, -1
3977 Yemerald_stone, FALSE, FALSE,
3978 EL_NUT, ACTION_BREAKING, -1
3981 Xdiamond, TRUE, FALSE,
3985 Xdiamond_pause, FALSE, FALSE,
3989 Xdiamond_fall, FALSE, FALSE,
3993 Xdiamond_shine, FALSE, FALSE,
3994 EL_DIAMOND, ACTION_TWINKLING, -1
3997 Ydiamond_s, FALSE, FALSE,
3998 EL_DIAMOND, ACTION_FALLING, -1
4001 Ydiamond_sB, FALSE, TRUE,
4002 EL_DIAMOND, ACTION_FALLING, -1
4005 Ydiamond_e, FALSE, FALSE,
4006 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4009 Ydiamond_eB, FALSE, TRUE,
4010 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4013 Ydiamond_w, FALSE, FALSE,
4014 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4017 Ydiamond_wB, FALSE, TRUE,
4018 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4021 Ydiamond_eat, FALSE, FALSE,
4022 EL_DIAMOND, ACTION_COLLECTING, -1
4025 Ydiamond_stone, FALSE, FALSE,
4026 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4029 Xdrip_fall, TRUE, FALSE,
4030 EL_AMOEBA_DROP, -1, -1
4033 Xdrip_stretch, FALSE, FALSE,
4034 EL_AMOEBA_DROP, ACTION_FALLING, -1
4037 Xdrip_stretchB, FALSE, TRUE,
4038 EL_AMOEBA_DROP, ACTION_FALLING, -1
4041 Xdrip_eat, FALSE, FALSE,
4042 EL_AMOEBA_DROP, ACTION_GROWING, -1
4045 Ydrip_s1, FALSE, FALSE,
4046 EL_AMOEBA_DROP, ACTION_FALLING, -1
4049 Ydrip_s1B, FALSE, TRUE,
4050 EL_AMOEBA_DROP, ACTION_FALLING, -1
4053 Ydrip_s2, FALSE, FALSE,
4054 EL_AMOEBA_DROP, ACTION_FALLING, -1
4057 Ydrip_s2B, FALSE, TRUE,
4058 EL_AMOEBA_DROP, ACTION_FALLING, -1
4065 Xbomb_pause, FALSE, FALSE,
4069 Xbomb_fall, FALSE, FALSE,
4073 Ybomb_s, FALSE, FALSE,
4074 EL_BOMB, ACTION_FALLING, -1
4077 Ybomb_sB, FALSE, TRUE,
4078 EL_BOMB, ACTION_FALLING, -1
4081 Ybomb_e, FALSE, FALSE,
4082 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4085 Ybomb_eB, FALSE, TRUE,
4086 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4089 Ybomb_w, FALSE, FALSE,
4090 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4093 Ybomb_wB, FALSE, TRUE,
4094 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4097 Ybomb_eat, FALSE, FALSE,
4098 EL_BOMB, ACTION_ACTIVATING, -1
4101 Xballoon, TRUE, FALSE,
4105 Yballoon_n, FALSE, FALSE,
4106 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4109 Yballoon_nB, FALSE, TRUE,
4110 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4113 Yballoon_e, FALSE, FALSE,
4114 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4117 Yballoon_eB, FALSE, TRUE,
4118 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4121 Yballoon_s, FALSE, FALSE,
4122 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4125 Yballoon_sB, FALSE, TRUE,
4126 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4129 Yballoon_w, FALSE, FALSE,
4130 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4133 Yballoon_wB, FALSE, TRUE,
4134 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4137 Xgrass, TRUE, FALSE,
4138 EL_EMC_GRASS, -1, -1
4141 Ygrass_nB, FALSE, FALSE,
4142 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4145 Ygrass_eB, FALSE, FALSE,
4146 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4149 Ygrass_sB, FALSE, FALSE,
4150 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4153 Ygrass_wB, FALSE, FALSE,
4154 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4161 Ydirt_nB, FALSE, FALSE,
4162 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4165 Ydirt_eB, FALSE, FALSE,
4166 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4169 Ydirt_sB, FALSE, FALSE,
4170 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4173 Ydirt_wB, FALSE, FALSE,
4174 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4177 Xacid_ne, TRUE, FALSE,
4178 EL_ACID_POOL_TOPRIGHT, -1, -1
4181 Xacid_se, TRUE, FALSE,
4182 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4185 Xacid_s, TRUE, FALSE,
4186 EL_ACID_POOL_BOTTOM, -1, -1
4189 Xacid_sw, TRUE, FALSE,
4190 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4193 Xacid_nw, TRUE, FALSE,
4194 EL_ACID_POOL_TOPLEFT, -1, -1
4197 Xacid_1, TRUE, FALSE,
4201 Xacid_2, FALSE, FALSE,
4205 Xacid_3, FALSE, FALSE,
4209 Xacid_4, FALSE, FALSE,
4213 Xacid_5, FALSE, FALSE,
4217 Xacid_6, FALSE, FALSE,
4221 Xacid_7, FALSE, FALSE,
4225 Xacid_8, FALSE, FALSE,
4229 Xball_1, TRUE, FALSE,
4230 EL_EMC_MAGIC_BALL, -1, -1
4233 Xball_1B, FALSE, FALSE,
4234 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4237 Xball_2, FALSE, FALSE,
4238 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4241 Xball_2B, FALSE, FALSE,
4242 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4245 Yball_eat, FALSE, FALSE,
4246 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4249 Ykey_1_eat, FALSE, FALSE,
4250 EL_EM_KEY_1, ACTION_COLLECTING, -1
4253 Ykey_2_eat, FALSE, FALSE,
4254 EL_EM_KEY_2, ACTION_COLLECTING, -1
4257 Ykey_3_eat, FALSE, FALSE,
4258 EL_EM_KEY_3, ACTION_COLLECTING, -1
4261 Ykey_4_eat, FALSE, FALSE,
4262 EL_EM_KEY_4, ACTION_COLLECTING, -1
4265 Ykey_5_eat, FALSE, FALSE,
4266 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4269 Ykey_6_eat, FALSE, FALSE,
4270 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4273 Ykey_7_eat, FALSE, FALSE,
4274 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4277 Ykey_8_eat, FALSE, FALSE,
4278 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4281 Ylenses_eat, FALSE, FALSE,
4282 EL_EMC_LENSES, ACTION_COLLECTING, -1
4285 Ymagnify_eat, FALSE, FALSE,
4286 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4289 Ygrass_eat, FALSE, FALSE,
4290 EL_EMC_GRASS, ACTION_SNAPPING, -1
4293 Ydirt_eat, FALSE, FALSE,
4294 EL_SAND, ACTION_SNAPPING, -1
4297 Xgrow_ns, TRUE, FALSE,
4298 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4301 Ygrow_ns_eat, FALSE, FALSE,
4302 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4305 Xgrow_ew, TRUE, FALSE,
4306 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4309 Ygrow_ew_eat, FALSE, FALSE,
4310 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4313 Xwonderwall, TRUE, FALSE,
4314 EL_MAGIC_WALL, -1, -1
4317 XwonderwallB, FALSE, FALSE,
4318 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4321 Xamoeba_1, TRUE, FALSE,
4322 EL_AMOEBA_DRY, ACTION_OTHER, -1
4325 Xamoeba_2, FALSE, FALSE,
4326 EL_AMOEBA_DRY, ACTION_OTHER, -1
4329 Xamoeba_3, FALSE, FALSE,
4330 EL_AMOEBA_DRY, ACTION_OTHER, -1
4333 Xamoeba_4, FALSE, FALSE,
4334 EL_AMOEBA_DRY, ACTION_OTHER, -1
4337 Xamoeba_5, TRUE, FALSE,
4338 EL_AMOEBA_WET, ACTION_OTHER, -1
4341 Xamoeba_6, FALSE, FALSE,
4342 EL_AMOEBA_WET, ACTION_OTHER, -1
4345 Xamoeba_7, FALSE, FALSE,
4346 EL_AMOEBA_WET, ACTION_OTHER, -1
4349 Xamoeba_8, FALSE, FALSE,
4350 EL_AMOEBA_WET, ACTION_OTHER, -1
4353 Xdoor_1, TRUE, FALSE,
4354 EL_EM_GATE_1, -1, -1
4357 Xdoor_2, TRUE, FALSE,
4358 EL_EM_GATE_2, -1, -1
4361 Xdoor_3, TRUE, FALSE,
4362 EL_EM_GATE_3, -1, -1
4365 Xdoor_4, TRUE, FALSE,
4366 EL_EM_GATE_4, -1, -1
4369 Xdoor_5, TRUE, FALSE,
4370 EL_EMC_GATE_5, -1, -1
4373 Xdoor_6, TRUE, FALSE,
4374 EL_EMC_GATE_6, -1, -1
4377 Xdoor_7, TRUE, FALSE,
4378 EL_EMC_GATE_7, -1, -1
4381 Xdoor_8, TRUE, FALSE,
4382 EL_EMC_GATE_8, -1, -1
4385 Xkey_1, TRUE, FALSE,
4389 Xkey_2, TRUE, FALSE,
4393 Xkey_3, TRUE, FALSE,
4397 Xkey_4, TRUE, FALSE,
4401 Xkey_5, TRUE, FALSE,
4402 EL_EMC_KEY_5, -1, -1
4405 Xkey_6, TRUE, FALSE,
4406 EL_EMC_KEY_6, -1, -1
4409 Xkey_7, TRUE, FALSE,
4410 EL_EMC_KEY_7, -1, -1
4413 Xkey_8, TRUE, FALSE,
4414 EL_EMC_KEY_8, -1, -1
4417 Xwind_n, TRUE, FALSE,
4418 EL_BALLOON_SWITCH_UP, -1, -1
4421 Xwind_e, TRUE, FALSE,
4422 EL_BALLOON_SWITCH_RIGHT, -1, -1
4425 Xwind_s, TRUE, FALSE,
4426 EL_BALLOON_SWITCH_DOWN, -1, -1
4429 Xwind_w, TRUE, FALSE,
4430 EL_BALLOON_SWITCH_LEFT, -1, -1
4433 Xwind_nesw, TRUE, FALSE,
4434 EL_BALLOON_SWITCH_ANY, -1, -1
4437 Xwind_stop, TRUE, FALSE,
4438 EL_BALLOON_SWITCH_NONE, -1, -1
4442 EL_EXIT_CLOSED, -1, -1
4445 Xexit_1, TRUE, FALSE,
4446 EL_EXIT_OPEN, -1, -1
4449 Xexit_2, FALSE, FALSE,
4450 EL_EXIT_OPEN, -1, -1
4453 Xexit_3, FALSE, FALSE,
4454 EL_EXIT_OPEN, -1, -1
4457 Xdynamite, TRUE, FALSE,
4458 EL_EM_DYNAMITE, -1, -1
4461 Ydynamite_eat, FALSE, FALSE,
4462 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4465 Xdynamite_1, TRUE, FALSE,
4466 EL_EM_DYNAMITE_ACTIVE, -1, -1
4469 Xdynamite_2, FALSE, FALSE,
4470 EL_EM_DYNAMITE_ACTIVE, -1, -1
4473 Xdynamite_3, FALSE, FALSE,
4474 EL_EM_DYNAMITE_ACTIVE, -1, -1
4477 Xdynamite_4, FALSE, FALSE,
4478 EL_EM_DYNAMITE_ACTIVE, -1, -1
4481 Xbumper, TRUE, FALSE,
4482 EL_EMC_SPRING_BUMPER, -1, -1
4485 XbumperB, FALSE, FALSE,
4486 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4489 Xwheel, TRUE, FALSE,
4490 EL_ROBOT_WHEEL, -1, -1
4493 XwheelB, FALSE, FALSE,
4494 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4497 Xswitch, TRUE, FALSE,
4498 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4501 XswitchB, FALSE, FALSE,
4502 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4506 EL_QUICKSAND_EMPTY, -1, -1
4509 Xsand_stone, TRUE, FALSE,
4510 EL_QUICKSAND_FULL, -1, -1
4513 Xsand_stonein_1, FALSE, TRUE,
4514 EL_ROCK, ACTION_FILLING, -1
4517 Xsand_stonein_2, FALSE, TRUE,
4518 EL_ROCK, ACTION_FILLING, -1
4521 Xsand_stonein_3, FALSE, TRUE,
4522 EL_ROCK, ACTION_FILLING, -1
4525 Xsand_stonein_4, FALSE, TRUE,
4526 EL_ROCK, ACTION_FILLING, -1
4529 Xsand_stonesand_1, FALSE, FALSE,
4530 EL_QUICKSAND_FULL, -1, -1
4533 Xsand_stonesand_2, FALSE, FALSE,
4534 EL_QUICKSAND_FULL, -1, -1
4537 Xsand_stonesand_3, FALSE, FALSE,
4538 EL_QUICKSAND_FULL, -1, -1
4541 Xsand_stonesand_4, FALSE, FALSE,
4542 EL_QUICKSAND_FULL, -1, -1
4545 Xsand_stoneout_1, FALSE, FALSE,
4546 EL_ROCK, ACTION_EMPTYING, -1
4549 Xsand_stoneout_2, FALSE, FALSE,
4550 EL_ROCK, ACTION_EMPTYING, -1
4553 Xsand_sandstone_1, FALSE, FALSE,
4554 EL_QUICKSAND_FULL, -1, -1
4557 Xsand_sandstone_2, FALSE, FALSE,
4558 EL_QUICKSAND_FULL, -1, -1
4561 Xsand_sandstone_3, FALSE, FALSE,
4562 EL_QUICKSAND_FULL, -1, -1
4565 Xsand_sandstone_4, FALSE, FALSE,
4566 EL_QUICKSAND_FULL, -1, -1
4569 Xplant, TRUE, FALSE,
4570 EL_EMC_PLANT, -1, -1
4573 Yplant, FALSE, FALSE,
4574 EL_EMC_PLANT, -1, -1
4577 Xlenses, TRUE, FALSE,
4578 EL_EMC_LENSES, -1, -1
4581 Xmagnify, TRUE, FALSE,
4582 EL_EMC_MAGNIFIER, -1, -1
4585 Xdripper, TRUE, FALSE,
4586 EL_EMC_DRIPPER, -1, -1
4589 XdripperB, FALSE, FALSE,
4590 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
4593 Xfake_blank, TRUE, FALSE,
4594 EL_INVISIBLE_WALL, -1, -1
4597 Xfake_blankB, FALSE, FALSE,
4598 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
4601 Xfake_grass, TRUE, FALSE,
4602 EL_EMC_FAKE_GRASS, -1, -1
4605 Xfake_grassB, FALSE, FALSE,
4606 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
4609 Xfake_door_1, TRUE, FALSE,
4610 EL_EM_GATE_1_GRAY, -1, -1
4613 Xfake_door_2, TRUE, FALSE,
4614 EL_EM_GATE_2_GRAY, -1, -1
4617 Xfake_door_3, TRUE, FALSE,
4618 EL_EM_GATE_3_GRAY, -1, -1
4621 Xfake_door_4, TRUE, FALSE,
4622 EL_EM_GATE_4_GRAY, -1, -1
4625 Xfake_door_5, TRUE, FALSE,
4626 EL_EMC_GATE_5_GRAY, -1, -1
4629 Xfake_door_6, TRUE, FALSE,
4630 EL_EMC_GATE_6_GRAY, -1, -1
4633 Xfake_door_7, TRUE, FALSE,
4634 EL_EMC_GATE_7_GRAY, -1, -1
4637 Xfake_door_8, TRUE, FALSE,
4638 EL_EMC_GATE_8_GRAY, -1, -1
4641 Xfake_acid_1, TRUE, FALSE,
4642 EL_EMC_FAKE_ACID, -1, -1
4645 Xfake_acid_2, FALSE, FALSE,
4646 EL_EMC_FAKE_ACID, -1, -1
4649 Xfake_acid_3, FALSE, FALSE,
4650 EL_EMC_FAKE_ACID, -1, -1
4653 Xfake_acid_4, FALSE, FALSE,
4654 EL_EMC_FAKE_ACID, -1, -1
4657 Xfake_acid_5, FALSE, FALSE,
4658 EL_EMC_FAKE_ACID, -1, -1
4661 Xfake_acid_6, FALSE, FALSE,
4662 EL_EMC_FAKE_ACID, -1, -1
4665 Xfake_acid_7, FALSE, FALSE,
4666 EL_EMC_FAKE_ACID, -1, -1
4669 Xfake_acid_8, FALSE, FALSE,
4670 EL_EMC_FAKE_ACID, -1, -1
4673 Xsteel_1, TRUE, FALSE,
4674 EL_STEELWALL, -1, -1
4677 Xsteel_2, TRUE, FALSE,
4678 EL_EMC_STEELWALL_2, -1, -1
4681 Xsteel_3, TRUE, FALSE,
4682 EL_EMC_STEELWALL_3, -1, -1
4685 Xsteel_4, TRUE, FALSE,
4686 EL_EMC_STEELWALL_4, -1, -1
4689 Xwall_1, TRUE, FALSE,
4693 Xwall_2, TRUE, FALSE,
4694 EL_EMC_WALL_14, -1, -1
4697 Xwall_3, TRUE, FALSE,
4698 EL_EMC_WALL_15, -1, -1
4701 Xwall_4, TRUE, FALSE,
4702 EL_EMC_WALL_16, -1, -1
4705 Xround_wall_1, TRUE, FALSE,
4706 EL_WALL_SLIPPERY, -1, -1
4709 Xround_wall_2, TRUE, FALSE,
4710 EL_EMC_WALL_SLIPPERY_2, -1, -1
4713 Xround_wall_3, TRUE, FALSE,
4714 EL_EMC_WALL_SLIPPERY_3, -1, -1
4717 Xround_wall_4, TRUE, FALSE,
4718 EL_EMC_WALL_SLIPPERY_4, -1, -1
4721 Xdecor_1, TRUE, FALSE,
4722 EL_EMC_WALL_8, -1, -1
4725 Xdecor_2, TRUE, FALSE,
4726 EL_EMC_WALL_6, -1, -1
4729 Xdecor_3, TRUE, FALSE,
4730 EL_EMC_WALL_4, -1, -1
4733 Xdecor_4, TRUE, FALSE,
4734 EL_EMC_WALL_7, -1, -1
4737 Xdecor_5, TRUE, FALSE,
4738 EL_EMC_WALL_5, -1, -1
4741 Xdecor_6, TRUE, FALSE,
4742 EL_EMC_WALL_9, -1, -1
4745 Xdecor_7, TRUE, FALSE,
4746 EL_EMC_WALL_10, -1, -1
4749 Xdecor_8, TRUE, FALSE,
4750 EL_EMC_WALL_1, -1, -1
4753 Xdecor_9, TRUE, FALSE,
4754 EL_EMC_WALL_2, -1, -1
4757 Xdecor_10, TRUE, FALSE,
4758 EL_EMC_WALL_3, -1, -1
4761 Xdecor_11, TRUE, FALSE,
4762 EL_EMC_WALL_11, -1, -1
4765 Xdecor_12, TRUE, FALSE,
4766 EL_EMC_WALL_12, -1, -1
4769 Xalpha_0, TRUE, FALSE,
4770 EL_CHAR('0'), -1, -1
4773 Xalpha_1, TRUE, FALSE,
4774 EL_CHAR('1'), -1, -1
4777 Xalpha_2, TRUE, FALSE,
4778 EL_CHAR('2'), -1, -1
4781 Xalpha_3, TRUE, FALSE,
4782 EL_CHAR('3'), -1, -1
4785 Xalpha_4, TRUE, FALSE,
4786 EL_CHAR('4'), -1, -1
4789 Xalpha_5, TRUE, FALSE,
4790 EL_CHAR('5'), -1, -1
4793 Xalpha_6, TRUE, FALSE,
4794 EL_CHAR('6'), -1, -1
4797 Xalpha_7, TRUE, FALSE,
4798 EL_CHAR('7'), -1, -1
4801 Xalpha_8, TRUE, FALSE,
4802 EL_CHAR('8'), -1, -1
4805 Xalpha_9, TRUE, FALSE,
4806 EL_CHAR('9'), -1, -1
4809 Xalpha_excla, TRUE, FALSE,
4810 EL_CHAR('!'), -1, -1
4813 Xalpha_quote, TRUE, FALSE,
4814 EL_CHAR('"'), -1, -1
4817 Xalpha_comma, TRUE, FALSE,
4818 EL_CHAR(','), -1, -1
4821 Xalpha_minus, TRUE, FALSE,
4822 EL_CHAR('-'), -1, -1
4825 Xalpha_perio, TRUE, FALSE,
4826 EL_CHAR('.'), -1, -1
4829 Xalpha_colon, TRUE, FALSE,
4830 EL_CHAR(':'), -1, -1
4833 Xalpha_quest, TRUE, FALSE,
4834 EL_CHAR('?'), -1, -1
4837 Xalpha_a, TRUE, FALSE,
4838 EL_CHAR('A'), -1, -1
4841 Xalpha_b, TRUE, FALSE,
4842 EL_CHAR('B'), -1, -1
4845 Xalpha_c, TRUE, FALSE,
4846 EL_CHAR('C'), -1, -1
4849 Xalpha_d, TRUE, FALSE,
4850 EL_CHAR('D'), -1, -1
4853 Xalpha_e, TRUE, FALSE,
4854 EL_CHAR('E'), -1, -1
4857 Xalpha_f, TRUE, FALSE,
4858 EL_CHAR('F'), -1, -1
4861 Xalpha_g, TRUE, FALSE,
4862 EL_CHAR('G'), -1, -1
4865 Xalpha_h, TRUE, FALSE,
4866 EL_CHAR('H'), -1, -1
4869 Xalpha_i, TRUE, FALSE,
4870 EL_CHAR('I'), -1, -1
4873 Xalpha_j, TRUE, FALSE,
4874 EL_CHAR('J'), -1, -1
4877 Xalpha_k, TRUE, FALSE,
4878 EL_CHAR('K'), -1, -1
4881 Xalpha_l, TRUE, FALSE,
4882 EL_CHAR('L'), -1, -1
4885 Xalpha_m, TRUE, FALSE,
4886 EL_CHAR('M'), -1, -1
4889 Xalpha_n, TRUE, FALSE,
4890 EL_CHAR('N'), -1, -1
4893 Xalpha_o, TRUE, FALSE,
4894 EL_CHAR('O'), -1, -1
4897 Xalpha_p, TRUE, FALSE,
4898 EL_CHAR('P'), -1, -1
4901 Xalpha_q, TRUE, FALSE,
4902 EL_CHAR('Q'), -1, -1
4905 Xalpha_r, TRUE, FALSE,
4906 EL_CHAR('R'), -1, -1
4909 Xalpha_s, TRUE, FALSE,
4910 EL_CHAR('S'), -1, -1
4913 Xalpha_t, TRUE, FALSE,
4914 EL_CHAR('T'), -1, -1
4917 Xalpha_u, TRUE, FALSE,
4918 EL_CHAR('U'), -1, -1
4921 Xalpha_v, TRUE, FALSE,
4922 EL_CHAR('V'), -1, -1
4925 Xalpha_w, TRUE, FALSE,
4926 EL_CHAR('W'), -1, -1
4929 Xalpha_x, TRUE, FALSE,
4930 EL_CHAR('X'), -1, -1
4933 Xalpha_y, TRUE, FALSE,
4934 EL_CHAR('Y'), -1, -1
4937 Xalpha_z, TRUE, FALSE,
4938 EL_CHAR('Z'), -1, -1
4941 Xalpha_arrow_e, TRUE, FALSE,
4942 EL_CHAR('>'), -1, -1
4945 Xalpha_arrow_w, TRUE, FALSE,
4946 EL_CHAR('<'), -1, -1
4949 Xalpha_copyr, TRUE, FALSE,
4950 EL_CHAR('©'), -1, -1
4954 Xboom_bug, FALSE, FALSE,
4955 EL_BUG, ACTION_EXPLODING, -1
4958 Xboom_bomb, FALSE, FALSE,
4959 EL_BOMB, ACTION_EXPLODING, -1
4962 Xboom_android, FALSE, FALSE,
4963 EL_EMC_ANDROID, ACTION_OTHER, -1
4966 Xboom_1, FALSE, FALSE,
4967 EL_DEFAULT, ACTION_EXPLODING, -1
4970 Xboom_2, FALSE, FALSE,
4971 EL_DEFAULT, ACTION_EXPLODING, -1
4974 Znormal, FALSE, FALSE,
4978 Zdynamite, FALSE, FALSE,
4982 Zplayer, FALSE, FALSE,
4986 ZBORDER, FALSE, FALSE,
4996 static struct Mapping_EM_to_RND_player
5005 em_player_mapping_list[] =
5009 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5013 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5017 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5021 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5025 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5029 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5033 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5037 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5041 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5045 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5049 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5053 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5057 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5061 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5065 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5069 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5073 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5077 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5081 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5085 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5089 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5093 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5097 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5101 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5105 EL_PLAYER_1, ACTION_DEFAULT, -1,
5109 EL_PLAYER_2, ACTION_DEFAULT, -1,
5113 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5117 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5121 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5125 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5129 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5133 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5137 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5141 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5145 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5149 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5153 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5157 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5161 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5165 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5169 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5173 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5177 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5181 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5185 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5189 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5193 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5197 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5201 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5205 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5209 EL_PLAYER_3, ACTION_DEFAULT, -1,
5213 EL_PLAYER_4, ACTION_DEFAULT, -1,
5222 int map_element_RND_to_EM(int element_rnd)
5224 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5225 static boolean mapping_initialized = FALSE;
5227 if (!mapping_initialized)
5231 /* return "Xalpha_quest" for all undefined elements in mapping array */
5232 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5233 mapping_RND_to_EM[i] = Xalpha_quest;
5235 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5236 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5237 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5238 em_object_mapping_list[i].element_em;
5240 mapping_initialized = TRUE;
5243 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5244 return mapping_RND_to_EM[element_rnd];
5246 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5251 int map_element_EM_to_RND(int element_em)
5253 static unsigned short mapping_EM_to_RND[TILE_MAX];
5254 static boolean mapping_initialized = FALSE;
5256 if (!mapping_initialized)
5260 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5261 for (i = 0; i < TILE_MAX; i++)
5262 mapping_EM_to_RND[i] = EL_UNKNOWN;
5264 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5265 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5266 em_object_mapping_list[i].element_rnd;
5268 mapping_initialized = TRUE;
5271 if (element_em >= 0 && element_em < TILE_MAX)
5272 return mapping_EM_to_RND[element_em];
5274 Error(ERR_WARN, "invalid EM level element %d", element_em);
5279 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5281 struct LevelInfo_EM *level_em = level->native_em_level;
5282 struct LEVEL *lev = level_em->lev;
5285 for (i = 0; i < TILE_MAX; i++)
5286 lev->android_array[i] = Xblank;
5288 for (i = 0; i < level->num_android_clone_elements; i++)
5290 int element_rnd = level->android_clone_element[i];
5291 int element_em = map_element_RND_to_EM(element_rnd);
5293 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5294 if (em_object_mapping_list[j].element_rnd == element_rnd)
5295 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5299 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5301 struct LevelInfo_EM *level_em = level->native_em_level;
5302 struct LEVEL *lev = level_em->lev;
5305 level->num_android_clone_elements = 0;
5307 for (i = 0; i < TILE_MAX; i++)
5309 int element_em = lev->android_array[i];
5311 boolean element_found = FALSE;
5313 if (element_em == Xblank)
5316 element_rnd = map_element_EM_to_RND(element_em);
5318 for (j = 0; j < level->num_android_clone_elements; j++)
5319 if (level->android_clone_element[j] == element_rnd)
5320 element_found = TRUE;
5324 level->android_clone_element[level->num_android_clone_elements++] =
5327 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5332 if (level->num_android_clone_elements == 0)
5334 level->num_android_clone_elements = 1;
5335 level->android_clone_element[0] = EL_EMPTY;
5339 int map_direction_RND_to_EM(int direction)
5341 return (direction == MV_UP ? 0 :
5342 direction == MV_RIGHT ? 1 :
5343 direction == MV_DOWN ? 2 :
5344 direction == MV_LEFT ? 3 :
5348 int map_direction_EM_to_RND(int direction)
5350 return (direction == 0 ? MV_UP :
5351 direction == 1 ? MV_RIGHT :
5352 direction == 2 ? MV_DOWN :
5353 direction == 3 ? MV_LEFT :
5357 int get_next_element(int element)
5361 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5362 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5363 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5364 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5365 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5366 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5367 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5369 default: return element;
5374 int el_act_dir2img(int element, int action, int direction)
5376 element = GFX_ELEMENT(element);
5378 if (direction == MV_NONE)
5379 return element_info[element].graphic[action];
5381 direction = MV_DIR_TO_BIT(direction);
5383 return element_info[element].direction_graphic[action][direction];
5386 int el_act_dir2img(int element, int action, int direction)
5388 element = GFX_ELEMENT(element);
5389 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5391 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5392 return element_info[element].direction_graphic[action][direction];
5397 static int el_act_dir2crm(int element, int action, int direction)
5399 element = GFX_ELEMENT(element);
5401 if (direction == MV_NONE)
5402 return element_info[element].crumbled[action];
5404 direction = MV_DIR_TO_BIT(direction);
5406 return element_info[element].direction_crumbled[action][direction];
5409 static int el_act_dir2crm(int element, int action, int direction)
5411 element = GFX_ELEMENT(element);
5412 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5414 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5415 return element_info[element].direction_crumbled[action][direction];
5419 int el_act2img(int element, int action)
5421 element = GFX_ELEMENT(element);
5423 return element_info[element].graphic[action];
5426 int el_act2crm(int element, int action)
5428 element = GFX_ELEMENT(element);
5430 return element_info[element].crumbled[action];
5433 int el_dir2img(int element, int direction)
5435 element = GFX_ELEMENT(element);
5437 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5440 int el2baseimg(int element)
5442 return element_info[element].graphic[ACTION_DEFAULT];
5445 int el2img(int element)
5447 element = GFX_ELEMENT(element);
5449 return element_info[element].graphic[ACTION_DEFAULT];
5452 int el2edimg(int element)
5454 element = GFX_ELEMENT(element);
5456 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5459 int el2preimg(int element)
5461 element = GFX_ELEMENT(element);
5463 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5466 int font2baseimg(int font_nr)
5468 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5471 int getNumActivePlayers_EM()
5473 int num_players = 0;
5479 for (i = 0; i < MAX_PLAYERS; i++)
5480 if (tape.player_participates[i])
5486 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5488 int game_frame_delay_value;
5490 game_frame_delay_value =
5491 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5492 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5495 if (tape.playing && tape.warp_forward && !tape.pausing)
5496 game_frame_delay_value = 0;
5498 return game_frame_delay_value;
5501 unsigned int InitRND(long seed)
5503 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5504 return InitEngineRandom_EM(seed);
5506 return InitEngineRandom_RND(seed);
5509 void InitGraphicInfo_EM(void)
5511 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5512 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5516 int num_em_gfx_errors = 0;
5518 if (graphic_info_em_object[0][0].bitmap == NULL)
5520 /* EM graphics not yet initialized in em_open_all() */
5525 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5528 /* always start with reliable default values */
5529 for (i = 0; i < TILE_MAX; i++)
5531 object_mapping[i].element_rnd = EL_UNKNOWN;
5532 object_mapping[i].is_backside = FALSE;
5533 object_mapping[i].action = ACTION_DEFAULT;
5534 object_mapping[i].direction = MV_NONE;
5537 /* always start with reliable default values */
5538 for (p = 0; p < MAX_PLAYERS; p++)
5540 for (i = 0; i < SPR_MAX; i++)
5542 player_mapping[p][i].element_rnd = EL_UNKNOWN;
5543 player_mapping[p][i].action = ACTION_DEFAULT;
5544 player_mapping[p][i].direction = MV_NONE;
5548 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5550 int e = em_object_mapping_list[i].element_em;
5552 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5553 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5555 if (em_object_mapping_list[i].action != -1)
5556 object_mapping[e].action = em_object_mapping_list[i].action;
5558 if (em_object_mapping_list[i].direction != -1)
5559 object_mapping[e].direction =
5560 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5563 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5565 int a = em_player_mapping_list[i].action_em;
5566 int p = em_player_mapping_list[i].player_nr;
5568 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5570 if (em_player_mapping_list[i].action != -1)
5571 player_mapping[p][a].action = em_player_mapping_list[i].action;
5573 if (em_player_mapping_list[i].direction != -1)
5574 player_mapping[p][a].direction =
5575 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5578 for (i = 0; i < TILE_MAX; i++)
5580 int element = object_mapping[i].element_rnd;
5581 int action = object_mapping[i].action;
5582 int direction = object_mapping[i].direction;
5583 boolean is_backside = object_mapping[i].is_backside;
5584 boolean action_removing = (action == ACTION_DIGGING ||
5585 action == ACTION_SNAPPING ||
5586 action == ACTION_COLLECTING);
5587 boolean action_exploding = ((action == ACTION_EXPLODING ||
5588 action == ACTION_SMASHED_BY_ROCK ||
5589 action == ACTION_SMASHED_BY_SPRING) &&
5590 element != EL_DIAMOND);
5591 boolean action_active = (action == ACTION_ACTIVE);
5592 boolean action_other = (action == ACTION_OTHER);
5594 for (j = 0; j < 8; j++)
5596 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5597 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5599 i == Xdrip_stretch ? element :
5600 i == Xdrip_stretchB ? element :
5601 i == Ydrip_s1 ? element :
5602 i == Ydrip_s1B ? element :
5603 i == Xball_1B ? element :
5604 i == Xball_2 ? element :
5605 i == Xball_2B ? element :
5606 i == Yball_eat ? element :
5607 i == Ykey_1_eat ? element :
5608 i == Ykey_2_eat ? element :
5609 i == Ykey_3_eat ? element :
5610 i == Ykey_4_eat ? element :
5611 i == Ykey_5_eat ? element :
5612 i == Ykey_6_eat ? element :
5613 i == Ykey_7_eat ? element :
5614 i == Ykey_8_eat ? element :
5615 i == Ylenses_eat ? element :
5616 i == Ymagnify_eat ? element :
5617 i == Ygrass_eat ? element :
5618 i == Ydirt_eat ? element :
5619 i == Yemerald_stone ? EL_EMERALD :
5620 i == Ydiamond_stone ? EL_ROCK :
5621 i == Xsand_stonein_1 ? element :
5622 i == Xsand_stonein_2 ? element :
5623 i == Xsand_stonein_3 ? element :
5624 i == Xsand_stonein_4 ? element :
5625 is_backside ? EL_EMPTY :
5626 action_removing ? EL_EMPTY :
5628 int effective_action = (j < 7 ? action :
5629 i == Xdrip_stretch ? action :
5630 i == Xdrip_stretchB ? action :
5631 i == Ydrip_s1 ? action :
5632 i == Ydrip_s1B ? action :
5633 i == Xball_1B ? action :
5634 i == Xball_2 ? action :
5635 i == Xball_2B ? action :
5636 i == Yball_eat ? action :
5637 i == Ykey_1_eat ? action :
5638 i == Ykey_2_eat ? action :
5639 i == Ykey_3_eat ? action :
5640 i == Ykey_4_eat ? action :
5641 i == Ykey_5_eat ? action :
5642 i == Ykey_6_eat ? action :
5643 i == Ykey_7_eat ? action :
5644 i == Ykey_8_eat ? action :
5645 i == Ylenses_eat ? action :
5646 i == Ymagnify_eat ? action :
5647 i == Ygrass_eat ? action :
5648 i == Ydirt_eat ? action :
5649 i == Xsand_stonein_1 ? action :
5650 i == Xsand_stonein_2 ? action :
5651 i == Xsand_stonein_3 ? action :
5652 i == Xsand_stonein_4 ? action :
5653 i == Xsand_stoneout_1 ? action :
5654 i == Xsand_stoneout_2 ? action :
5655 i == Xboom_android ? ACTION_EXPLODING :
5656 action_exploding ? ACTION_EXPLODING :
5657 action_active ? action :
5658 action_other ? action :
5660 int graphic = (el_act_dir2img(effective_element, effective_action,
5662 int crumbled = (el_act_dir2crm(effective_element, effective_action,
5664 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5665 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5666 boolean has_action_graphics = (graphic != base_graphic);
5667 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5668 struct GraphicInfo *g = &graphic_info[graphic];
5669 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5672 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5673 boolean special_animation = (action != ACTION_DEFAULT &&
5674 g->anim_frames == 3 &&
5675 g->anim_delay == 2 &&
5676 g->anim_mode & ANIM_LINEAR);
5677 int sync_frame = (i == Xdrip_stretch ? 7 :
5678 i == Xdrip_stretchB ? 7 :
5679 i == Ydrip_s2 ? j + 8 :
5680 i == Ydrip_s2B ? j + 8 :
5689 i == Xfake_acid_1 ? 0 :
5690 i == Xfake_acid_2 ? 10 :
5691 i == Xfake_acid_3 ? 20 :
5692 i == Xfake_acid_4 ? 30 :
5693 i == Xfake_acid_5 ? 40 :
5694 i == Xfake_acid_6 ? 50 :
5695 i == Xfake_acid_7 ? 60 :
5696 i == Xfake_acid_8 ? 70 :
5698 i == Xball_2B ? j + 8 :
5699 i == Yball_eat ? j + 1 :
5700 i == Ykey_1_eat ? j + 1 :
5701 i == Ykey_2_eat ? j + 1 :
5702 i == Ykey_3_eat ? j + 1 :
5703 i == Ykey_4_eat ? j + 1 :
5704 i == Ykey_5_eat ? j + 1 :
5705 i == Ykey_6_eat ? j + 1 :
5706 i == Ykey_7_eat ? j + 1 :
5707 i == Ykey_8_eat ? j + 1 :
5708 i == Ylenses_eat ? j + 1 :
5709 i == Ymagnify_eat ? j + 1 :
5710 i == Ygrass_eat ? j + 1 :
5711 i == Ydirt_eat ? j + 1 :
5712 i == Xamoeba_1 ? 0 :
5713 i == Xamoeba_2 ? 1 :
5714 i == Xamoeba_3 ? 2 :
5715 i == Xamoeba_4 ? 3 :
5716 i == Xamoeba_5 ? 0 :
5717 i == Xamoeba_6 ? 1 :
5718 i == Xamoeba_7 ? 2 :
5719 i == Xamoeba_8 ? 3 :
5720 i == Xexit_2 ? j + 8 :
5721 i == Xexit_3 ? j + 16 :
5722 i == Xdynamite_1 ? 0 :
5723 i == Xdynamite_2 ? 8 :
5724 i == Xdynamite_3 ? 16 :
5725 i == Xdynamite_4 ? 24 :
5726 i == Xsand_stonein_1 ? j + 1 :
5727 i == Xsand_stonein_2 ? j + 9 :
5728 i == Xsand_stonein_3 ? j + 17 :
5729 i == Xsand_stonein_4 ? j + 25 :
5730 i == Xsand_stoneout_1 && j == 0 ? 0 :
5731 i == Xsand_stoneout_1 && j == 1 ? 0 :
5732 i == Xsand_stoneout_1 && j == 2 ? 1 :
5733 i == Xsand_stoneout_1 && j == 3 ? 2 :
5734 i == Xsand_stoneout_1 && j == 4 ? 2 :
5735 i == Xsand_stoneout_1 && j == 5 ? 3 :
5736 i == Xsand_stoneout_1 && j == 6 ? 4 :
5737 i == Xsand_stoneout_1 && j == 7 ? 4 :
5738 i == Xsand_stoneout_2 && j == 0 ? 5 :
5739 i == Xsand_stoneout_2 && j == 1 ? 6 :
5740 i == Xsand_stoneout_2 && j == 2 ? 7 :
5741 i == Xsand_stoneout_2 && j == 3 ? 8 :
5742 i == Xsand_stoneout_2 && j == 4 ? 9 :
5743 i == Xsand_stoneout_2 && j == 5 ? 11 :
5744 i == Xsand_stoneout_2 && j == 6 ? 13 :
5745 i == Xsand_stoneout_2 && j == 7 ? 15 :
5746 i == Xboom_bug && j == 1 ? 2 :
5747 i == Xboom_bug && j == 2 ? 2 :
5748 i == Xboom_bug && j == 3 ? 4 :
5749 i == Xboom_bug && j == 4 ? 4 :
5750 i == Xboom_bug && j == 5 ? 2 :
5751 i == Xboom_bug && j == 6 ? 2 :
5752 i == Xboom_bug && j == 7 ? 0 :
5753 i == Xboom_bomb && j == 1 ? 2 :
5754 i == Xboom_bomb && j == 2 ? 2 :
5755 i == Xboom_bomb && j == 3 ? 4 :
5756 i == Xboom_bomb && j == 4 ? 4 :
5757 i == Xboom_bomb && j == 5 ? 2 :
5758 i == Xboom_bomb && j == 6 ? 2 :
5759 i == Xboom_bomb && j == 7 ? 0 :
5760 i == Xboom_android && j == 7 ? 6 :
5761 i == Xboom_1 && j == 1 ? 2 :
5762 i == Xboom_1 && j == 2 ? 2 :
5763 i == Xboom_1 && j == 3 ? 4 :
5764 i == Xboom_1 && j == 4 ? 4 :
5765 i == Xboom_1 && j == 5 ? 6 :
5766 i == Xboom_1 && j == 6 ? 6 :
5767 i == Xboom_1 && j == 7 ? 8 :
5768 i == Xboom_2 && j == 0 ? 8 :
5769 i == Xboom_2 && j == 1 ? 8 :
5770 i == Xboom_2 && j == 2 ? 10 :
5771 i == Xboom_2 && j == 3 ? 10 :
5772 i == Xboom_2 && j == 4 ? 10 :
5773 i == Xboom_2 && j == 5 ? 12 :
5774 i == Xboom_2 && j == 6 ? 12 :
5775 i == Xboom_2 && j == 7 ? 12 :
5776 special_animation && j == 4 ? 3 :
5777 effective_action != action ? 0 :
5781 Bitmap *debug_bitmap = g_em->bitmap;
5782 int debug_src_x = g_em->src_x;
5783 int debug_src_y = g_em->src_y;
5786 int frame = getAnimationFrame(g->anim_frames,
5789 g->anim_start_frame,
5792 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5793 g->double_movement && is_backside);
5795 g_em->bitmap = src_bitmap;
5796 g_em->src_x = src_x;
5797 g_em->src_y = src_y;
5798 g_em->src_offset_x = 0;
5799 g_em->src_offset_y = 0;
5800 g_em->dst_offset_x = 0;
5801 g_em->dst_offset_y = 0;
5802 g_em->width = TILEX;
5803 g_em->height = TILEY;
5805 g_em->crumbled_bitmap = NULL;
5806 g_em->crumbled_src_x = 0;
5807 g_em->crumbled_src_y = 0;
5808 g_em->crumbled_border_size = 0;
5810 g_em->has_crumbled_graphics = FALSE;
5811 g_em->preserve_background = FALSE;
5814 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5815 printf("::: empty crumbled: %d [%s], %d, %d\n",
5816 effective_element, element_info[effective_element].token_name,
5817 effective_action, direction);
5820 /* if element can be crumbled, but certain action graphics are just empty
5821 space (like snapping sand with the original R'n'D graphics), do not
5822 treat these empty space graphics as crumbled graphics in EMC engine */
5823 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5825 getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5827 g_em->has_crumbled_graphics = TRUE;
5828 g_em->crumbled_bitmap = src_bitmap;
5829 g_em->crumbled_src_x = src_x;
5830 g_em->crumbled_src_y = src_y;
5831 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5835 if (element == EL_ROCK &&
5836 effective_action == ACTION_FILLING)
5837 printf("::: has_action_graphics == %d\n", has_action_graphics);
5840 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5841 effective_action == ACTION_MOVING ||
5842 effective_action == ACTION_PUSHING ||
5843 effective_action == ACTION_EATING)) ||
5844 (!has_action_graphics && (effective_action == ACTION_FILLING ||
5845 effective_action == ACTION_EMPTYING)))
5848 (effective_action == ACTION_FALLING ||
5849 effective_action == ACTION_FILLING ||
5850 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5851 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5852 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
5853 int num_steps = (i == Ydrip_s1 ? 16 :
5854 i == Ydrip_s1B ? 16 :
5855 i == Ydrip_s2 ? 16 :
5856 i == Ydrip_s2B ? 16 :
5857 i == Xsand_stonein_1 ? 32 :
5858 i == Xsand_stonein_2 ? 32 :
5859 i == Xsand_stonein_3 ? 32 :
5860 i == Xsand_stonein_4 ? 32 :
5861 i == Xsand_stoneout_1 ? 16 :
5862 i == Xsand_stoneout_2 ? 16 : 8);
5863 int cx = ABS(dx) * (TILEX / num_steps);
5864 int cy = ABS(dy) * (TILEY / num_steps);
5865 int step_frame = (i == Ydrip_s2 ? j + 8 :
5866 i == Ydrip_s2B ? j + 8 :
5867 i == Xsand_stonein_2 ? j + 8 :
5868 i == Xsand_stonein_3 ? j + 16 :
5869 i == Xsand_stonein_4 ? j + 24 :
5870 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5871 int step = (is_backside ? step_frame : num_steps - step_frame);
5873 if (is_backside) /* tile where movement starts */
5875 if (dx < 0 || dy < 0)
5877 g_em->src_offset_x = cx * step;
5878 g_em->src_offset_y = cy * step;
5882 g_em->dst_offset_x = cx * step;
5883 g_em->dst_offset_y = cy * step;
5886 else /* tile where movement ends */
5888 if (dx < 0 || dy < 0)
5890 g_em->dst_offset_x = cx * step;
5891 g_em->dst_offset_y = cy * step;
5895 g_em->src_offset_x = cx * step;
5896 g_em->src_offset_y = cy * step;
5900 g_em->width = TILEX - cx * step;
5901 g_em->height = TILEY - cy * step;
5904 /* create unique graphic identifier to decide if tile must be redrawn */
5905 /* bit 31 - 16 (16 bit): EM style graphic
5906 bit 15 - 12 ( 4 bit): EM style frame
5907 bit 11 - 6 ( 6 bit): graphic width
5908 bit 5 - 0 ( 6 bit): graphic height */
5909 g_em->unique_identifier =
5910 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5914 /* skip check for EMC elements not contained in original EMC artwork */
5915 if (element == EL_EMC_FAKE_ACID)
5918 if (g_em->bitmap != debug_bitmap ||
5919 g_em->src_x != debug_src_x ||
5920 g_em->src_y != debug_src_y ||
5921 g_em->src_offset_x != 0 ||
5922 g_em->src_offset_y != 0 ||
5923 g_em->dst_offset_x != 0 ||
5924 g_em->dst_offset_y != 0 ||
5925 g_em->width != TILEX ||
5926 g_em->height != TILEY)
5928 static int last_i = -1;
5936 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5937 i, element, element_info[element].token_name,
5938 element_action_info[effective_action].suffix, direction);
5940 if (element != effective_element)
5941 printf(" [%d ('%s')]",
5943 element_info[effective_element].token_name);
5947 if (g_em->bitmap != debug_bitmap)
5948 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5949 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5951 if (g_em->src_x != debug_src_x ||
5952 g_em->src_y != debug_src_y)
5953 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5954 j, (is_backside ? 'B' : 'F'),
5955 g_em->src_x, g_em->src_y,
5956 g_em->src_x / 32, g_em->src_y / 32,
5957 debug_src_x, debug_src_y,
5958 debug_src_x / 32, debug_src_y / 32);
5960 if (g_em->src_offset_x != 0 ||
5961 g_em->src_offset_y != 0 ||
5962 g_em->dst_offset_x != 0 ||
5963 g_em->dst_offset_y != 0)
5964 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5966 g_em->src_offset_x, g_em->src_offset_y,
5967 g_em->dst_offset_x, g_em->dst_offset_y);
5969 if (g_em->width != TILEX ||
5970 g_em->height != TILEY)
5971 printf(" %d (%d): size %d,%d should be %d,%d\n",
5973 g_em->width, g_em->height, TILEX, TILEY);
5975 num_em_gfx_errors++;
5982 for (i = 0; i < TILE_MAX; i++)
5984 for (j = 0; j < 8; j++)
5986 int element = object_mapping[i].element_rnd;
5987 int action = object_mapping[i].action;
5988 int direction = object_mapping[i].direction;
5989 boolean is_backside = object_mapping[i].is_backside;
5990 int graphic_action = el_act_dir2img(element, action, direction);
5991 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5993 if ((action == ACTION_SMASHED_BY_ROCK ||
5994 action == ACTION_SMASHED_BY_SPRING ||
5995 action == ACTION_EATING) &&
5996 graphic_action == graphic_default)
5998 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
5999 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6000 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
6001 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6004 /* no separate animation for "smashed by rock" -- use rock instead */
6005 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6006 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6008 g_em->bitmap = g_xx->bitmap;
6009 g_em->src_x = g_xx->src_x;
6010 g_em->src_y = g_xx->src_y;
6011 g_em->src_offset_x = g_xx->src_offset_x;
6012 g_em->src_offset_y = g_xx->src_offset_y;
6013 g_em->dst_offset_x = g_xx->dst_offset_x;
6014 g_em->dst_offset_y = g_xx->dst_offset_y;
6015 g_em->width = g_xx->width;
6016 g_em->height = g_xx->height;
6017 g_em->unique_identifier = g_xx->unique_identifier;
6020 g_em->preserve_background = TRUE;
6025 for (p = 0; p < MAX_PLAYERS; p++)
6027 for (i = 0; i < SPR_MAX; i++)
6029 int element = player_mapping[p][i].element_rnd;
6030 int action = player_mapping[p][i].action;
6031 int direction = player_mapping[p][i].direction;
6033 for (j = 0; j < 8; j++)
6035 int effective_element = element;
6036 int effective_action = action;
6037 int graphic = (direction == MV_NONE ?
6038 el_act2img(effective_element, effective_action) :
6039 el_act_dir2img(effective_element, effective_action,
6041 struct GraphicInfo *g = &graphic_info[graphic];
6042 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6048 Bitmap *debug_bitmap = g_em->bitmap;
6049 int debug_src_x = g_em->src_x;
6050 int debug_src_y = g_em->src_y;
6053 int frame = getAnimationFrame(g->anim_frames,
6056 g->anim_start_frame,
6059 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6061 g_em->bitmap = src_bitmap;
6062 g_em->src_x = src_x;
6063 g_em->src_y = src_y;
6064 g_em->src_offset_x = 0;
6065 g_em->src_offset_y = 0;
6066 g_em->dst_offset_x = 0;
6067 g_em->dst_offset_y = 0;
6068 g_em->width = TILEX;
6069 g_em->height = TILEY;
6073 /* skip check for EMC elements not contained in original EMC artwork */
6074 if (element == EL_PLAYER_3 ||
6075 element == EL_PLAYER_4)
6078 if (g_em->bitmap != debug_bitmap ||
6079 g_em->src_x != debug_src_x ||
6080 g_em->src_y != debug_src_y)
6082 static int last_i = -1;
6090 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6091 p, i, element, element_info[element].token_name,
6092 element_action_info[effective_action].suffix, direction);
6094 if (element != effective_element)
6095 printf(" [%d ('%s')]",
6097 element_info[effective_element].token_name);
6101 if (g_em->bitmap != debug_bitmap)
6102 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
6103 j, (int)(g_em->bitmap), (int)(debug_bitmap));
6105 if (g_em->src_x != debug_src_x ||
6106 g_em->src_y != debug_src_y)
6107 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6109 g_em->src_x, g_em->src_y,
6110 g_em->src_x / 32, g_em->src_y / 32,
6111 debug_src_x, debug_src_y,
6112 debug_src_x / 32, debug_src_y / 32);
6114 num_em_gfx_errors++;
6124 printf("::: [%d errors found]\n", num_em_gfx_errors);
6130 void PlayMenuSound()
6132 int sound = menu.sound[game_status];
6134 if (sound == SND_UNDEFINED)
6137 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6138 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6141 if (IS_LOOP_SOUND(sound))
6142 PlaySoundLoop(sound);
6147 void PlayMenuSoundStereo(int sound, int stereo_position)
6149 if (sound == SND_UNDEFINED)
6152 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6153 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6156 if (IS_LOOP_SOUND(sound))
6157 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6159 PlaySoundStereo(sound, stereo_position);
6162 void PlayMenuSoundIfLoop()
6164 int sound = menu.sound[game_status];
6166 if (sound == SND_UNDEFINED)
6169 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6170 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6173 if (IS_LOOP_SOUND(sound))
6174 PlaySoundLoop(sound);
6177 void PlayMenuMusic()
6179 int music = menu.music[game_status];
6181 if (music == MUS_UNDEFINED)
6187 void ToggleFullscreenIfNeeded()
6189 boolean change_fullscreen = (setup.fullscreen !=
6190 video.fullscreen_enabled);
6191 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6192 !strEqual(setup.fullscreen_mode,
6193 video.fullscreen_mode_current));
6195 if (!video.fullscreen_available)
6199 if (change_fullscreen || change_fullscreen_mode)
6201 if (setup.fullscreen != video.fullscreen_enabled ||
6202 setup.fullscreen_mode != video.fullscreen_mode_current)
6205 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6207 /* save backbuffer content which gets lost when toggling fullscreen mode */
6208 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6211 if (change_fullscreen_mode)
6213 if (setup.fullscreen && video.fullscreen_enabled)
6216 /* keep fullscreen, but change fullscreen mode (screen resolution) */
6218 /* (this is now set in sdl.c) */
6220 video.fullscreen_mode_current = setup.fullscreen_mode;
6222 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
6225 /* toggle fullscreen */
6226 ChangeVideoModeIfNeeded(setup.fullscreen);
6228 setup.fullscreen = video.fullscreen_enabled;
6230 /* restore backbuffer content from temporary backbuffer backup bitmap */
6231 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6233 FreeBitmap(tmp_backbuffer);
6236 /* update visible window/screen */
6237 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6239 redraw_mask = REDRAW_ALL;