1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES 0
25 #define TOOL_CTRL_ID_NO 1
26 #define TOOL_CTRL_ID_CONFIRM 2
27 #define TOOL_CTRL_ID_PLAYER_1 3
28 #define TOOL_CTRL_ID_PLAYER_2 4
29 #define TOOL_CTRL_ID_PLAYER_3 5
30 #define TOOL_CTRL_ID_PLAYER_4 6
32 #define NUM_TOOL_BUTTONS 7
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
37 static int el_act_dir2crm(int, int, int);
38 static int el_act2crm(int, int);
40 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
41 static int request_gadget_id = -1;
43 static char *print_if_not_empty(int element)
45 static char *s = NULL;
46 char *token_name = element_info[element].token_name;
51 s = checked_malloc(strlen(token_name) + 10 + 1);
53 if (element != EL_EMPTY)
54 sprintf(s, "%d\t['%s']", element, token_name);
56 sprintf(s, "%d", element);
61 void DumpTile(int x, int y)
67 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
70 if (!IN_LEV_FIELD(x, y))
72 printf("(not in level field)\n");
78 printf(" Feld: %d\t['%s']\n", Feld[x][y],
79 element_info[Feld[x][y]].token_name);
80 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
81 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
82 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
83 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
84 printf(" MovPos: %d\n", MovPos[x][y]);
85 printf(" MovDir: %d\n", MovDir[x][y]);
86 printf(" MovDelay: %d\n", MovDelay[x][y]);
87 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
88 printf(" GfxElement: %d\n", GfxElement[x][y]);
89 printf(" GfxAction: %d\n", GfxAction[x][y]);
90 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
94 void SetDrawtoField(int mode)
96 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
107 drawto_field = fieldbuffer;
109 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
115 BX2 = SCR_FIELDX - 1;
116 BY2 = SCR_FIELDY - 1;
120 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
124 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
126 if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
132 width = gfx.sxsize + 2 * TILEX;
133 height = gfx.sysize + 2 * TILEY;
136 if (force_redraw || setup.direct_draw)
139 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
140 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
142 if (setup.direct_draw)
143 SetDrawtoField(DRAW_BACKBUFFER);
145 for (xx = BX1; xx <= BX2; xx++)
146 for (yy = BY1; yy <= BY2; yy++)
147 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
148 DrawScreenField(xx, yy);
151 if (setup.direct_draw)
152 SetDrawtoField(DRAW_DIRECT);
155 if (setup.soft_scrolling)
157 int fx = FX, fy = FY;
159 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
160 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
162 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
166 BlitBitmap(drawto, window, x, y, width, height, x, y);
172 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
174 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
175 redraw_mask &= ~REDRAW_MAIN;
177 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
178 redraw_mask |= REDRAW_FIELD;
180 if (redraw_mask & REDRAW_FIELD)
181 redraw_mask &= ~REDRAW_TILES;
183 if (redraw_mask == REDRAW_NONE)
186 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
188 static boolean last_frame_skipped = FALSE;
189 boolean skip_even_when_not_scrolling = TRUE;
190 boolean just_scrolling = (ScreenMovDir != 0);
191 boolean verbose = FALSE;
193 if (global.fps_slowdown_factor > 1 &&
194 (FrameCounter % global.fps_slowdown_factor) &&
195 (just_scrolling || skip_even_when_not_scrolling))
197 redraw_mask &= ~REDRAW_MAIN;
199 last_frame_skipped = TRUE;
202 printf("FRAME SKIPPED\n");
206 if (last_frame_skipped)
207 redraw_mask |= REDRAW_FIELD;
209 last_frame_skipped = FALSE;
212 printf("frame not skipped\n");
216 /* synchronize X11 graphics at this point; if we would synchronize the
217 display immediately after the buffer switching (after the XFlush),
218 this could mean that we have to wait for the graphics to complete,
219 although we could go on doing calculations for the next frame */
223 if (redraw_mask & REDRAW_ALL)
225 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
229 if (redraw_mask & REDRAW_FIELD)
231 if (game_status != GAME_MODE_PLAYING ||
232 redraw_mask & REDRAW_FROM_BACKBUFFER)
234 BlitBitmap(backbuffer, window,
235 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
239 int fx = FX, fy = FY;
241 if (setup.soft_scrolling)
243 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
244 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
247 if (setup.soft_scrolling ||
248 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
249 ABS(ScreenMovPos) == ScrollStepSize ||
250 redraw_tiles > REDRAWTILES_THRESHOLD)
252 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
256 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
258 (setup.soft_scrolling ?
259 "setup.soft_scrolling" :
260 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
261 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
262 ABS(ScreenGfxPos) == ScrollStepSize ?
263 "ABS(ScreenGfxPos) == ScrollStepSize" :
264 "redraw_tiles > REDRAWTILES_THRESHOLD"));
270 redraw_mask &= ~REDRAW_MAIN;
273 if (redraw_mask & REDRAW_DOORS)
275 if (redraw_mask & REDRAW_DOOR_1)
276 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
278 if (redraw_mask & REDRAW_DOOR_2)
281 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
283 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
287 if (redraw_mask & REDRAW_VIDEO_1)
288 BlitBitmap(backbuffer, window,
289 VX + VIDEO_DISPLAY1_XPOS, VY + VIDEO_DISPLAY1_YPOS,
290 VIDEO_DISPLAY_XSIZE, VIDEO_DISPLAY_YSIZE,
291 VX + VIDEO_DISPLAY1_XPOS, VY + VIDEO_DISPLAY1_YPOS);
292 if (redraw_mask & REDRAW_VIDEO_2)
293 BlitBitmap(backbuffer, window,
294 VX + VIDEO_DISPLAY2_XPOS, VY + VIDEO_DISPLAY2_YPOS,
295 VIDEO_DISPLAY_XSIZE, VIDEO_DISPLAY_YSIZE,
296 VX + VIDEO_DISPLAY2_XPOS, VY + VIDEO_DISPLAY2_YPOS);
297 if (redraw_mask & REDRAW_VIDEO_3)
298 BlitBitmap(backbuffer, window,
299 VX + VIDEO_CONTROL_XPOS, VY + VIDEO_CONTROL_YPOS,
300 VIDEO_CONTROL_XSIZE, VIDEO_CONTROL_YSIZE,
301 VX + VIDEO_CONTROL_XPOS, VY + VIDEO_CONTROL_YPOS);
306 if (redraw_mask & REDRAW_DOOR_3)
307 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
309 redraw_mask &= ~REDRAW_DOORS;
312 if (redraw_mask & REDRAW_MICROLEVEL)
314 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
315 SX, SY + 10 * TILEY);
317 redraw_mask &= ~REDRAW_MICROLEVEL;
320 if (redraw_mask & REDRAW_TILES)
322 for (x = 0; x < SCR_FIELDX; x++)
323 for (y = 0 ; y < SCR_FIELDY; y++)
324 if (redraw[redraw_x1 + x][redraw_y1 + y])
325 BlitBitmap(buffer, window,
326 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
327 SX + x * TILEX, SY + y * TILEY);
330 if (redraw_mask & REDRAW_FPS) /* display frames per second */
335 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
336 if (!global.fps_slowdown)
339 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
340 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
345 for (x = 0; x < MAX_BUF_XSIZE; x++)
346 for (y = 0; y < MAX_BUF_YSIZE; y++)
349 redraw_mask = REDRAW_NONE;
355 long fading_delay = 300;
357 if (setup.fading && (redraw_mask & REDRAW_FIELD))
364 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
367 for (i = 0; i < 2 * FULL_SYSIZE; i++)
369 for (y = 0; y < FULL_SYSIZE; y++)
371 BlitBitmap(backbuffer, window,
372 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
380 for (i = 1; i < FULL_SYSIZE; i+=2)
381 BlitBitmap(backbuffer, window,
382 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
388 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
389 BlitBitmapMasked(backbuffer, window,
390 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
395 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
396 BlitBitmapMasked(backbuffer, window,
397 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
402 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
403 BlitBitmapMasked(backbuffer, window,
404 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
409 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
410 BlitBitmapMasked(backbuffer, window,
411 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
416 redraw_mask &= ~REDRAW_MAIN;
423 void SetMainBackgroundImage(int graphic)
425 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
426 graphic_info[graphic].bitmap ?
427 graphic_info[graphic].bitmap :
428 graphic_info[IMG_BACKGROUND].bitmap);
431 void SetDoorBackgroundImage(int graphic)
433 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
434 graphic_info[graphic].bitmap ?
435 graphic_info[graphic].bitmap :
436 graphic_info[IMG_BACKGROUND].bitmap);
439 void DrawBackground(int dest_x, int dest_y, int width, int height)
441 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
443 redraw_mask |= REDRAW_FIELD;
448 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
450 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
452 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
453 SetDrawtoField(DRAW_BUFFERED);
456 SetDrawtoField(DRAW_BACKBUFFER);
458 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
460 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
461 SetDrawtoField(DRAW_DIRECT);
465 void MarkTileDirty(int x, int y)
467 int xx = redraw_x1 + x;
468 int yy = redraw_y1 + y;
473 redraw[xx][yy] = TRUE;
474 redraw_mask |= REDRAW_TILES;
477 void SetBorderElement()
481 BorderElement = EL_EMPTY;
483 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
485 for (x = 0; x < lev_fieldx; x++)
487 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
488 BorderElement = EL_STEELWALL;
490 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
496 void SetRandomAnimationValue(int x, int y)
498 gfx.anim_random_frame = GfxRandom[x][y];
501 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
503 /* animation synchronized with global frame counter, not move position */
504 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
505 sync_frame = FrameCounter;
507 return getAnimationFrame(graphic_info[graphic].anim_frames,
508 graphic_info[graphic].anim_delay,
509 graphic_info[graphic].anim_mode,
510 graphic_info[graphic].anim_start_frame,
514 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
515 int graphic, int sync_frame, int mask_mode)
517 int frame = getGraphicAnimationFrame(graphic, sync_frame);
519 if (mask_mode == USE_MASKING)
520 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
522 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
525 inline void DrawGraphicAnimation(int x, int y, int graphic)
527 int lx = LEVELX(x), ly = LEVELY(y);
529 if (!IN_SCR_FIELD(x, y))
532 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
533 graphic, GfxFrame[lx][ly], NO_MASKING);
537 void DrawLevelGraphicAnimation(int x, int y, int graphic)
539 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
542 void DrawLevelElementAnimation(int x, int y, int element)
545 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
547 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
549 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
553 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
555 int sx = SCREENX(x), sy = SCREENY(y);
557 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
560 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
563 DrawGraphicAnimation(sx, sy, graphic);
565 if (GFX_CRUMBLED(Feld[x][y]))
566 DrawLevelFieldCrumbledSand(x, y);
569 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
571 int sx = SCREENX(x), sy = SCREENY(y);
574 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
577 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
579 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
582 DrawGraphicAnimation(sx, sy, graphic);
584 if (GFX_CRUMBLED(element))
585 DrawLevelFieldCrumbledSand(x, y);
588 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
590 if (player->use_murphy_graphic)
592 /* this works only because currently only one player can be "murphy" ... */
593 static int last_horizontal_dir = MV_LEFT;
594 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
596 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
597 last_horizontal_dir = move_dir;
599 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
601 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
603 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
609 return el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
612 static boolean equalGraphics(int graphic1, int graphic2)
614 struct GraphicInfo *g1 = &graphic_info[graphic1];
615 struct GraphicInfo *g2 = &graphic_info[graphic2];
617 return (g1->bitmap == g2->bitmap &&
618 g1->src_x == g2->src_x &&
619 g1->src_y == g2->src_y &&
620 g1->anim_frames == g2->anim_frames &&
621 g1->anim_delay == g2->anim_delay &&
622 g1->anim_mode == g2->anim_mode);
625 void DrawAllPlayers()
629 for (i = 0; i < MAX_PLAYERS; i++)
630 if (stored_player[i].active)
631 DrawPlayer(&stored_player[i]);
634 void DrawPlayerField(int x, int y)
636 if (!IS_PLAYER(x, y))
639 DrawPlayer(PLAYERINFO(x, y));
642 void DrawPlayer(struct PlayerInfo *player)
646 int move_dir = player->MovDir;
648 int last_jx = player->last_jx;
649 int last_jy = player->last_jy;
650 int next_jx = jx + (jx - last_jx);
651 int next_jy = jy + (jy - last_jy);
652 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
654 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
655 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
656 int last_jx = (player->is_moving ? jx - dx : jx);
657 int last_jy = (player->is_moving ? jy - dy : jy);
658 int next_jx = jx + dx;
659 int next_jy = jy + dy;
660 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
662 int sx = SCREENX(jx), sy = SCREENY(jy);
663 int sxx = 0, syy = 0;
664 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
666 int action = ACTION_DEFAULT;
667 int last_player_graphic = getPlayerGraphic(player, move_dir);
668 int last_player_frame = player->Frame;
671 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
675 if (!IN_LEV_FIELD(jx, jy))
677 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
678 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
679 printf("DrawPlayerField(): This should never happen!\n");
684 if (element == EL_EXPLOSION)
687 action = (player->is_pushing ? ACTION_PUSHING :
688 player->is_digging ? ACTION_DIGGING :
689 player->is_collecting ? ACTION_COLLECTING :
690 player->is_moving ? ACTION_MOVING :
691 player->is_snapping ? ACTION_SNAPPING :
692 player->is_dropping ? ACTION_DROPPING :
693 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
695 InitPlayerGfxAnimation(player, action, move_dir);
697 /* ----------------------------------------------------------------------- */
698 /* draw things in the field the player is leaving, if needed */
699 /* ----------------------------------------------------------------------- */
702 if (player->is_moving)
704 if (player_is_moving)
707 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
709 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
711 if (last_element == EL_DYNAMITE_ACTIVE ||
712 last_element == EL_SP_DISK_RED_ACTIVE)
713 DrawDynamite(last_jx, last_jy);
715 DrawLevelFieldThruMask(last_jx, last_jy);
717 else if (last_element == EL_DYNAMITE_ACTIVE ||
718 last_element == EL_SP_DISK_RED_ACTIVE)
719 DrawDynamite(last_jx, last_jy);
721 DrawLevelField(last_jx, last_jy);
723 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
724 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
727 if (!IN_SCR_FIELD(sx, sy))
730 if (setup.direct_draw)
731 SetDrawtoField(DRAW_BUFFERED);
733 /* ----------------------------------------------------------------------- */
734 /* draw things behind the player, if needed */
735 /* ----------------------------------------------------------------------- */
738 DrawLevelElement(jx, jy, Back[jx][jy]);
739 else if (IS_ACTIVE_BOMB(element))
740 DrawLevelElement(jx, jy, EL_EMPTY);
743 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
745 if (GFX_CRUMBLED(GfxElement[jx][jy]))
746 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
749 int old_element = GfxElement[jx][jy];
750 int old_graphic = el_act_dir2img(old_element, action, move_dir);
751 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
753 DrawGraphic(sx, sy, old_graphic, frame);
758 GfxElement[jx][jy] = EL_UNDEFINED;
760 DrawLevelField(jx, jy);
764 /* ----------------------------------------------------------------------- */
765 /* draw player himself */
766 /* ----------------------------------------------------------------------- */
770 graphic = getPlayerGraphic(player, move_dir);
772 /* in the case of changed player action or direction, prevent the current
773 animation frame from being restarted for identical animations */
774 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
775 player->Frame = last_player_frame;
779 if (player->use_murphy_graphic)
781 static int last_horizontal_dir = MV_LEFT;
783 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
784 last_horizontal_dir = move_dir;
786 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
788 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
790 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
792 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
796 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
800 frame = getGraphicAnimationFrame(graphic, player->Frame);
804 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
805 sxx = player->GfxPos;
807 syy = player->GfxPos;
810 if (!setup.soft_scrolling && ScreenMovPos)
813 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
815 if (SHIELD_ON(player))
817 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
818 IMG_SHIELD_NORMAL_ACTIVE);
819 int frame = getGraphicAnimationFrame(graphic, -1);
821 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
824 /* ----------------------------------------------------------------------- */
825 /* draw things the player is pushing, if needed */
826 /* ----------------------------------------------------------------------- */
829 printf("::: %d, %d [%d, %d] [%d]\n",
830 player->is_pushing, player_is_moving, player->GfxAction,
831 player->is_moving, player_is_moving);
835 if (player->is_pushing && player->is_moving)
837 if (player->is_pushing && player_is_moving)
840 int px = SCREENX(next_jx), py = SCREENY(next_jy);
842 if (Back[next_jx][next_jy])
843 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
845 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
846 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
850 int element = MovingOrBlocked2Element(next_jx, next_jy);
851 int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
853 int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
855 int frame = getGraphicAnimationFrame(graphic, player->Frame);
858 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
859 NO_CUTTING, NO_MASKING);
863 /* ----------------------------------------------------------------------- */
864 /* draw things in front of player (active dynamite or dynabombs) */
865 /* ----------------------------------------------------------------------- */
867 if (IS_ACTIVE_BOMB(element))
869 graphic = el2img(element);
870 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
872 if (game.emulation == EMU_SUPAPLEX)
873 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
875 DrawGraphicThruMask(sx, sy, graphic, frame);
878 if (player_is_moving && last_element == EL_EXPLOSION)
880 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
881 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
882 int phase = ExplodePhase[last_jx][last_jy] - 1;
883 int frame = getGraphicAnimationFrame(graphic, phase - delay);
886 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
889 /* ----------------------------------------------------------------------- */
890 /* draw elements the player is just walking/passing through/under */
891 /* ----------------------------------------------------------------------- */
893 if (player_is_moving)
895 /* handle the field the player is leaving ... */
896 if (IS_ACCESSIBLE_INSIDE(last_element))
897 DrawLevelField(last_jx, last_jy);
898 else if (IS_ACCESSIBLE_UNDER(last_element))
899 DrawLevelFieldThruMask(last_jx, last_jy);
903 /* do not redraw accessible elements if the player is just pushing them */
904 if (!player_is_moving || !player->is_pushing)
906 /* ... and the field the player is entering */
907 if (IS_ACCESSIBLE_INSIDE(element))
908 DrawLevelField(jx, jy);
909 else if (IS_ACCESSIBLE_UNDER(element))
910 DrawLevelFieldThruMask(jx, jy);
916 /* !!! I have forgotton what this should be good for !!! */
917 /* !!! causes player being visible when pushing from within tubes !!! */
918 if (!player->is_pushing)
921 /* ... and the field the player is entering */
922 if (IS_ACCESSIBLE_INSIDE(element))
923 DrawLevelField(jx, jy);
924 else if (IS_ACCESSIBLE_UNDER(element))
925 DrawLevelFieldThruMask(jx, jy);
929 if (setup.direct_draw)
931 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
932 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
933 int x_size = TILEX * (1 + ABS(jx - last_jx));
934 int y_size = TILEY * (1 + ABS(jy - last_jy));
936 BlitBitmap(drawto_field, window,
937 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
938 SetDrawtoField(DRAW_DIRECT);
941 MarkTileDirty(sx, sy);
944 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
946 struct GraphicInfo *g = &graphic_info[graphic];
950 if (g->offset_y == 0) /* frames are ordered horizontally */
952 int max_width = g->anim_frames_per_line * g->width;
954 *x = (g->src_x + frame * g->offset_x) % max_width;
955 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
957 else if (g->offset_x == 0) /* frames are ordered vertically */
959 int max_height = g->anim_frames_per_line * g->height;
961 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
962 *y = (g->src_y + frame * g->offset_y) % max_height;
964 else /* frames are ordered diagonally */
966 *x = g->src_x + frame * g->offset_x;
967 *y = g->src_y + frame * g->offset_y;
971 void DrawGraphic(int x, int y, int graphic, int frame)
974 if (!IN_SCR_FIELD(x, y))
976 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
977 printf("DrawGraphic(): This should never happen!\n");
982 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
986 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
992 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
993 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
996 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
999 if (!IN_SCR_FIELD(x, y))
1001 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1002 printf("DrawGraphicThruMask(): This should never happen!\n");
1007 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1009 MarkTileDirty(x, y);
1012 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
1020 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1021 drawing_gc = src_bitmap->stored_clip_gc;
1023 GC drawing_gc = src_bitmap->stored_clip_gc;
1024 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1025 int src_x = graphic_info[graphic].src_x;
1026 int src_y = graphic_info[graphic].src_y;
1027 int offset_x = graphic_info[graphic].offset_x;
1028 int offset_y = graphic_info[graphic].offset_y;
1030 src_x += frame * offset_x;
1031 src_y += frame * offset_y;
1035 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1036 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1039 void DrawMiniGraphic(int x, int y, int graphic)
1041 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1042 MarkTileDirty(x / 2, y / 2);
1045 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1047 struct GraphicInfo *g = &graphic_info[graphic];
1048 int mini_startx = 0;
1049 int mini_starty = g->bitmap->height * 2 / 3;
1051 *bitmap = g->bitmap;
1052 *x = mini_startx + g->src_x / 2;
1053 *y = mini_starty + g->src_y / 2;
1056 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1061 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1062 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1065 void DrawGraphicShifted(int x, int y, int dx, int dy, int graphic, int frame,
1066 int cut_mode, int mask_mode)
1071 int width = TILEX, height = TILEY;
1077 DrawGraphic(x, y, graphic, frame);
1081 if (dx || dy) /* shifted graphic */
1083 if (x < BX1) /* object enters playfield from the left */
1090 else if (x > BX2) /* object enters playfield from the right */
1096 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1102 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1104 else if (dx) /* general horizontal movement */
1105 MarkTileDirty(x + SIGN(dx), y);
1107 if (y < BY1) /* object enters playfield from the top */
1109 if (cut_mode==CUT_BELOW) /* object completely above top border */
1117 else if (y > BY2) /* object enters playfield from the bottom */
1123 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1129 else if (dy > 0 && cut_mode == CUT_ABOVE)
1131 if (y == BY2) /* object completely above bottom border */
1137 MarkTileDirty(x, y + 1);
1138 } /* object leaves playfield to the bottom */
1139 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1141 else if (dy) /* general vertical movement */
1142 MarkTileDirty(x, y + SIGN(dy));
1146 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1148 src_bitmap = graphic_info[graphic].bitmap;
1149 src_x = graphic_info[graphic].src_x;
1150 src_y = graphic_info[graphic].src_y;
1151 offset_x = graphic_info[graphic].offset_x;
1152 offset_y = graphic_info[graphic].offset_y;
1154 src_x += frame * offset_x;
1155 src_y += frame * offset_y;
1158 drawing_gc = src_bitmap->stored_clip_gc;
1163 dest_x = FX + x * TILEX + dx;
1164 dest_y = FY + y * TILEY + dy;
1167 if (!IN_SCR_FIELD(x,y))
1169 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1170 printf("DrawGraphicShifted(): This should never happen!\n");
1175 if (mask_mode == USE_MASKING)
1177 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1178 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1182 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1185 MarkTileDirty(x, y);
1188 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1189 int frame, int cut_mode)
1191 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1194 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1195 int cut_mode, int mask_mode)
1197 int lx = LEVELX(x), ly = LEVELY(y);
1201 if (IN_LEV_FIELD(lx, ly))
1203 SetRandomAnimationValue(lx, ly);
1205 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1206 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1208 else /* border element */
1210 graphic = el2img(element);
1211 frame = getGraphicAnimationFrame(graphic, -1);
1214 if (element == EL_EXPANDABLE_WALL)
1216 boolean left_stopped = FALSE, right_stopped = FALSE;
1218 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1219 left_stopped = TRUE;
1220 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1221 right_stopped = TRUE;
1223 if (left_stopped && right_stopped)
1225 else if (left_stopped)
1227 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1228 frame = graphic_info[graphic].anim_frames - 1;
1230 else if (right_stopped)
1232 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1233 frame = graphic_info[graphic].anim_frames - 1;
1238 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1239 else if (mask_mode == USE_MASKING)
1240 DrawGraphicThruMask(x, y, graphic, frame);
1242 DrawGraphic(x, y, graphic, frame);
1245 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1246 int cut_mode, int mask_mode)
1248 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1249 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1250 cut_mode, mask_mode);
1253 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1256 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1259 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1262 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1265 void DrawLevelElementThruMask(int x, int y, int element)
1267 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1270 void DrawLevelFieldThruMask(int x, int y)
1272 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1275 #define TILE_GFX_ELEMENT(x, y) \
1276 (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ? \
1277 GfxElement[x][y] : Feld[x][y])
1279 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1283 int sx = SCREENX(x), sy = SCREENY(y);
1285 int width, height, cx, cy, i;
1287 int crumbled_border_size = graphic_info[graphic].border_size;
1289 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1291 static int xy[4][2] =
1300 if (x == 0 && y == 7)
1301 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1302 crumbled_border_size);
1305 if (!IN_LEV_FIELD(x, y))
1308 element = TILE_GFX_ELEMENT(x, y);
1310 /* crumble field itself */
1311 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1313 if (!IN_SCR_FIELD(sx, sy))
1316 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1318 for (i = 0; i < 4; i++)
1320 int xx = x + xy[i][0];
1321 int yy = y + xy[i][1];
1324 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1327 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1330 /* check if neighbour field is of same type */
1331 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1335 if (Feld[x][y] == EL_CUSTOM_START + 123)
1336 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1337 i, Feld[x][y], element,
1338 GFX_CRUMBLED(element), IS_MOVING(x, y));
1341 if (i == 1 || i == 2)
1343 width = crumbled_border_size;
1345 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1351 height = crumbled_border_size;
1353 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1356 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1357 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1360 MarkTileDirty(sx, sy);
1362 else /* crumble neighbour fields */
1365 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1368 for (i = 0; i < 4; i++)
1370 int xx = x + xy[i][0];
1371 int yy = y + xy[i][1];
1372 int sxx = sx + xy[i][0];
1373 int syy = sy + xy[i][1];
1376 if (!IN_LEV_FIELD(xx, yy) ||
1377 !IN_SCR_FIELD(sxx, syy) ||
1381 element = TILE_GFX_ELEMENT(xx, yy);
1383 if (!GFX_CRUMBLED(element))
1386 if (!IN_LEV_FIELD(xx, yy) ||
1387 !IN_SCR_FIELD(sxx, syy) ||
1388 !GFX_CRUMBLED(Feld[xx][yy]) ||
1394 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1395 crumbled_border_size = graphic_info[graphic].border_size;
1397 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1400 if (i == 1 || i == 2)
1402 width = crumbled_border_size;
1404 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1410 height = crumbled_border_size;
1412 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1415 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1416 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1418 MarkTileDirty(sxx, syy);
1423 void DrawLevelFieldCrumbledSand(int x, int y)
1428 if (!IN_LEV_FIELD(x, y))
1431 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1433 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1435 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1439 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1443 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1444 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1446 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1447 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1449 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1450 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1451 int sx = SCREENX(x), sy = SCREENY(y);
1453 DrawGraphic(sx, sy, graphic1, frame1);
1454 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1457 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1459 int sx = SCREENX(x), sy = SCREENY(y);
1460 static int xy[4][2] =
1469 for (i = 0; i < 4; i++)
1471 int xx = x + xy[i][0];
1472 int yy = y + xy[i][1];
1473 int sxx = sx + xy[i][0];
1474 int syy = sy + xy[i][1];
1476 if (!IN_LEV_FIELD(xx, yy) ||
1477 !IN_SCR_FIELD(sxx, syy) ||
1478 !GFX_CRUMBLED(Feld[xx][yy]) ||
1482 DrawLevelField(xx, yy);
1486 static int getBorderElement(int x, int y)
1490 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1491 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1492 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1493 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1494 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1495 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1496 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1498 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1499 int steel_position = (x == -1 && y == -1 ? 0 :
1500 x == lev_fieldx && y == -1 ? 1 :
1501 x == -1 && y == lev_fieldy ? 2 :
1502 x == lev_fieldx && y == lev_fieldy ? 3 :
1503 x == -1 || x == lev_fieldx ? 4 :
1504 y == -1 || y == lev_fieldy ? 5 : 6);
1506 return border[steel_position][steel_type];
1509 void DrawScreenElement(int x, int y, int element)
1511 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1512 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1515 void DrawLevelElement(int x, int y, int element)
1517 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1518 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1521 void DrawScreenField(int x, int y)
1523 int lx = LEVELX(x), ly = LEVELY(y);
1524 int element, content;
1526 if (!IN_LEV_FIELD(lx, ly))
1528 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1531 element = getBorderElement(lx, ly);
1533 DrawScreenElement(x, y, element);
1537 element = Feld[lx][ly];
1538 content = Store[lx][ly];
1540 if (IS_MOVING(lx, ly))
1542 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1543 boolean cut_mode = NO_CUTTING;
1545 if (element == EL_QUICKSAND_EMPTYING ||
1546 element == EL_MAGIC_WALL_EMPTYING ||
1547 element == EL_BD_MAGIC_WALL_EMPTYING ||
1548 element == EL_AMOEBA_DROPPING)
1549 cut_mode = CUT_ABOVE;
1550 else if (element == EL_QUICKSAND_FILLING ||
1551 element == EL_MAGIC_WALL_FILLING ||
1552 element == EL_BD_MAGIC_WALL_FILLING)
1553 cut_mode = CUT_BELOW;
1555 if (cut_mode == CUT_ABOVE)
1556 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1558 DrawScreenElement(x, y, EL_EMPTY);
1561 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1562 else if (cut_mode == NO_CUTTING)
1563 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1565 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1567 if (content == EL_ACID)
1569 int dir = MovDir[lx][ly];
1570 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1571 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1573 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1576 else if (IS_BLOCKED(lx, ly))
1581 boolean cut_mode = NO_CUTTING;
1582 int element_old, content_old;
1584 Blocked2Moving(lx, ly, &oldx, &oldy);
1587 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1588 MovDir[oldx][oldy] == MV_RIGHT);
1590 element_old = Feld[oldx][oldy];
1591 content_old = Store[oldx][oldy];
1593 if (element_old == EL_QUICKSAND_EMPTYING ||
1594 element_old == EL_MAGIC_WALL_EMPTYING ||
1595 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1596 element_old == EL_AMOEBA_DROPPING)
1597 cut_mode = CUT_ABOVE;
1599 DrawScreenElement(x, y, EL_EMPTY);
1602 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1604 else if (cut_mode == NO_CUTTING)
1605 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1608 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1611 else if (IS_DRAWABLE(element))
1612 DrawScreenElement(x, y, element);
1614 DrawScreenElement(x, y, EL_EMPTY);
1617 void DrawLevelField(int x, int y)
1619 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1620 DrawScreenField(SCREENX(x), SCREENY(y));
1621 else if (IS_MOVING(x, y))
1625 Moving2Blocked(x, y, &newx, &newy);
1626 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1627 DrawScreenField(SCREENX(newx), SCREENY(newy));
1629 else if (IS_BLOCKED(x, y))
1633 Blocked2Moving(x, y, &oldx, &oldy);
1634 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1635 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1639 void DrawMiniElement(int x, int y, int element)
1643 graphic = el2edimg(element);
1644 DrawMiniGraphic(x, y, graphic);
1647 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1649 int x = sx + scroll_x, y = sy + scroll_y;
1651 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1652 DrawMiniElement(sx, sy, EL_EMPTY);
1653 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1654 DrawMiniElement(sx, sy, Feld[x][y]);
1656 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1659 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1660 int x, int y, int xsize, int ysize, int font_nr)
1662 int font_width = getFontWidth(font_nr);
1663 int font_height = getFontHeight(font_nr);
1664 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1667 int dst_x = SX + startx + x * font_width;
1668 int dst_y = SY + starty + y * font_height;
1669 int width = graphic_info[graphic].width;
1670 int height = graphic_info[graphic].height;
1671 int inner_width = MAX(width - 2 * font_width, font_width);
1672 int inner_height = MAX(height - 2 * font_height, font_height);
1673 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1674 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1675 boolean draw_masked = graphic_info[graphic].draw_masked;
1677 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1679 if (src_bitmap == NULL || width < font_width || height < font_height)
1681 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1685 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1686 inner_sx + (x - 1) * font_width % inner_width);
1687 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1688 inner_sy + (y - 1) * font_height % inner_height);
1692 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1693 dst_x - src_x, dst_y - src_y);
1694 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1698 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1702 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1704 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1706 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1707 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1709 boolean draw_masked = graphic_info[graphic].draw_masked;
1710 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1712 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1713 boolean no_delay = (tape.warp_forward);
1714 unsigned long anim_delay = 0;
1715 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1716 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1717 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1718 int font_width = getFontWidth(font_nr);
1719 int font_height = getFontHeight(font_nr);
1720 int max_xsize = level.envelope_xsize[envelope_nr];
1721 int max_ysize = level.envelope_ysize[envelope_nr];
1722 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1723 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1724 int xend = max_xsize;
1725 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1726 int xstep = (xstart < xend ? 1 : 0);
1727 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1730 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1732 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1733 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1734 int sx = (SXSIZE - xsize * font_width) / 2;
1735 int sy = (SYSIZE - ysize * font_height) / 2;
1738 SetDrawtoField(DRAW_BUFFERED);
1740 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1742 SetDrawtoField(DRAW_BACKBUFFER);
1744 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1745 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1747 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1748 level.envelope_text[envelope_nr], font_nr, max_xsize,
1749 xsize - 2, ysize - 2, mask_mode);
1751 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1754 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1758 void ShowEnvelope(int envelope_nr)
1760 int element = EL_ENVELOPE_1 + envelope_nr;
1761 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1762 int sound_opening = element_info[element].sound[ACTION_OPENING];
1763 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1764 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1765 boolean no_delay = (tape.warp_forward);
1766 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1767 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1768 int anim_mode = graphic_info[graphic].anim_mode;
1769 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1770 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1772 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1774 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1776 if (anim_mode == ANIM_DEFAULT)
1777 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1779 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1782 Delay(wait_delay_value);
1784 WaitForEventToContinue();
1786 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1788 if (anim_mode != ANIM_NONE)
1789 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1791 if (anim_mode == ANIM_DEFAULT)
1792 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1794 game.envelope_active = FALSE;
1796 SetDrawtoField(DRAW_BUFFERED);
1798 redraw_mask |= REDRAW_FIELD;
1802 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1804 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1805 int mini_startx = src_bitmap->width * 3 / 4;
1806 int mini_starty = src_bitmap->height * 2 / 3;
1807 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1808 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1810 *bitmap = src_bitmap;
1815 void DrawMicroElement(int xpos, int ypos, int element)
1819 int graphic = el2preimg(element);
1821 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1822 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1830 SetDrawBackgroundMask(REDRAW_NONE);
1833 for (x = BX1; x <= BX2; x++)
1834 for (y = BY1; y <= BY2; y++)
1835 DrawScreenField(x, y);
1837 redraw_mask |= REDRAW_FIELD;
1840 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1844 for (x = 0; x < size_x; x++)
1845 for (y = 0; y < size_y; y++)
1846 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1848 redraw_mask |= REDRAW_FIELD;
1851 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1855 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1857 if (lev_fieldx < STD_LEV_FIELDX)
1858 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1859 if (lev_fieldy < STD_LEV_FIELDY)
1860 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1862 xpos += MICRO_TILEX;
1863 ypos += MICRO_TILEY;
1865 for (x = -1; x <= STD_LEV_FIELDX; x++)
1867 for (y = -1; y <= STD_LEV_FIELDY; y++)
1869 int lx = from_x + x, ly = from_y + y;
1871 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1872 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1873 level.field[lx][ly]);
1874 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1875 && BorderElement != EL_EMPTY)
1876 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1877 getBorderElement(lx, ly));
1881 redraw_mask |= REDRAW_MICROLEVEL;
1884 #define MICROLABEL_EMPTY 0
1885 #define MICROLABEL_LEVEL_NAME 1
1886 #define MICROLABEL_CREATED_BY 2
1887 #define MICROLABEL_LEVEL_AUTHOR 3
1888 #define MICROLABEL_IMPORTED_FROM 4
1889 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1891 static void DrawMicroLevelLabelExt(int mode)
1893 char label_text[MAX_OUTPUT_LINESIZE + 1];
1894 int max_len_label_text;
1895 int font_nr = FONT_TEXT_2;
1897 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1898 font_nr = FONT_TEXT_3;
1900 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1902 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1904 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1905 mode == MICROLABEL_CREATED_BY ? "created by" :
1906 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1907 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1908 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1909 leveldir_current->imported_from : ""),
1910 max_len_label_text);
1911 label_text[max_len_label_text] = '\0';
1913 if (strlen(label_text) > 0)
1915 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1916 int lypos = MICROLABEL_YPOS;
1918 DrawText(lxpos, lypos, label_text, font_nr);
1921 redraw_mask |= REDRAW_MICROLEVEL;
1924 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1926 static unsigned long scroll_delay = 0;
1927 static unsigned long label_delay = 0;
1928 static int from_x, from_y, scroll_direction;
1929 static int label_state, label_counter;
1930 int last_game_status = game_status; /* save current game status */
1932 /* force PREVIEW font on preview level */
1933 game_status = GAME_MODE_PSEUDO_PREVIEW;
1937 from_x = from_y = 0;
1938 scroll_direction = MV_RIGHT;
1942 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1943 DrawMicroLevelLabelExt(label_state);
1945 /* initialize delay counters */
1946 DelayReached(&scroll_delay, 0);
1947 DelayReached(&label_delay, 0);
1949 if (leveldir_current->name)
1951 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1952 int lxpos = SX + (SXSIZE - text_width) / 2;
1953 int lypos = SY + 352;
1955 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1958 game_status = last_game_status; /* restore current game status */
1963 /* scroll micro level, if needed */
1964 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1965 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1967 switch (scroll_direction)
1973 scroll_direction = MV_UP;
1977 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1980 scroll_direction = MV_DOWN;
1987 scroll_direction = MV_RIGHT;
1991 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1994 scroll_direction = MV_LEFT;
2001 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
2004 /* redraw micro level label, if needed */
2005 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
2006 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
2007 strcmp(level.author, leveldir_current->name) != 0 &&
2008 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2010 int max_label_counter = 23;
2012 if (leveldir_current->imported_from != NULL)
2013 max_label_counter += 14;
2015 label_counter = (label_counter + 1) % max_label_counter;
2016 label_state = (label_counter >= 0 && label_counter <= 7 ?
2017 MICROLABEL_LEVEL_NAME :
2018 label_counter >= 9 && label_counter <= 12 ?
2019 MICROLABEL_CREATED_BY :
2020 label_counter >= 14 && label_counter <= 21 ?
2021 MICROLABEL_LEVEL_AUTHOR :
2022 label_counter >= 23 && label_counter <= 26 ?
2023 MICROLABEL_IMPORTED_FROM :
2024 label_counter >= 28 && label_counter <= 35 ?
2025 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
2026 DrawMicroLevelLabelExt(label_state);
2029 game_status = last_game_status; /* restore current game status */
2032 void WaitForEventToContinue()
2034 boolean still_wait = TRUE;
2036 /* simulate releasing mouse button over last gadget, if still pressed */
2038 HandleGadgets(-1, -1, 0);
2040 button_status = MB_RELEASED;
2052 case EVENT_BUTTONPRESS:
2053 case EVENT_KEYPRESS:
2057 case EVENT_KEYRELEASE:
2058 ClearPlayerAction();
2062 HandleOtherEvents(&event);
2066 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2073 /* don't eat all CPU time */
2078 #define MAX_REQUEST_LINES 13
2079 #define MAX_REQUEST_LINE_FONT1_LEN 7
2080 #define MAX_REQUEST_LINE_FONT2_LEN 10
2082 boolean Request(char *text, unsigned int req_state)
2084 int mx, my, ty, result = -1;
2085 unsigned int old_door_state;
2086 int last_game_status = game_status; /* save current game status */
2087 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2088 int font_nr = FONT_TEXT_2;
2089 int max_word_len = 0;
2092 for (text_ptr = text; *text_ptr; text_ptr++)
2094 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2096 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2098 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2099 font_nr = FONT_LEVEL_NUMBER;
2106 /* disable deactivated drawing when quick-loading level tape recording */
2107 if (tape.playing && tape.deactivate_display)
2108 TapeDeactivateDisplayOff(TRUE);
2112 SetMouseCursor(CURSOR_DEFAULT);
2115 #if defined(NETWORK_AVALIABLE)
2116 /* pause network game while waiting for request to answer */
2117 if (options.network &&
2118 game_status == GAME_MODE_PLAYING &&
2119 req_state & REQUEST_WAIT_FOR)
2120 SendToServer_PausePlaying();
2123 old_door_state = GetDoorState();
2125 /* simulate releasing mouse button over last gadget, if still pressed */
2127 HandleGadgets(-1, -1, 0);
2131 CloseDoor(DOOR_CLOSE_1);
2133 /* save old door content */
2134 BlitBitmap(bitmap_db_door, bitmap_db_door,
2135 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2136 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2138 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2140 /* clear door drawing field */
2141 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2143 /* force DOOR font on preview level */
2144 game_status = GAME_MODE_PSEUDO_DOOR;
2146 /* write text for request */
2147 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2149 char text_line[max_request_line_len + 1];
2155 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2158 if (!tc || tc == ' ')
2169 strncpy(text_line, text, tl);
2172 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2173 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2174 text_line, font_nr);
2176 text += tl + (tc == ' ' ? 1 : 0);
2179 game_status = last_game_status; /* restore current game status */
2181 if (req_state & REQ_ASK)
2183 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2184 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2186 else if (req_state & REQ_CONFIRM)
2188 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2190 else if (req_state & REQ_PLAYER)
2192 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2193 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2194 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2195 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2198 /* copy request gadgets to door backbuffer */
2199 BlitBitmap(drawto, bitmap_db_door,
2200 DX, DY, DXSIZE, DYSIZE,
2201 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2203 OpenDoor(DOOR_OPEN_1);
2209 if (!(req_state & REQUEST_WAIT_FOR))
2211 SetDrawBackgroundMask(REDRAW_FIELD);
2216 if (game_status != GAME_MODE_MAIN)
2219 button_status = MB_RELEASED;
2221 request_gadget_id = -1;
2223 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2226 SetMouseCursor(CURSOR_DEFAULT);
2239 case EVENT_BUTTONPRESS:
2240 case EVENT_BUTTONRELEASE:
2241 case EVENT_MOTIONNOTIFY:
2243 if (event.type == EVENT_MOTIONNOTIFY)
2245 if (!PointerInWindow(window))
2246 continue; /* window and pointer are on different screens */
2251 motion_status = TRUE;
2252 mx = ((MotionEvent *) &event)->x;
2253 my = ((MotionEvent *) &event)->y;
2257 motion_status = FALSE;
2258 mx = ((ButtonEvent *) &event)->x;
2259 my = ((ButtonEvent *) &event)->y;
2260 if (event.type == EVENT_BUTTONPRESS)
2261 button_status = ((ButtonEvent *) &event)->button;
2263 button_status = MB_RELEASED;
2266 /* this sets 'request_gadget_id' */
2267 HandleGadgets(mx, my, button_status);
2269 switch(request_gadget_id)
2271 case TOOL_CTRL_ID_YES:
2274 case TOOL_CTRL_ID_NO:
2277 case TOOL_CTRL_ID_CONFIRM:
2278 result = TRUE | FALSE;
2281 case TOOL_CTRL_ID_PLAYER_1:
2284 case TOOL_CTRL_ID_PLAYER_2:
2287 case TOOL_CTRL_ID_PLAYER_3:
2290 case TOOL_CTRL_ID_PLAYER_4:
2301 case EVENT_KEYPRESS:
2302 switch(GetEventKey((KeyEvent *)&event, TRUE))
2315 if (req_state & REQ_PLAYER)
2319 case EVENT_KEYRELEASE:
2320 ClearPlayerAction();
2324 HandleOtherEvents(&event);
2328 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2330 int joy = AnyJoystick();
2332 if (joy & JOY_BUTTON_1)
2334 else if (joy & JOY_BUTTON_2)
2340 /* don't eat all CPU time */
2344 if (game_status != GAME_MODE_MAIN)
2349 if (!(req_state & REQ_STAY_OPEN))
2351 CloseDoor(DOOR_CLOSE_1);
2353 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2355 BlitBitmap(bitmap_db_door, bitmap_db_door,
2356 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2357 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2358 OpenDoor(DOOR_OPEN_1);
2364 SetDrawBackgroundMask(REDRAW_FIELD);
2366 #if defined(NETWORK_AVALIABLE)
2367 /* continue network game after request */
2368 if (options.network &&
2369 game_status == GAME_MODE_PLAYING &&
2370 req_state & REQUEST_WAIT_FOR)
2371 SendToServer_ContinuePlaying();
2375 /* restore deactivated drawing when quick-loading level tape recording */
2376 if (tape.playing && tape.deactivate_display)
2377 TapeDeactivateDisplayOn();
2383 unsigned int OpenDoor(unsigned int door_state)
2385 unsigned int new_door_state;
2387 if (door_state & DOOR_COPY_BACK)
2389 BlitBitmap(bitmap_db_door, bitmap_db_door,
2390 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2391 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2392 door_state &= ~DOOR_COPY_BACK;
2395 new_door_state = MoveDoor(door_state);
2397 return(new_door_state);
2400 unsigned int CloseDoor(unsigned int door_state)
2402 unsigned int new_door_state;
2404 BlitBitmap(backbuffer, bitmap_db_door,
2405 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2406 BlitBitmap(backbuffer, bitmap_db_door,
2407 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2409 new_door_state = MoveDoor(door_state);
2411 return(new_door_state);
2414 unsigned int GetDoorState()
2416 return MoveDoor(DOOR_GET_STATE);
2419 unsigned int SetDoorState(unsigned int door_state)
2421 return MoveDoor(door_state | DOOR_SET_STATE);
2424 unsigned int MoveDoor(unsigned int door_state)
2426 static int door1 = DOOR_OPEN_1;
2427 static int door2 = DOOR_CLOSE_2;
2428 unsigned long door_delay = 0;
2429 unsigned long door_delay_value;
2432 if (door_state == DOOR_GET_STATE)
2433 return(door1 | door2);
2435 if (door_state & DOOR_SET_STATE)
2437 if (door_state & DOOR_ACTION_1)
2438 door1 = door_state & DOOR_ACTION_1;
2439 if (door_state & DOOR_ACTION_2)
2440 door2 = door_state & DOOR_ACTION_2;
2442 return(door1 | door2);
2445 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2446 door_state &= ~DOOR_OPEN_1;
2447 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2448 door_state &= ~DOOR_CLOSE_1;
2449 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2450 door_state &= ~DOOR_OPEN_2;
2451 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2452 door_state &= ~DOOR_CLOSE_2;
2454 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2457 if (setup.quick_doors)
2459 stepsize = 20; /* must be choosen to always draw last frame */
2460 door_delay_value = 0;
2463 StopSound(SND_DOOR_OPENING);
2464 StopSound(SND_DOOR_CLOSING);
2468 if (global.autoplay_leveldir)
2470 door_state |= DOOR_NO_DELAY;
2471 door_state &= ~DOOR_CLOSE_ALL;
2474 if (door_state & DOOR_ACTION)
2476 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2477 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2478 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2479 int end = (door_state & DOOR_ACTION_1 &&
2480 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2483 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2485 /* opening door sound has priority over simultaneously closing door */
2486 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2487 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2488 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2489 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2492 for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2494 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2495 GC gc = bitmap->stored_clip_gc;
2497 if (door_state & DOOR_ACTION_1)
2499 int a = MIN(x * door_1.step_offset, end);
2500 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2504 BlitBitmap(bitmap_db_door, drawto,
2505 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2506 DXSIZE,DYSIZE - i / 2, DX, DY);
2508 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2511 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2513 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2514 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2515 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2516 int dst2_x = DX, dst2_y = DY;
2517 int width = i, height = DYSIZE;
2519 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2520 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2523 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2524 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2527 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2529 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2530 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2531 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2532 int dst2_x = DX, dst2_y = DY;
2533 int width = DXSIZE, height = i;
2535 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2536 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2539 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2540 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2543 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2545 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2547 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2548 BlitBitmapMasked(bitmap, drawto,
2549 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2550 DX + DXSIZE - i, DY + j);
2551 BlitBitmapMasked(bitmap, drawto,
2552 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2553 DX + DXSIZE - i, DY + 140 + j);
2554 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2555 DY - (DOOR_GFX_PAGEY1 + j));
2556 BlitBitmapMasked(bitmap, drawto,
2557 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2559 BlitBitmapMasked(bitmap, drawto,
2560 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2563 BlitBitmapMasked(bitmap, drawto,
2564 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2566 BlitBitmapMasked(bitmap, drawto,
2567 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2569 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2570 BlitBitmapMasked(bitmap, drawto,
2571 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2572 DX + DXSIZE - i, DY + 77 + j);
2573 BlitBitmapMasked(bitmap, drawto,
2574 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2575 DX + DXSIZE - i, DY + 203 + j);
2578 redraw_mask |= REDRAW_DOOR_1;
2579 door_1_done = (a == end);
2582 if (door_state & DOOR_ACTION_2)
2584 int a = MIN(x * door_2.step_offset, VXSIZE);
2585 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2589 BlitBitmap(bitmap_db_door, drawto,
2590 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2591 VXSIZE, VYSIZE - i / 2, VX, VY);
2593 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2596 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2598 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2599 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2600 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2601 int dst2_x = VX, dst2_y = VY;
2602 int width = i, height = VYSIZE;
2604 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2605 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2608 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2609 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2612 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2614 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2615 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2616 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2617 int dst2_x = VX, dst2_y = VY;
2618 int width = VXSIZE, height = i;
2620 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2621 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2624 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2625 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2628 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2630 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2632 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2633 BlitBitmapMasked(bitmap, drawto,
2634 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2635 VX + VXSIZE - i, VY + j);
2636 SetClipOrigin(bitmap, gc,
2637 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2638 BlitBitmapMasked(bitmap, drawto,
2639 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2642 BlitBitmapMasked(bitmap, drawto,
2643 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2644 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2645 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2646 BlitBitmapMasked(bitmap, drawto,
2647 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2649 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2652 redraw_mask |= REDRAW_DOOR_2;
2653 door_2_done = (a == VXSIZE);
2658 if (game_status == GAME_MODE_MAIN)
2661 if (!(door_state & DOOR_NO_DELAY))
2662 WaitUntilDelayReached(&door_delay, door_delay_value);
2667 if (setup.quick_doors)
2669 StopSound(SND_DOOR_OPENING);
2670 StopSound(SND_DOOR_CLOSING);
2674 if (door_state & DOOR_ACTION_1)
2675 door1 = door_state & DOOR_ACTION_1;
2676 if (door_state & DOOR_ACTION_2)
2677 door2 = door_state & DOOR_ACTION_2;
2679 return (door1 | door2);
2682 void DrawSpecialEditorDoor()
2684 /* draw bigger toolbox window */
2685 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2686 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2688 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2689 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2692 redraw_mask |= REDRAW_ALL;
2695 void UndrawSpecialEditorDoor()
2697 /* draw normal tape recorder window */
2698 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2699 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2702 redraw_mask |= REDRAW_ALL;
2706 /* ---------- new tool button stuff ---------------------------------------- */
2708 /* graphic position values for tool buttons */
2709 #define TOOL_BUTTON_YES_XPOS 2
2710 #define TOOL_BUTTON_YES_YPOS 250
2711 #define TOOL_BUTTON_YES_GFX_YPOS 0
2712 #define TOOL_BUTTON_YES_XSIZE 46
2713 #define TOOL_BUTTON_YES_YSIZE 28
2714 #define TOOL_BUTTON_NO_XPOS 52
2715 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2716 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2717 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2718 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2719 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2720 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2721 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2722 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2723 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2724 #define TOOL_BUTTON_PLAYER_XSIZE 30
2725 #define TOOL_BUTTON_PLAYER_YSIZE 30
2726 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2727 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2728 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2729 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2730 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2731 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2732 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2733 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2734 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2735 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2736 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2737 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2738 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2739 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2740 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2741 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2742 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2743 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2744 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2745 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2754 } toolbutton_info[NUM_TOOL_BUTTONS] =
2757 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2758 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2759 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2764 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2765 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2766 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2771 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2772 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2773 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2774 TOOL_CTRL_ID_CONFIRM,
2778 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2779 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2780 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2781 TOOL_CTRL_ID_PLAYER_1,
2785 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2786 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2787 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2788 TOOL_CTRL_ID_PLAYER_2,
2792 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2793 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2794 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2795 TOOL_CTRL_ID_PLAYER_3,
2799 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2800 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2801 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2802 TOOL_CTRL_ID_PLAYER_4,
2807 void CreateToolButtons()
2811 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2813 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2814 Bitmap *deco_bitmap = None;
2815 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2816 struct GadgetInfo *gi;
2817 unsigned long event_mask;
2818 int gd_xoffset, gd_yoffset;
2819 int gd_x1, gd_x2, gd_y;
2822 event_mask = GD_EVENT_RELEASED;
2824 gd_xoffset = toolbutton_info[i].xpos;
2825 gd_yoffset = toolbutton_info[i].ypos;
2826 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2827 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2828 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2830 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2832 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2834 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2835 &deco_bitmap, &deco_x, &deco_y);
2836 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2837 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2840 gi = CreateGadget(GDI_CUSTOM_ID, id,
2841 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2842 GDI_X, DX + toolbutton_info[i].x,
2843 GDI_Y, DY + toolbutton_info[i].y,
2844 GDI_WIDTH, toolbutton_info[i].width,
2845 GDI_HEIGHT, toolbutton_info[i].height,
2846 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2847 GDI_STATE, GD_BUTTON_UNPRESSED,
2848 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2849 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2850 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2851 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2852 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2853 GDI_DECORATION_SHIFTING, 1, 1,
2854 GDI_EVENT_MASK, event_mask,
2855 GDI_CALLBACK_ACTION, HandleToolButtons,
2859 Error(ERR_EXIT, "cannot create gadget");
2861 tool_gadget[id] = gi;
2865 void FreeToolButtons()
2869 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2870 FreeGadget(tool_gadget[i]);
2873 static void UnmapToolButtons()
2877 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2878 UnmapGadget(tool_gadget[i]);
2881 static void HandleToolButtons(struct GadgetInfo *gi)
2883 request_gadget_id = gi->custom_id;
2886 int get_next_element(int element)
2890 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2891 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2892 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2893 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2894 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2895 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2896 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2898 default: return element;
2902 int el_act_dir2img(int element, int action, int direction)
2904 element = GFX_ELEMENT(element);
2905 direction = MV_DIR_BIT(direction); /* default: MV_NO_MOVING => MV_DOWN */
2907 return element_info[element].direction_graphic[action][direction];
2910 static int el_act_dir2crm(int element, int action, int direction)
2912 element = GFX_ELEMENT(element);
2913 direction = MV_DIR_BIT(direction); /* default: MV_NO_MOVING => MV_DOWN */
2915 return element_info[element].direction_crumbled[action][direction];
2918 int el_act2img(int element, int action)
2920 element = GFX_ELEMENT(element);
2922 return element_info[element].graphic[action];
2925 int el_act2crm(int element, int action)
2927 element = GFX_ELEMENT(element);
2929 return element_info[element].crumbled[action];
2932 int el_dir2img(int element, int direction)
2934 element = GFX_ELEMENT(element);
2936 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2939 int el2baseimg(int element)
2941 return element_info[element].graphic[ACTION_DEFAULT];
2944 int el2img(int element)
2946 element = GFX_ELEMENT(element);
2948 return element_info[element].graphic[ACTION_DEFAULT];
2951 int el2edimg(int element)
2953 element = GFX_ELEMENT(element);
2955 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2958 int el2preimg(int element)
2960 element = GFX_ELEMENT(element);
2962 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];