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 void DumpTile(int x, int y)
49 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
52 if (!IN_LEV_FIELD(x, y))
54 printf("(not in level field)\n");
60 printf(" Feld: %d ['%s']\n", Feld[x][y],
61 element_info[Feld[x][y]].token_name);
62 printf(" Back: %d\n", Back[x][y]);
63 printf(" Store: %d\n", Store[x][y]);
64 printf(" Store2: %d\n", Store2[x][y]);
65 printf(" StorePlayer: %d\n", StorePlayer[x][y]);
66 printf(" MovPos: %d\n", MovPos[x][y]);
67 printf(" MovDir: %d\n", MovDir[x][y]);
68 printf(" MovDelay: %d\n", MovDelay[x][y]);
69 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
70 printf(" GfxElement: %d\n", GfxElement[x][y]);
71 printf(" GfxAction: %d\n", GfxAction[x][y]);
72 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
76 void SetDrawtoField(int mode)
78 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
89 drawto_field = fieldbuffer;
91 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
102 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
106 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
108 if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
114 width = gfx.sxsize + 2 * TILEX;
115 height = gfx.sysize + 2 * TILEY;
118 if (force_redraw || setup.direct_draw)
121 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
122 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
124 if (setup.direct_draw)
125 SetDrawtoField(DRAW_BACKBUFFER);
127 for (xx = BX1; xx <= BX2; xx++)
128 for (yy = BY1; yy <= BY2; yy++)
129 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
130 DrawScreenField(xx, yy);
133 if (setup.direct_draw)
134 SetDrawtoField(DRAW_DIRECT);
137 if (setup.soft_scrolling)
139 int fx = FX, fy = FY;
141 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
142 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
144 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
148 BlitBitmap(drawto, window, x, y, width, height, x, y);
154 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
156 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
157 redraw_mask &= ~REDRAW_MAIN;
159 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
160 redraw_mask |= REDRAW_FIELD;
162 if (redraw_mask & REDRAW_FIELD)
163 redraw_mask &= ~REDRAW_TILES;
165 if (redraw_mask == REDRAW_NONE)
168 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
170 static boolean last_frame_skipped = FALSE;
171 boolean skip_even_when_not_scrolling = TRUE;
172 boolean just_scrolling = (ScreenMovDir != 0);
173 boolean verbose = FALSE;
175 if (global.fps_slowdown_factor > 1 &&
176 (FrameCounter % global.fps_slowdown_factor) &&
177 (just_scrolling || skip_even_when_not_scrolling))
179 redraw_mask &= ~REDRAW_MAIN;
181 last_frame_skipped = TRUE;
184 printf("FRAME SKIPPED\n");
188 if (last_frame_skipped)
189 redraw_mask |= REDRAW_FIELD;
191 last_frame_skipped = FALSE;
194 printf("frame not skipped\n");
198 /* synchronize X11 graphics at this point; if we would synchronize the
199 display immediately after the buffer switching (after the XFlush),
200 this could mean that we have to wait for the graphics to complete,
201 although we could go on doing calculations for the next frame */
205 if (redraw_mask & REDRAW_ALL)
207 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
211 if (redraw_mask & REDRAW_FIELD)
213 if (game_status != GAME_MODE_PLAYING ||
214 redraw_mask & REDRAW_FROM_BACKBUFFER)
216 BlitBitmap(backbuffer, window,
217 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
221 int fx = FX, fy = FY;
223 if (setup.soft_scrolling)
225 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
226 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
229 if (setup.soft_scrolling ||
230 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
231 ABS(ScreenMovPos) == ScrollStepSize ||
232 redraw_tiles > REDRAWTILES_THRESHOLD)
234 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
238 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
240 (setup.soft_scrolling ?
241 "setup.soft_scrolling" :
242 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
243 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
244 ABS(ScreenGfxPos) == ScrollStepSize ?
245 "ABS(ScreenGfxPos) == ScrollStepSize" :
246 "redraw_tiles > REDRAWTILES_THRESHOLD"));
252 redraw_mask &= ~REDRAW_MAIN;
255 if (redraw_mask & REDRAW_DOORS)
257 if (redraw_mask & REDRAW_DOOR_1)
258 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
259 if (redraw_mask & REDRAW_DOOR_2)
261 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
262 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
265 if (redraw_mask & REDRAW_VIDEO_1)
266 BlitBitmap(backbuffer, window,
267 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
268 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
269 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
270 if (redraw_mask & REDRAW_VIDEO_2)
271 BlitBitmap(backbuffer, window,
272 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
273 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
274 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
275 if (redraw_mask & REDRAW_VIDEO_3)
276 BlitBitmap(backbuffer, window,
277 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
278 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
279 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
283 if (redraw_mask & REDRAW_DOOR_3)
284 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
286 redraw_mask &= ~REDRAW_DOORS;
289 if (redraw_mask & REDRAW_MICROLEVEL)
291 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
292 SX, SY + 10 * TILEY);
294 redraw_mask &= ~REDRAW_MICROLEVEL;
297 if (redraw_mask & REDRAW_TILES)
299 for (x = 0; x < SCR_FIELDX; x++)
300 for (y =0 ; y < SCR_FIELDY; y++)
301 if (redraw[redraw_x1 + x][redraw_y1 + y])
302 BlitBitmap(buffer, window,
303 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
304 SX + x * TILEX, SY + y * TILEY);
307 if (redraw_mask & REDRAW_FPS) /* display frames per second */
312 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
313 if (!global.fps_slowdown)
316 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
317 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
322 for (x = 0; x < MAX_BUF_XSIZE; x++)
323 for (y = 0; y < MAX_BUF_YSIZE; y++)
326 redraw_mask = REDRAW_NONE;
332 long fading_delay = 300;
334 if (setup.fading && (redraw_mask & REDRAW_FIELD))
341 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
344 for (i = 0; i < 2 * FULL_SYSIZE; i++)
346 for (y = 0; y < FULL_SYSIZE; y++)
348 BlitBitmap(backbuffer, window,
349 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
357 for (i = 1; i < FULL_SYSIZE; i+=2)
358 BlitBitmap(backbuffer, window,
359 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
365 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
366 BlitBitmapMasked(backbuffer, window,
367 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
372 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
373 BlitBitmapMasked(backbuffer, window,
374 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
379 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
380 BlitBitmapMasked(backbuffer, window,
381 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
386 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
387 BlitBitmapMasked(backbuffer, window,
388 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
393 redraw_mask &= ~REDRAW_MAIN;
400 void SetMainBackgroundImage(int graphic)
402 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
403 graphic_info[graphic].bitmap ?
404 graphic_info[graphic].bitmap :
405 graphic_info[IMG_BACKGROUND].bitmap);
408 void SetDoorBackgroundImage(int graphic)
410 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
411 graphic_info[graphic].bitmap ?
412 graphic_info[graphic].bitmap :
413 graphic_info[IMG_BACKGROUND].bitmap);
416 void DrawBackground(int dest_x, int dest_y, int width, int height)
418 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
420 redraw_mask |= REDRAW_FIELD;
425 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
427 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
429 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
430 SetDrawtoField(DRAW_BUFFERED);
433 SetDrawtoField(DRAW_BACKBUFFER);
435 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
437 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
438 SetDrawtoField(DRAW_DIRECT);
442 void MarkTileDirty(int x, int y)
444 int xx = redraw_x1 + x;
445 int yy = redraw_y1 + y;
450 redraw[xx][yy] = TRUE;
451 redraw_mask |= REDRAW_TILES;
454 void SetBorderElement()
458 BorderElement = EL_EMPTY;
460 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
462 for (x = 0; x < lev_fieldx; x++)
464 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
465 BorderElement = EL_STEELWALL;
467 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
473 void SetRandomAnimationValue(int x, int y)
475 gfx.anim_random_frame = GfxRandom[x][y];
478 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
480 /* animation synchronized with global frame counter, not move position */
481 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
482 sync_frame = FrameCounter;
484 return getAnimationFrame(graphic_info[graphic].anim_frames,
485 graphic_info[graphic].anim_delay,
486 graphic_info[graphic].anim_mode,
487 graphic_info[graphic].anim_start_frame,
491 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
492 int graphic, int sync_frame, int mask_mode)
494 int frame = getGraphicAnimationFrame(graphic, sync_frame);
496 if (mask_mode == USE_MASKING)
497 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
499 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
502 inline void DrawGraphicAnimation(int x, int y, int graphic)
504 int lx = LEVELX(x), ly = LEVELY(y);
506 if (!IN_SCR_FIELD(x, y))
509 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
510 graphic, GfxFrame[lx][ly], NO_MASKING);
514 void DrawLevelGraphicAnimation(int x, int y, int graphic)
516 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
519 void DrawLevelElementAnimation(int x, int y, int element)
522 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
524 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
526 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
530 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
532 int sx = SCREENX(x), sy = SCREENY(y);
534 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
537 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
540 DrawGraphicAnimation(sx, sy, graphic);
542 if (GFX_CRUMBLED(Feld[x][y]))
543 DrawLevelFieldCrumbledSand(x, y);
546 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
548 int sx = SCREENX(x), sy = SCREENY(y);
551 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
554 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
556 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
559 DrawGraphicAnimation(sx, sy, graphic);
561 if (GFX_CRUMBLED(element))
562 DrawLevelFieldCrumbledSand(x, y);
565 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
567 if (player->use_murphy_graphic)
569 /* this works only because currently only one player can be "murphy" ... */
570 static int last_horizontal_dir = MV_LEFT;
571 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
573 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
574 last_horizontal_dir = move_dir;
576 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
578 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
580 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
586 return el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
589 static boolean equalGraphics(int graphic1, int graphic2)
591 struct GraphicInfo *g1 = &graphic_info[graphic1];
592 struct GraphicInfo *g2 = &graphic_info[graphic2];
594 return (g1->bitmap == g2->bitmap &&
595 g1->src_x == g2->src_x &&
596 g1->src_y == g2->src_y &&
597 g1->anim_frames == g2->anim_frames &&
598 g1->anim_delay == g2->anim_delay &&
599 g1->anim_mode == g2->anim_mode);
602 void DrawAllPlayers()
606 for (i = 0; i < MAX_PLAYERS; i++)
607 if (stored_player[i].active)
608 DrawPlayer(&stored_player[i]);
611 void DrawPlayerField(int x, int y)
613 if (!IS_PLAYER(x, y))
616 DrawPlayer(PLAYERINFO(x, y));
619 void DrawPlayer(struct PlayerInfo *player)
623 int move_dir = player->MovDir;
625 int last_jx = player->last_jx;
626 int last_jy = player->last_jy;
627 int next_jx = jx + (jx - last_jx);
628 int next_jy = jy + (jy - last_jy);
629 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
631 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
632 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
633 int last_jx = (player->is_moving ? jx - dx : jx);
634 int last_jy = (player->is_moving ? jy - dy : jy);
635 int next_jx = jx + dx;
636 int next_jy = jy + dy;
637 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
639 int sx = SCREENX(jx), sy = SCREENY(jy);
640 int sxx = 0, syy = 0;
641 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
643 int action = ACTION_DEFAULT;
644 int last_player_graphic = getPlayerGraphic(player, move_dir);
645 int last_player_frame = player->Frame;
648 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
652 if (!IN_LEV_FIELD(jx, jy))
654 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
655 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
656 printf("DrawPlayerField(): This should never happen!\n");
661 if (element == EL_EXPLOSION)
664 action = (player->is_pushing ? ACTION_PUSHING :
665 player->is_digging ? ACTION_DIGGING :
666 player->is_collecting ? ACTION_COLLECTING :
667 player->is_moving ? ACTION_MOVING :
668 player->is_snapping ? ACTION_SNAPPING :
669 player->is_dropping ? ACTION_DROPPING :
670 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
672 InitPlayerGfxAnimation(player, action, move_dir);
674 /* ----------------------------------------------------------------------- */
675 /* draw things in the field the player is leaving, if needed */
676 /* ----------------------------------------------------------------------- */
679 if (player->is_moving)
681 if (player_is_moving)
684 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
686 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
688 if (last_element == EL_DYNAMITE_ACTIVE ||
689 last_element == EL_SP_DISK_RED_ACTIVE)
690 DrawDynamite(last_jx, last_jy);
692 DrawLevelFieldThruMask(last_jx, last_jy);
694 else if (last_element == EL_DYNAMITE_ACTIVE ||
695 last_element == EL_SP_DISK_RED_ACTIVE)
696 DrawDynamite(last_jx, last_jy);
698 DrawLevelField(last_jx, last_jy);
700 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
701 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
704 if (!IN_SCR_FIELD(sx, sy))
707 if (setup.direct_draw)
708 SetDrawtoField(DRAW_BUFFERED);
710 /* ----------------------------------------------------------------------- */
711 /* draw things behind the player, if needed */
712 /* ----------------------------------------------------------------------- */
715 DrawLevelElement(jx, jy, Back[jx][jy]);
716 else if (IS_ACTIVE_BOMB(element))
717 DrawLevelElement(jx, jy, EL_EMPTY);
720 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
722 if (GFX_CRUMBLED(GfxElement[jx][jy]))
723 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
726 int old_element = GfxElement[jx][jy];
727 int old_graphic = el_act_dir2img(old_element, action, move_dir);
728 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
730 DrawGraphic(sx, sy, old_graphic, frame);
735 GfxElement[jx][jy] = EL_UNDEFINED;
737 DrawLevelField(jx, jy);
741 /* ----------------------------------------------------------------------- */
742 /* draw player himself */
743 /* ----------------------------------------------------------------------- */
747 graphic = getPlayerGraphic(player, move_dir);
749 /* in the case of changed player action or direction, prevent the current
750 animation frame from being restarted for identical animations */
751 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
752 player->Frame = last_player_frame;
756 if (player->use_murphy_graphic)
758 static int last_horizontal_dir = MV_LEFT;
760 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
761 last_horizontal_dir = move_dir;
763 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
765 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
767 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
769 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
773 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
777 frame = getGraphicAnimationFrame(graphic, player->Frame);
781 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
782 sxx = player->GfxPos;
784 syy = player->GfxPos;
787 if (!setup.soft_scrolling && ScreenMovPos)
790 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
792 if (SHIELD_ON(player))
794 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
795 IMG_SHIELD_NORMAL_ACTIVE);
796 int frame = getGraphicAnimationFrame(graphic, -1);
798 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
801 /* ----------------------------------------------------------------------- */
802 /* draw things the player is pushing, if needed */
803 /* ----------------------------------------------------------------------- */
806 printf("::: %d, %d [%d, %d] [%d]\n",
807 player->is_pushing, player_is_moving, player->GfxAction,
808 player->is_moving, player_is_moving);
812 if (player->is_pushing && player->is_moving)
814 if (player->is_pushing && player_is_moving)
817 int px = SCREENX(next_jx), py = SCREENY(next_jy);
819 if (Back[next_jx][next_jy])
820 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
822 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
823 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
827 int element = MovingOrBlocked2Element(next_jx, next_jy);
828 int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
830 int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
832 int frame = getGraphicAnimationFrame(graphic, player->Frame);
835 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
836 NO_CUTTING, NO_MASKING);
840 /* ----------------------------------------------------------------------- */
841 /* draw things in front of player (active dynamite or dynabombs) */
842 /* ----------------------------------------------------------------------- */
844 if (IS_ACTIVE_BOMB(element))
846 graphic = el2img(element);
847 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
849 if (game.emulation == EMU_SUPAPLEX)
850 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
852 DrawGraphicThruMask(sx, sy, graphic, frame);
855 if (player_is_moving && last_element == EL_EXPLOSION)
857 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
858 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
859 int phase = ExplodePhase[last_jx][last_jy] - 1;
860 int frame = getGraphicAnimationFrame(graphic, phase - delay);
863 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
866 /* ----------------------------------------------------------------------- */
867 /* draw elements the player is just walking/passing through/under */
868 /* ----------------------------------------------------------------------- */
870 /* handle the field the player is leaving ... */
871 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
872 DrawLevelField(last_jx, last_jy);
873 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
874 DrawLevelFieldThruMask(last_jx, last_jy);
876 /* ... and the field the player is entering */
877 if (IS_ACCESSIBLE_INSIDE(element))
878 DrawLevelField(jx, jy);
879 else if (IS_ACCESSIBLE_UNDER(element))
880 DrawLevelFieldThruMask(jx, jy);
882 if (setup.direct_draw)
884 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
885 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
886 int x_size = TILEX * (1 + ABS(jx - last_jx));
887 int y_size = TILEY * (1 + ABS(jy - last_jy));
889 BlitBitmap(drawto_field, window,
890 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
891 SetDrawtoField(DRAW_DIRECT);
894 MarkTileDirty(sx, sy);
897 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
899 struct GraphicInfo *g = &graphic_info[graphic];
903 if (g->offset_y == 0) /* frames are ordered horizontally */
905 int max_width = g->anim_frames_per_line * g->width;
907 *x = (g->src_x + frame * g->offset_x) % max_width;
908 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
910 else if (g->offset_x == 0) /* frames are ordered vertically */
912 int max_height = g->anim_frames_per_line * g->height;
914 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
915 *y = (g->src_y + frame * g->offset_y) % max_height;
917 else /* frames are ordered diagonally */
919 *x = g->src_x + frame * g->offset_x;
920 *y = g->src_y + frame * g->offset_y;
924 void DrawGraphic(int x, int y, int graphic, int frame)
927 if (!IN_SCR_FIELD(x, y))
929 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
930 printf("DrawGraphic(): This should never happen!\n");
935 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
939 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
945 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
946 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
949 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
952 if (!IN_SCR_FIELD(x, y))
954 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
955 printf("DrawGraphicThruMask(): This should never happen!\n");
960 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
965 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
973 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
974 drawing_gc = src_bitmap->stored_clip_gc;
976 GC drawing_gc = src_bitmap->stored_clip_gc;
977 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
978 int src_x = graphic_info[graphic].src_x;
979 int src_y = graphic_info[graphic].src_y;
980 int offset_x = graphic_info[graphic].offset_x;
981 int offset_y = graphic_info[graphic].offset_y;
983 src_x += frame * offset_x;
984 src_y += frame * offset_y;
988 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
989 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
992 void DrawMiniGraphic(int x, int y, int graphic)
994 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
995 MarkTileDirty(x / 2, y / 2);
998 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1000 struct GraphicInfo *g = &graphic_info[graphic];
1001 int mini_startx = 0;
1002 int mini_starty = g->bitmap->height * 2 / 3;
1004 *bitmap = g->bitmap;
1005 *x = mini_startx + g->src_x / 2;
1006 *y = mini_starty + g->src_y / 2;
1009 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1014 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1015 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1018 void DrawGraphicShifted(int x, int y, int dx, int dy, int graphic, int frame,
1019 int cut_mode, int mask_mode)
1024 int width = TILEX, height = TILEY;
1030 DrawGraphic(x, y, graphic, frame);
1034 if (dx || dy) /* shifted graphic */
1036 if (x < BX1) /* object enters playfield from the left */
1043 else if (x > BX2) /* object enters playfield from the right */
1049 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1055 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1057 else if (dx) /* general horizontal movement */
1058 MarkTileDirty(x + SIGN(dx), y);
1060 if (y < BY1) /* object enters playfield from the top */
1062 if (cut_mode==CUT_BELOW) /* object completely above top border */
1070 else if (y > BY2) /* object enters playfield from the bottom */
1076 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1082 else if (dy > 0 && cut_mode == CUT_ABOVE)
1084 if (y == BY2) /* object completely above bottom border */
1090 MarkTileDirty(x, y + 1);
1091 } /* object leaves playfield to the bottom */
1092 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1094 else if (dy) /* general vertical movement */
1095 MarkTileDirty(x, y + SIGN(dy));
1099 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1101 src_bitmap = graphic_info[graphic].bitmap;
1102 src_x = graphic_info[graphic].src_x;
1103 src_y = graphic_info[graphic].src_y;
1104 offset_x = graphic_info[graphic].offset_x;
1105 offset_y = graphic_info[graphic].offset_y;
1107 src_x += frame * offset_x;
1108 src_y += frame * offset_y;
1111 drawing_gc = src_bitmap->stored_clip_gc;
1116 dest_x = FX + x * TILEX + dx;
1117 dest_y = FY + y * TILEY + dy;
1120 if (!IN_SCR_FIELD(x,y))
1122 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1123 printf("DrawGraphicShifted(): This should never happen!\n");
1128 if (mask_mode == USE_MASKING)
1130 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1131 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1135 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1138 MarkTileDirty(x, y);
1141 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1142 int frame, int cut_mode)
1144 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1147 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1148 int cut_mode, int mask_mode)
1150 int lx = LEVELX(x), ly = LEVELY(y);
1154 if (IN_LEV_FIELD(lx, ly))
1156 SetRandomAnimationValue(lx, ly);
1158 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1159 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1161 else /* border element */
1163 graphic = el2img(element);
1164 frame = getGraphicAnimationFrame(graphic, -1);
1167 if (element == EL_EXPANDABLE_WALL)
1169 boolean left_stopped = FALSE, right_stopped = FALSE;
1171 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1172 left_stopped = TRUE;
1173 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1174 right_stopped = TRUE;
1176 if (left_stopped && right_stopped)
1178 else if (left_stopped)
1180 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1181 frame = graphic_info[graphic].anim_frames - 1;
1183 else if (right_stopped)
1185 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1186 frame = graphic_info[graphic].anim_frames - 1;
1191 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1192 else if (mask_mode == USE_MASKING)
1193 DrawGraphicThruMask(x, y, graphic, frame);
1195 DrawGraphic(x, y, graphic, frame);
1198 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1199 int cut_mode, int mask_mode)
1201 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1202 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1203 cut_mode, mask_mode);
1206 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1209 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1212 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1215 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1218 void DrawLevelElementThruMask(int x, int y, int element)
1220 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1223 void DrawLevelFieldThruMask(int x, int y)
1225 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1228 #define TILE_GFX_ELEMENT(x, y) \
1229 (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ? \
1230 GfxElement[x][y] : Feld[x][y])
1232 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1236 int sx = SCREENX(x), sy = SCREENY(y);
1238 int width, height, cx, cy, i;
1240 int crumbled_border_size = graphic_info[graphic].border_size;
1242 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1244 static int xy[4][2] =
1253 if (x == 0 && y == 7)
1254 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1255 crumbled_border_size);
1258 if (!IN_LEV_FIELD(x, y))
1261 element = TILE_GFX_ELEMENT(x, y);
1263 /* crumble field itself */
1264 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1266 if (!IN_SCR_FIELD(sx, sy))
1269 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1271 for (i = 0; i < 4; i++)
1273 int xx = x + xy[i][0];
1274 int yy = y + xy[i][1];
1277 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1280 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1283 /* check if neighbour field is of same type */
1284 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1288 if (Feld[x][y] == EL_CUSTOM_START + 123)
1289 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1290 i, Feld[x][y], element,
1291 GFX_CRUMBLED(element), IS_MOVING(x, y));
1294 if (i == 1 || i == 2)
1296 width = crumbled_border_size;
1298 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1304 height = crumbled_border_size;
1306 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1309 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1310 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1313 MarkTileDirty(sx, sy);
1315 else /* crumble neighbour fields */
1318 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1321 for (i = 0; i < 4; i++)
1323 int xx = x + xy[i][0];
1324 int yy = y + xy[i][1];
1325 int sxx = sx + xy[i][0];
1326 int syy = sy + xy[i][1];
1329 if (!IN_LEV_FIELD(xx, yy) ||
1330 !IN_SCR_FIELD(sxx, syy) ||
1334 element = TILE_GFX_ELEMENT(xx, yy);
1336 if (!GFX_CRUMBLED(element))
1339 if (!IN_LEV_FIELD(xx, yy) ||
1340 !IN_SCR_FIELD(sxx, syy) ||
1341 !GFX_CRUMBLED(Feld[xx][yy]) ||
1347 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1348 crumbled_border_size = graphic_info[graphic].border_size;
1350 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1353 if (i == 1 || i == 2)
1355 width = crumbled_border_size;
1357 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1363 height = crumbled_border_size;
1365 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1368 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1369 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1371 MarkTileDirty(sxx, syy);
1376 void DrawLevelFieldCrumbledSand(int x, int y)
1381 if (!IN_LEV_FIELD(x, y))
1384 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1386 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1388 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1392 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1396 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1397 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1399 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1400 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1402 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1403 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1404 int sx = SCREENX(x), sy = SCREENY(y);
1406 DrawGraphic(sx, sy, graphic1, frame1);
1407 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1410 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1412 int sx = SCREENX(x), sy = SCREENY(y);
1413 static int xy[4][2] =
1422 for (i = 0; i < 4; i++)
1424 int xx = x + xy[i][0];
1425 int yy = y + xy[i][1];
1426 int sxx = sx + xy[i][0];
1427 int syy = sy + xy[i][1];
1429 if (!IN_LEV_FIELD(xx, yy) ||
1430 !IN_SCR_FIELD(sxx, syy) ||
1431 !GFX_CRUMBLED(Feld[xx][yy]) ||
1435 DrawLevelField(xx, yy);
1439 static int getBorderElement(int x, int y)
1443 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1444 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1445 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1446 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1447 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1448 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1449 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1451 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1452 int steel_position = (x == -1 && y == -1 ? 0 :
1453 x == lev_fieldx && y == -1 ? 1 :
1454 x == -1 && y == lev_fieldy ? 2 :
1455 x == lev_fieldx && y == lev_fieldy ? 3 :
1456 x == -1 || x == lev_fieldx ? 4 :
1457 y == -1 || y == lev_fieldy ? 5 : 6);
1459 return border[steel_position][steel_type];
1462 void DrawScreenElement(int x, int y, int element)
1464 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1465 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1468 void DrawLevelElement(int x, int y, int element)
1470 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1471 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1474 void DrawScreenField(int x, int y)
1476 int lx = LEVELX(x), ly = LEVELY(y);
1477 int element, content;
1479 if (!IN_LEV_FIELD(lx, ly))
1481 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1484 element = getBorderElement(lx, ly);
1486 DrawScreenElement(x, y, element);
1490 element = Feld[lx][ly];
1491 content = Store[lx][ly];
1493 if (IS_MOVING(lx, ly))
1495 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1496 boolean cut_mode = NO_CUTTING;
1498 if (element == EL_QUICKSAND_EMPTYING ||
1499 element == EL_MAGIC_WALL_EMPTYING ||
1500 element == EL_BD_MAGIC_WALL_EMPTYING ||
1501 element == EL_AMOEBA_DROPPING)
1502 cut_mode = CUT_ABOVE;
1503 else if (element == EL_QUICKSAND_FILLING ||
1504 element == EL_MAGIC_WALL_FILLING ||
1505 element == EL_BD_MAGIC_WALL_FILLING)
1506 cut_mode = CUT_BELOW;
1508 if (cut_mode == CUT_ABOVE)
1509 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1511 DrawScreenElement(x, y, EL_EMPTY);
1514 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1515 else if (cut_mode == NO_CUTTING)
1516 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1518 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1520 if (content == EL_ACID)
1522 int dir = MovDir[lx][ly];
1523 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1524 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1526 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1529 else if (IS_BLOCKED(lx, ly))
1534 boolean cut_mode = NO_CUTTING;
1535 int element_old, content_old;
1537 Blocked2Moving(lx, ly, &oldx, &oldy);
1540 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1541 MovDir[oldx][oldy] == MV_RIGHT);
1543 element_old = Feld[oldx][oldy];
1544 content_old = Store[oldx][oldy];
1546 if (element_old == EL_QUICKSAND_EMPTYING ||
1547 element_old == EL_MAGIC_WALL_EMPTYING ||
1548 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1549 element_old == EL_AMOEBA_DROPPING)
1550 cut_mode = CUT_ABOVE;
1552 DrawScreenElement(x, y, EL_EMPTY);
1555 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1557 else if (cut_mode == NO_CUTTING)
1558 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1561 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1564 else if (IS_DRAWABLE(element))
1565 DrawScreenElement(x, y, element);
1567 DrawScreenElement(x, y, EL_EMPTY);
1570 void DrawLevelField(int x, int y)
1572 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1573 DrawScreenField(SCREENX(x), SCREENY(y));
1574 else if (IS_MOVING(x, y))
1578 Moving2Blocked(x, y, &newx, &newy);
1579 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1580 DrawScreenField(SCREENX(newx), SCREENY(newy));
1582 else if (IS_BLOCKED(x, y))
1586 Blocked2Moving(x, y, &oldx, &oldy);
1587 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1588 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1592 void DrawMiniElement(int x, int y, int element)
1596 graphic = el2edimg(element);
1597 DrawMiniGraphic(x, y, graphic);
1600 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1602 int x = sx + scroll_x, y = sy + scroll_y;
1604 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1605 DrawMiniElement(sx, sy, EL_EMPTY);
1606 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1607 DrawMiniElement(sx, sy, Feld[x][y]);
1609 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1612 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1613 int x, int y, int xsize, int ysize, int font_nr)
1615 int font_width = getFontWidth(font_nr);
1616 int font_height = getFontHeight(font_nr);
1617 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1620 int dst_x = SX + startx + x * font_width;
1621 int dst_y = SY + starty + y * font_height;
1622 int width = graphic_info[graphic].width;
1623 int height = graphic_info[graphic].height;
1624 int inner_width = MAX(width - 2 * font_width, font_width);
1625 int inner_height = MAX(height - 2 * font_height, font_height);
1626 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1627 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1628 boolean draw_masked = graphic_info[graphic].draw_masked;
1630 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1632 if (src_bitmap == NULL || width < font_width || height < font_height)
1634 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1638 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1639 inner_sx + (x - 1) * font_width % inner_width);
1640 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1641 inner_sy + (y - 1) * font_height % inner_height);
1645 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1646 dst_x - src_x, dst_y - src_y);
1647 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1651 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1655 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1657 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1658 boolean draw_masked = graphic_info[graphic].draw_masked;
1659 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1660 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1661 boolean no_delay = (tape.index_search);
1662 unsigned long anim_delay = 0;
1663 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1664 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1665 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1666 int font_width = getFontWidth(font_nr);
1667 int font_height = getFontHeight(font_nr);
1668 int max_xsize = level.envelope_xsize[envelope_nr];
1669 int max_ysize = level.envelope_ysize[envelope_nr];
1670 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1671 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1672 int xend = max_xsize;
1673 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1674 int xstep = (xstart < xend ? 1 : 0);
1675 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1678 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1680 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1681 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1682 int sx = (SXSIZE - xsize * font_width) / 2;
1683 int sy = (SYSIZE - ysize * font_height) / 2;
1686 SetDrawtoField(DRAW_BUFFERED);
1688 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1690 SetDrawtoField(DRAW_BACKBUFFER);
1692 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1693 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1695 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1696 level.envelope_text[envelope_nr], font_nr, max_xsize,
1697 xsize - 2, ysize - 2, mask_mode);
1699 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1702 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1706 void ShowEnvelope(int envelope_nr)
1708 int element = EL_ENVELOPE_1 + envelope_nr;
1709 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1710 int sound_opening = element_info[element].sound[ACTION_OPENING];
1711 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1712 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1713 boolean no_delay = (tape.index_search);
1714 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1715 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1716 int anim_mode = graphic_info[graphic].anim_mode;
1717 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1718 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1720 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1722 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1724 if (anim_mode == ANIM_DEFAULT)
1725 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1727 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1730 Delay(wait_delay_value);
1732 WaitForEventToContinue();
1734 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1736 if (anim_mode != ANIM_NONE)
1737 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1739 if (anim_mode == ANIM_DEFAULT)
1740 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1742 game.envelope_active = FALSE;
1744 SetDrawtoField(DRAW_BUFFERED);
1746 redraw_mask |= REDRAW_FIELD;
1750 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1752 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1753 int mini_startx = src_bitmap->width * 3 / 4;
1754 int mini_starty = src_bitmap->height * 2 / 3;
1755 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1756 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1758 *bitmap = src_bitmap;
1763 void DrawMicroElement(int xpos, int ypos, int element)
1767 int graphic = el2preimg(element);
1769 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1770 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1778 SetDrawBackgroundMask(REDRAW_NONE);
1781 for (x = BX1; x <= BX2; x++)
1782 for (y = BY1; y <= BY2; y++)
1783 DrawScreenField(x, y);
1785 redraw_mask |= REDRAW_FIELD;
1788 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1792 for (x = 0; x < size_x; x++)
1793 for (y = 0; y < size_y; y++)
1794 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1796 redraw_mask |= REDRAW_FIELD;
1799 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1803 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1805 if (lev_fieldx < STD_LEV_FIELDX)
1806 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1807 if (lev_fieldy < STD_LEV_FIELDY)
1808 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1810 xpos += MICRO_TILEX;
1811 ypos += MICRO_TILEY;
1813 for (x = -1; x <= STD_LEV_FIELDX; x++)
1815 for (y = -1; y <= STD_LEV_FIELDY; y++)
1817 int lx = from_x + x, ly = from_y + y;
1819 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1820 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1821 level.field[lx][ly]);
1822 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1823 && BorderElement != EL_EMPTY)
1824 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1825 getBorderElement(lx, ly));
1829 redraw_mask |= REDRAW_MICROLEVEL;
1832 #define MICROLABEL_EMPTY 0
1833 #define MICROLABEL_LEVEL_NAME 1
1834 #define MICROLABEL_CREATED_BY 2
1835 #define MICROLABEL_LEVEL_AUTHOR 3
1836 #define MICROLABEL_IMPORTED_FROM 4
1837 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1839 static void DrawMicroLevelLabelExt(int mode)
1841 char label_text[MAX_OUTPUT_LINESIZE + 1];
1842 int max_len_label_text;
1843 int font_nr = FONT_TEXT_2;
1845 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1846 font_nr = FONT_TEXT_3;
1848 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1850 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1852 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1853 mode == MICROLABEL_CREATED_BY ? "created by" :
1854 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1855 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1856 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1857 leveldir_current->imported_from : ""),
1858 max_len_label_text);
1859 label_text[max_len_label_text] = '\0';
1861 if (strlen(label_text) > 0)
1863 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1864 int lypos = MICROLABEL_YPOS;
1866 DrawText(lxpos, lypos, label_text, font_nr);
1869 redraw_mask |= REDRAW_MICROLEVEL;
1872 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1874 static unsigned long scroll_delay = 0;
1875 static unsigned long label_delay = 0;
1876 static int from_x, from_y, scroll_direction;
1877 static int label_state, label_counter;
1878 int last_game_status = game_status; /* save current game status */
1880 /* force PREVIEW font on preview level */
1881 game_status = GAME_MODE_PSEUDO_PREVIEW;
1885 from_x = from_y = 0;
1886 scroll_direction = MV_RIGHT;
1890 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1891 DrawMicroLevelLabelExt(label_state);
1893 /* initialize delay counters */
1894 DelayReached(&scroll_delay, 0);
1895 DelayReached(&label_delay, 0);
1897 if (leveldir_current->name)
1899 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1900 int lxpos = SX + (SXSIZE - text_width) / 2;
1901 int lypos = SY + 352;
1903 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1906 game_status = last_game_status; /* restore current game status */
1911 /* scroll micro level, if needed */
1912 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1913 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1915 switch (scroll_direction)
1921 scroll_direction = MV_UP;
1925 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1928 scroll_direction = MV_DOWN;
1935 scroll_direction = MV_RIGHT;
1939 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1942 scroll_direction = MV_LEFT;
1949 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1952 /* redraw micro level label, if needed */
1953 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1954 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1955 strcmp(level.author, leveldir_current->name) != 0 &&
1956 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1958 int max_label_counter = 23;
1960 if (leveldir_current->imported_from != NULL)
1961 max_label_counter += 14;
1963 label_counter = (label_counter + 1) % max_label_counter;
1964 label_state = (label_counter >= 0 && label_counter <= 7 ?
1965 MICROLABEL_LEVEL_NAME :
1966 label_counter >= 9 && label_counter <= 12 ?
1967 MICROLABEL_CREATED_BY :
1968 label_counter >= 14 && label_counter <= 21 ?
1969 MICROLABEL_LEVEL_AUTHOR :
1970 label_counter >= 23 && label_counter <= 26 ?
1971 MICROLABEL_IMPORTED_FROM :
1972 label_counter >= 28 && label_counter <= 35 ?
1973 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1974 DrawMicroLevelLabelExt(label_state);
1977 game_status = last_game_status; /* restore current game status */
1980 void WaitForEventToContinue()
1982 boolean still_wait = TRUE;
1984 /* simulate releasing mouse button over last gadget, if still pressed */
1986 HandleGadgets(-1, -1, 0);
1988 button_status = MB_RELEASED;
2000 case EVENT_BUTTONPRESS:
2001 case EVENT_KEYPRESS:
2005 case EVENT_KEYRELEASE:
2006 ClearPlayerAction();
2010 HandleOtherEvents(&event);
2014 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2021 /* don't eat all CPU time */
2026 #define MAX_REQUEST_LINES 13
2027 #define MAX_REQUEST_LINE_FONT1_LEN 7
2028 #define MAX_REQUEST_LINE_FONT2_LEN 10
2030 boolean Request(char *text, unsigned int req_state)
2032 int mx, my, ty, result = -1;
2033 unsigned int old_door_state;
2034 int last_game_status = game_status; /* save current game status */
2035 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2036 int font_nr = FONT_TEXT_2;
2037 int max_word_len = 0;
2040 for (text_ptr = text; *text_ptr; text_ptr++)
2042 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2044 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2046 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2047 font_nr = FONT_LEVEL_NUMBER;
2054 /* disable deactivated drawing when quick-loading level tape recording */
2055 if (tape.playing && tape.index_search)
2057 SetDrawDeactivationMask(REDRAW_NONE);
2058 audio.sound_deactivated = FALSE;
2063 SetMouseCursor(CURSOR_DEFAULT);
2066 #if defined(PLATFORM_UNIX)
2067 /* pause network game while waiting for request to answer */
2068 if (options.network &&
2069 game_status == GAME_MODE_PLAYING &&
2070 req_state & REQUEST_WAIT_FOR)
2071 SendToServer_PausePlaying();
2074 old_door_state = GetDoorState();
2076 /* simulate releasing mouse button over last gadget, if still pressed */
2078 HandleGadgets(-1, -1, 0);
2082 CloseDoor(DOOR_CLOSE_1);
2084 /* save old door content */
2085 BlitBitmap(bitmap_db_door, bitmap_db_door,
2086 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2087 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2089 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2091 /* clear door drawing field */
2092 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2094 /* force DOOR font on preview level */
2095 game_status = GAME_MODE_PSEUDO_DOOR;
2097 /* write text for request */
2098 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2100 char text_line[max_request_line_len + 1];
2106 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2109 if (!tc || tc == ' ')
2120 strncpy(text_line, text, tl);
2123 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2124 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2125 text_line, font_nr);
2127 text += tl + (tc == ' ' ? 1 : 0);
2130 game_status = last_game_status; /* restore current game status */
2132 if (req_state & REQ_ASK)
2134 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2135 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2137 else if (req_state & REQ_CONFIRM)
2139 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2141 else if (req_state & REQ_PLAYER)
2143 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2144 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2145 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2146 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2149 /* copy request gadgets to door backbuffer */
2150 BlitBitmap(drawto, bitmap_db_door,
2151 DX, DY, DXSIZE, DYSIZE,
2152 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2154 OpenDoor(DOOR_OPEN_1);
2160 if (!(req_state & REQUEST_WAIT_FOR))
2162 SetDrawBackgroundMask(REDRAW_FIELD);
2167 if (game_status != GAME_MODE_MAIN)
2170 button_status = MB_RELEASED;
2172 request_gadget_id = -1;
2174 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2177 SetMouseCursor(CURSOR_DEFAULT);
2190 case EVENT_BUTTONPRESS:
2191 case EVENT_BUTTONRELEASE:
2192 case EVENT_MOTIONNOTIFY:
2194 if (event.type == EVENT_MOTIONNOTIFY)
2196 if (!PointerInWindow(window))
2197 continue; /* window and pointer are on different screens */
2202 motion_status = TRUE;
2203 mx = ((MotionEvent *) &event)->x;
2204 my = ((MotionEvent *) &event)->y;
2208 motion_status = FALSE;
2209 mx = ((ButtonEvent *) &event)->x;
2210 my = ((ButtonEvent *) &event)->y;
2211 if (event.type == EVENT_BUTTONPRESS)
2212 button_status = ((ButtonEvent *) &event)->button;
2214 button_status = MB_RELEASED;
2217 /* this sets 'request_gadget_id' */
2218 HandleGadgets(mx, my, button_status);
2220 switch(request_gadget_id)
2222 case TOOL_CTRL_ID_YES:
2225 case TOOL_CTRL_ID_NO:
2228 case TOOL_CTRL_ID_CONFIRM:
2229 result = TRUE | FALSE;
2232 case TOOL_CTRL_ID_PLAYER_1:
2235 case TOOL_CTRL_ID_PLAYER_2:
2238 case TOOL_CTRL_ID_PLAYER_3:
2241 case TOOL_CTRL_ID_PLAYER_4:
2252 case EVENT_KEYPRESS:
2253 switch(GetEventKey((KeyEvent *)&event, TRUE))
2266 if (req_state & REQ_PLAYER)
2270 case EVENT_KEYRELEASE:
2271 ClearPlayerAction();
2275 HandleOtherEvents(&event);
2279 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2281 int joy = AnyJoystick();
2283 if (joy & JOY_BUTTON_1)
2285 else if (joy & JOY_BUTTON_2)
2291 /* don't eat all CPU time */
2295 if (game_status != GAME_MODE_MAIN)
2300 if (!(req_state & REQ_STAY_OPEN))
2302 CloseDoor(DOOR_CLOSE_1);
2304 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2306 BlitBitmap(bitmap_db_door, bitmap_db_door,
2307 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2308 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2309 OpenDoor(DOOR_OPEN_1);
2315 SetDrawBackgroundMask(REDRAW_FIELD);
2317 #if defined(PLATFORM_UNIX)
2318 /* continue network game after request */
2319 if (options.network &&
2320 game_status == GAME_MODE_PLAYING &&
2321 req_state & REQUEST_WAIT_FOR)
2322 SendToServer_ContinuePlaying();
2326 /* restore deactivated drawing when quick-loading level tape recording */
2327 if (tape.playing && tape.index_search)
2329 SetDrawDeactivationMask(REDRAW_FIELD);
2330 audio.sound_deactivated = TRUE;
2337 unsigned int OpenDoor(unsigned int door_state)
2339 unsigned int new_door_state;
2341 if (door_state & DOOR_COPY_BACK)
2343 BlitBitmap(bitmap_db_door, bitmap_db_door,
2344 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2345 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2346 door_state &= ~DOOR_COPY_BACK;
2349 new_door_state = MoveDoor(door_state);
2351 return(new_door_state);
2354 unsigned int CloseDoor(unsigned int door_state)
2356 unsigned int new_door_state;
2358 BlitBitmap(backbuffer, bitmap_db_door,
2359 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2360 BlitBitmap(backbuffer, bitmap_db_door,
2361 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2363 new_door_state = MoveDoor(door_state);
2365 return(new_door_state);
2368 unsigned int GetDoorState()
2370 return MoveDoor(DOOR_GET_STATE);
2373 unsigned int SetDoorState(unsigned int door_state)
2375 return MoveDoor(door_state | DOOR_SET_STATE);
2378 unsigned int MoveDoor(unsigned int door_state)
2380 static int door1 = DOOR_OPEN_1;
2381 static int door2 = DOOR_CLOSE_2;
2382 unsigned long door_delay = 0;
2383 unsigned long door_delay_value;
2386 if (door_state == DOOR_GET_STATE)
2387 return(door1 | door2);
2389 if (door_state & DOOR_SET_STATE)
2391 if (door_state & DOOR_ACTION_1)
2392 door1 = door_state & DOOR_ACTION_1;
2393 if (door_state & DOOR_ACTION_2)
2394 door2 = door_state & DOOR_ACTION_2;
2396 return(door1 | door2);
2399 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2400 door_state &= ~DOOR_OPEN_1;
2401 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2402 door_state &= ~DOOR_CLOSE_1;
2403 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2404 door_state &= ~DOOR_OPEN_2;
2405 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2406 door_state &= ~DOOR_CLOSE_2;
2408 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2411 if (setup.quick_doors)
2413 stepsize = 20; /* must be choosen to always draw last frame */
2414 door_delay_value = 0;
2417 StopSound(SND_DOOR_OPENING);
2418 StopSound(SND_DOOR_CLOSING);
2422 if (global.autoplay_leveldir)
2424 door_state |= DOOR_NO_DELAY;
2425 door_state &= ~DOOR_CLOSE_ALL;
2428 if (door_state & DOOR_ACTION)
2430 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2431 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2432 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2433 int end = (door_state & DOOR_ACTION_1 &&
2434 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2437 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2439 /* opening door sound has priority over simultaneously closing door */
2440 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2441 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2442 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2443 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2446 for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2448 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2449 GC gc = bitmap->stored_clip_gc;
2451 if (door_state & DOOR_ACTION_1)
2453 int a = MIN(x * door_1.step_offset, end);
2454 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2458 BlitBitmap(bitmap_db_door, drawto,
2459 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2460 DXSIZE,DYSIZE - i / 2, DX, DY);
2462 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2465 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2467 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2468 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2469 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2470 int dst2_x = DX, dst2_y = DY;
2471 int width = i, height = DYSIZE;
2473 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2474 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2477 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2478 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2481 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2483 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2484 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2485 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2486 int dst2_x = DX, dst2_y = DY;
2487 int width = DXSIZE, height = i;
2489 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2490 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2493 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2494 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2497 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2499 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2501 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2502 BlitBitmapMasked(bitmap, drawto,
2503 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2504 DX + DXSIZE - i, DY + j);
2505 BlitBitmapMasked(bitmap, drawto,
2506 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2507 DX + DXSIZE - i, DY + 140 + j);
2508 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2509 DY - (DOOR_GFX_PAGEY1 + j));
2510 BlitBitmapMasked(bitmap, drawto,
2511 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2513 BlitBitmapMasked(bitmap, drawto,
2514 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2517 BlitBitmapMasked(bitmap, drawto,
2518 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2520 BlitBitmapMasked(bitmap, drawto,
2521 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2523 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2524 BlitBitmapMasked(bitmap, drawto,
2525 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2526 DX + DXSIZE - i, DY + 77 + j);
2527 BlitBitmapMasked(bitmap, drawto,
2528 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2529 DX + DXSIZE - i, DY + 203 + j);
2532 redraw_mask |= REDRAW_DOOR_1;
2533 door_1_done = (a == end);
2536 if (door_state & DOOR_ACTION_2)
2538 int a = MIN(x * door_2.step_offset, VXSIZE);
2539 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2543 BlitBitmap(bitmap_db_door, drawto,
2544 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2545 VXSIZE, VYSIZE - i / 2, VX, VY);
2547 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2550 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2552 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2553 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2554 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2555 int dst2_x = VX, dst2_y = VY;
2556 int width = i, height = VYSIZE;
2558 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2559 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2562 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2563 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2566 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2568 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2569 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2570 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2571 int dst2_x = VX, dst2_y = VY;
2572 int width = VXSIZE, height = i;
2574 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2575 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2578 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2579 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2582 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2584 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2586 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2587 BlitBitmapMasked(bitmap, drawto,
2588 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2589 VX + VXSIZE - i, VY + j);
2590 SetClipOrigin(bitmap, gc,
2591 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2592 BlitBitmapMasked(bitmap, drawto,
2593 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2596 BlitBitmapMasked(bitmap, drawto,
2597 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2598 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2599 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2600 BlitBitmapMasked(bitmap, drawto,
2601 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2603 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2606 redraw_mask |= REDRAW_DOOR_2;
2607 door_2_done = (a == VXSIZE);
2612 if (game_status == GAME_MODE_MAIN)
2615 if (!(door_state & DOOR_NO_DELAY))
2616 WaitUntilDelayReached(&door_delay, door_delay_value);
2621 if (setup.quick_doors)
2623 StopSound(SND_DOOR_OPENING);
2624 StopSound(SND_DOOR_CLOSING);
2628 if (door_state & DOOR_ACTION_1)
2629 door1 = door_state & DOOR_ACTION_1;
2630 if (door_state & DOOR_ACTION_2)
2631 door2 = door_state & DOOR_ACTION_2;
2633 return (door1 | door2);
2636 void DrawSpecialEditorDoor()
2638 /* draw bigger toolbox window */
2639 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2640 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2642 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2643 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2646 redraw_mask |= REDRAW_ALL;
2649 void UndrawSpecialEditorDoor()
2651 /* draw normal tape recorder window */
2652 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2653 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2656 redraw_mask |= REDRAW_ALL;
2660 /* ---------- new tool button stuff ---------------------------------------- */
2662 /* graphic position values for tool buttons */
2663 #define TOOL_BUTTON_YES_XPOS 2
2664 #define TOOL_BUTTON_YES_YPOS 250
2665 #define TOOL_BUTTON_YES_GFX_YPOS 0
2666 #define TOOL_BUTTON_YES_XSIZE 46
2667 #define TOOL_BUTTON_YES_YSIZE 28
2668 #define TOOL_BUTTON_NO_XPOS 52
2669 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2670 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2671 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2672 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2673 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2674 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2675 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2676 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2677 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2678 #define TOOL_BUTTON_PLAYER_XSIZE 30
2679 #define TOOL_BUTTON_PLAYER_YSIZE 30
2680 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2681 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2682 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2683 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2684 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2685 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2686 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2687 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2688 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2689 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2690 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2691 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2692 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2693 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2694 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2695 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2696 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2697 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2698 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2699 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2708 } toolbutton_info[NUM_TOOL_BUTTONS] =
2711 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2712 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2713 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2718 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2719 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2720 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2725 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2726 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2727 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2728 TOOL_CTRL_ID_CONFIRM,
2732 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2733 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2734 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2735 TOOL_CTRL_ID_PLAYER_1,
2739 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2740 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2741 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2742 TOOL_CTRL_ID_PLAYER_2,
2746 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2747 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2748 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2749 TOOL_CTRL_ID_PLAYER_3,
2753 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2754 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2755 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2756 TOOL_CTRL_ID_PLAYER_4,
2761 void CreateToolButtons()
2765 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2767 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2768 Bitmap *deco_bitmap = None;
2769 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2770 struct GadgetInfo *gi;
2771 unsigned long event_mask;
2772 int gd_xoffset, gd_yoffset;
2773 int gd_x1, gd_x2, gd_y;
2776 event_mask = GD_EVENT_RELEASED;
2778 gd_xoffset = toolbutton_info[i].xpos;
2779 gd_yoffset = toolbutton_info[i].ypos;
2780 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2781 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2782 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2784 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2786 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2788 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2789 &deco_bitmap, &deco_x, &deco_y);
2790 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2791 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2794 gi = CreateGadget(GDI_CUSTOM_ID, id,
2795 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2796 GDI_X, DX + toolbutton_info[i].x,
2797 GDI_Y, DY + toolbutton_info[i].y,
2798 GDI_WIDTH, toolbutton_info[i].width,
2799 GDI_HEIGHT, toolbutton_info[i].height,
2800 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2801 GDI_STATE, GD_BUTTON_UNPRESSED,
2802 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2803 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2804 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2805 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2806 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2807 GDI_DECORATION_SHIFTING, 1, 1,
2808 GDI_EVENT_MASK, event_mask,
2809 GDI_CALLBACK_ACTION, HandleToolButtons,
2813 Error(ERR_EXIT, "cannot create gadget");
2815 tool_gadget[id] = gi;
2819 void FreeToolButtons()
2823 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2824 FreeGadget(tool_gadget[i]);
2827 static void UnmapToolButtons()
2831 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2832 UnmapGadget(tool_gadget[i]);
2835 static void HandleToolButtons(struct GadgetInfo *gi)
2837 request_gadget_id = gi->custom_id;
2840 int get_next_element(int element)
2844 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2845 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2846 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2847 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2848 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2849 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2850 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2852 default: return element;
2856 int el_act_dir2img(int element, int action, int direction)
2858 element = GFX_ELEMENT(element);
2859 direction = MV_DIR_BIT(direction);
2861 return element_info[element].direction_graphic[action][direction];
2864 static int el_act_dir2crm(int element, int action, int direction)
2866 element = GFX_ELEMENT(element);
2867 direction = MV_DIR_BIT(direction);
2869 return element_info[element].direction_crumbled[action][direction];
2872 int el_act2img(int element, int action)
2874 element = GFX_ELEMENT(element);
2876 return element_info[element].graphic[action];
2879 int el_act2crm(int element, int action)
2881 element = GFX_ELEMENT(element);
2883 return element_info[element].crumbled[action];
2886 int el_dir2img(int element, int direction)
2888 element = GFX_ELEMENT(element);
2890 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2893 int el2img(int element)
2895 element = GFX_ELEMENT(element);
2897 return element_info[element].graphic[ACTION_DEFAULT];
2900 int el2edimg(int element)
2902 element = GFX_ELEMENT(element);
2904 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2907 int el2preimg(int element)
2909 element = GFX_ELEMENT(element);
2911 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];