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);
260 if (redraw_mask & REDRAW_DOOR_2)
263 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
265 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
269 if (redraw_mask & REDRAW_VIDEO_1)
270 BlitBitmap(backbuffer, window,
271 VX + VIDEO_DISPLAY1_XPOS, VY + VIDEO_DISPLAY1_YPOS,
272 VIDEO_DISPLAY_XSIZE, VIDEO_DISPLAY_YSIZE,
273 VX + VIDEO_DISPLAY1_XPOS, VY + VIDEO_DISPLAY1_YPOS);
274 if (redraw_mask & REDRAW_VIDEO_2)
275 BlitBitmap(backbuffer, window,
276 VX + VIDEO_DISPLAY2_XPOS, VY + VIDEO_DISPLAY2_YPOS,
277 VIDEO_DISPLAY_XSIZE, VIDEO_DISPLAY_YSIZE,
278 VX + VIDEO_DISPLAY2_XPOS, VY + VIDEO_DISPLAY2_YPOS);
279 if (redraw_mask & REDRAW_VIDEO_3)
280 BlitBitmap(backbuffer, window,
281 VX + VIDEO_CONTROL_XPOS, VY + VIDEO_CONTROL_YPOS,
282 VIDEO_CONTROL_XSIZE, VIDEO_CONTROL_YSIZE,
283 VX + VIDEO_CONTROL_XPOS, VY + VIDEO_CONTROL_YPOS);
288 if (redraw_mask & REDRAW_DOOR_3)
289 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
291 redraw_mask &= ~REDRAW_DOORS;
294 if (redraw_mask & REDRAW_MICROLEVEL)
296 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
297 SX, SY + 10 * TILEY);
299 redraw_mask &= ~REDRAW_MICROLEVEL;
302 if (redraw_mask & REDRAW_TILES)
304 for (x = 0; x < SCR_FIELDX; x++)
305 for (y = 0 ; y < SCR_FIELDY; y++)
306 if (redraw[redraw_x1 + x][redraw_y1 + y])
307 BlitBitmap(buffer, window,
308 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
309 SX + x * TILEX, SY + y * TILEY);
312 if (redraw_mask & REDRAW_FPS) /* display frames per second */
317 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
318 if (!global.fps_slowdown)
321 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
322 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
327 for (x = 0; x < MAX_BUF_XSIZE; x++)
328 for (y = 0; y < MAX_BUF_YSIZE; y++)
331 redraw_mask = REDRAW_NONE;
337 long fading_delay = 300;
339 if (setup.fading && (redraw_mask & REDRAW_FIELD))
346 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
349 for (i = 0; i < 2 * FULL_SYSIZE; i++)
351 for (y = 0; y < FULL_SYSIZE; y++)
353 BlitBitmap(backbuffer, window,
354 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
362 for (i = 1; i < FULL_SYSIZE; i+=2)
363 BlitBitmap(backbuffer, window,
364 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
370 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
371 BlitBitmapMasked(backbuffer, window,
372 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
377 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
378 BlitBitmapMasked(backbuffer, window,
379 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
384 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
385 BlitBitmapMasked(backbuffer, window,
386 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
391 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
392 BlitBitmapMasked(backbuffer, window,
393 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
398 redraw_mask &= ~REDRAW_MAIN;
405 void SetMainBackgroundImage(int graphic)
407 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
408 graphic_info[graphic].bitmap ?
409 graphic_info[graphic].bitmap :
410 graphic_info[IMG_BACKGROUND].bitmap);
413 void SetDoorBackgroundImage(int graphic)
415 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
416 graphic_info[graphic].bitmap ?
417 graphic_info[graphic].bitmap :
418 graphic_info[IMG_BACKGROUND].bitmap);
421 void DrawBackground(int dest_x, int dest_y, int width, int height)
423 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
425 redraw_mask |= REDRAW_FIELD;
430 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
432 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
434 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
435 SetDrawtoField(DRAW_BUFFERED);
438 SetDrawtoField(DRAW_BACKBUFFER);
440 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
442 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
443 SetDrawtoField(DRAW_DIRECT);
447 void MarkTileDirty(int x, int y)
449 int xx = redraw_x1 + x;
450 int yy = redraw_y1 + y;
455 redraw[xx][yy] = TRUE;
456 redraw_mask |= REDRAW_TILES;
459 void SetBorderElement()
463 BorderElement = EL_EMPTY;
465 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
467 for (x = 0; x < lev_fieldx; x++)
469 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
470 BorderElement = EL_STEELWALL;
472 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
478 void SetRandomAnimationValue(int x, int y)
480 gfx.anim_random_frame = GfxRandom[x][y];
483 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
485 /* animation synchronized with global frame counter, not move position */
486 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
487 sync_frame = FrameCounter;
489 return getAnimationFrame(graphic_info[graphic].anim_frames,
490 graphic_info[graphic].anim_delay,
491 graphic_info[graphic].anim_mode,
492 graphic_info[graphic].anim_start_frame,
496 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
497 int graphic, int sync_frame, int mask_mode)
499 int frame = getGraphicAnimationFrame(graphic, sync_frame);
501 if (mask_mode == USE_MASKING)
502 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
504 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
507 inline void DrawGraphicAnimation(int x, int y, int graphic)
509 int lx = LEVELX(x), ly = LEVELY(y);
511 if (!IN_SCR_FIELD(x, y))
514 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
515 graphic, GfxFrame[lx][ly], NO_MASKING);
519 void DrawLevelGraphicAnimation(int x, int y, int graphic)
521 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
524 void DrawLevelElementAnimation(int x, int y, int element)
527 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
529 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
531 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
535 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
537 int sx = SCREENX(x), sy = SCREENY(y);
539 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
542 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
545 DrawGraphicAnimation(sx, sy, graphic);
547 if (GFX_CRUMBLED(Feld[x][y]))
548 DrawLevelFieldCrumbledSand(x, y);
551 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
553 int sx = SCREENX(x), sy = SCREENY(y);
556 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
559 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
561 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
564 DrawGraphicAnimation(sx, sy, graphic);
566 if (GFX_CRUMBLED(element))
567 DrawLevelFieldCrumbledSand(x, y);
570 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
572 if (player->use_murphy_graphic)
574 /* this works only because currently only one player can be "murphy" ... */
575 static int last_horizontal_dir = MV_LEFT;
576 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
578 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
579 last_horizontal_dir = move_dir;
581 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
583 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
585 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
591 return el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
594 static boolean equalGraphics(int graphic1, int graphic2)
596 struct GraphicInfo *g1 = &graphic_info[graphic1];
597 struct GraphicInfo *g2 = &graphic_info[graphic2];
599 return (g1->bitmap == g2->bitmap &&
600 g1->src_x == g2->src_x &&
601 g1->src_y == g2->src_y &&
602 g1->anim_frames == g2->anim_frames &&
603 g1->anim_delay == g2->anim_delay &&
604 g1->anim_mode == g2->anim_mode);
607 void DrawAllPlayers()
611 for (i = 0; i < MAX_PLAYERS; i++)
612 if (stored_player[i].active)
613 DrawPlayer(&stored_player[i]);
616 void DrawPlayerField(int x, int y)
618 if (!IS_PLAYER(x, y))
621 DrawPlayer(PLAYERINFO(x, y));
624 void DrawPlayer(struct PlayerInfo *player)
628 int move_dir = player->MovDir;
630 int last_jx = player->last_jx;
631 int last_jy = player->last_jy;
632 int next_jx = jx + (jx - last_jx);
633 int next_jy = jy + (jy - last_jy);
634 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
636 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
637 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
638 int last_jx = (player->is_moving ? jx - dx : jx);
639 int last_jy = (player->is_moving ? jy - dy : jy);
640 int next_jx = jx + dx;
641 int next_jy = jy + dy;
642 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
644 int sx = SCREENX(jx), sy = SCREENY(jy);
645 int sxx = 0, syy = 0;
646 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
648 int action = ACTION_DEFAULT;
649 int last_player_graphic = getPlayerGraphic(player, move_dir);
650 int last_player_frame = player->Frame;
653 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
657 if (!IN_LEV_FIELD(jx, jy))
659 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
660 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
661 printf("DrawPlayerField(): This should never happen!\n");
666 if (element == EL_EXPLOSION)
669 action = (player->is_pushing ? ACTION_PUSHING :
670 player->is_digging ? ACTION_DIGGING :
671 player->is_collecting ? ACTION_COLLECTING :
672 player->is_moving ? ACTION_MOVING :
673 player->is_snapping ? ACTION_SNAPPING :
674 player->is_dropping ? ACTION_DROPPING :
675 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
677 InitPlayerGfxAnimation(player, action, move_dir);
679 /* ----------------------------------------------------------------------- */
680 /* draw things in the field the player is leaving, if needed */
681 /* ----------------------------------------------------------------------- */
684 if (player->is_moving)
686 if (player_is_moving)
689 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
691 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
693 if (last_element == EL_DYNAMITE_ACTIVE ||
694 last_element == EL_SP_DISK_RED_ACTIVE)
695 DrawDynamite(last_jx, last_jy);
697 DrawLevelFieldThruMask(last_jx, last_jy);
699 else if (last_element == EL_DYNAMITE_ACTIVE ||
700 last_element == EL_SP_DISK_RED_ACTIVE)
701 DrawDynamite(last_jx, last_jy);
703 DrawLevelField(last_jx, last_jy);
705 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
706 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
709 if (!IN_SCR_FIELD(sx, sy))
712 if (setup.direct_draw)
713 SetDrawtoField(DRAW_BUFFERED);
715 /* ----------------------------------------------------------------------- */
716 /* draw things behind the player, if needed */
717 /* ----------------------------------------------------------------------- */
720 DrawLevelElement(jx, jy, Back[jx][jy]);
721 else if (IS_ACTIVE_BOMB(element))
722 DrawLevelElement(jx, jy, EL_EMPTY);
725 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
727 if (GFX_CRUMBLED(GfxElement[jx][jy]))
728 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
731 int old_element = GfxElement[jx][jy];
732 int old_graphic = el_act_dir2img(old_element, action, move_dir);
733 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
735 DrawGraphic(sx, sy, old_graphic, frame);
740 GfxElement[jx][jy] = EL_UNDEFINED;
742 DrawLevelField(jx, jy);
746 /* ----------------------------------------------------------------------- */
747 /* draw player himself */
748 /* ----------------------------------------------------------------------- */
752 graphic = getPlayerGraphic(player, move_dir);
754 /* in the case of changed player action or direction, prevent the current
755 animation frame from being restarted for identical animations */
756 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
757 player->Frame = last_player_frame;
761 if (player->use_murphy_graphic)
763 static int last_horizontal_dir = MV_LEFT;
765 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
766 last_horizontal_dir = move_dir;
768 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
770 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
772 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
774 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
778 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
782 frame = getGraphicAnimationFrame(graphic, player->Frame);
786 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
787 sxx = player->GfxPos;
789 syy = player->GfxPos;
792 if (!setup.soft_scrolling && ScreenMovPos)
795 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
797 if (SHIELD_ON(player))
799 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
800 IMG_SHIELD_NORMAL_ACTIVE);
801 int frame = getGraphicAnimationFrame(graphic, -1);
803 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
806 /* ----------------------------------------------------------------------- */
807 /* draw things the player is pushing, if needed */
808 /* ----------------------------------------------------------------------- */
811 printf("::: %d, %d [%d, %d] [%d]\n",
812 player->is_pushing, player_is_moving, player->GfxAction,
813 player->is_moving, player_is_moving);
817 if (player->is_pushing && player->is_moving)
819 if (player->is_pushing && player_is_moving)
822 int px = SCREENX(next_jx), py = SCREENY(next_jy);
824 if (Back[next_jx][next_jy])
825 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
827 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
828 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
832 int element = MovingOrBlocked2Element(next_jx, next_jy);
833 int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
835 int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
837 int frame = getGraphicAnimationFrame(graphic, player->Frame);
840 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
841 NO_CUTTING, NO_MASKING);
845 /* ----------------------------------------------------------------------- */
846 /* draw things in front of player (active dynamite or dynabombs) */
847 /* ----------------------------------------------------------------------- */
849 if (IS_ACTIVE_BOMB(element))
851 graphic = el2img(element);
852 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
854 if (game.emulation == EMU_SUPAPLEX)
855 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
857 DrawGraphicThruMask(sx, sy, graphic, frame);
860 if (player_is_moving && last_element == EL_EXPLOSION)
862 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
863 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
864 int phase = ExplodePhase[last_jx][last_jy] - 1;
865 int frame = getGraphicAnimationFrame(graphic, phase - delay);
868 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
871 /* ----------------------------------------------------------------------- */
872 /* draw elements the player is just walking/passing through/under */
873 /* ----------------------------------------------------------------------- */
875 /* handle the field the player is leaving ... */
876 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
877 DrawLevelField(last_jx, last_jy);
878 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
879 DrawLevelFieldThruMask(last_jx, last_jy);
882 if (!player->is_pushing)
885 /* ... and the field the player is entering */
886 if (IS_ACCESSIBLE_INSIDE(element))
887 DrawLevelField(jx, jy);
888 else if (IS_ACCESSIBLE_UNDER(element))
889 DrawLevelFieldThruMask(jx, jy);
892 if (setup.direct_draw)
894 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
895 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
896 int x_size = TILEX * (1 + ABS(jx - last_jx));
897 int y_size = TILEY * (1 + ABS(jy - last_jy));
899 BlitBitmap(drawto_field, window,
900 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
901 SetDrawtoField(DRAW_DIRECT);
904 MarkTileDirty(sx, sy);
907 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
909 struct GraphicInfo *g = &graphic_info[graphic];
913 if (g->offset_y == 0) /* frames are ordered horizontally */
915 int max_width = g->anim_frames_per_line * g->width;
917 *x = (g->src_x + frame * g->offset_x) % max_width;
918 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
920 else if (g->offset_x == 0) /* frames are ordered vertically */
922 int max_height = g->anim_frames_per_line * g->height;
924 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
925 *y = (g->src_y + frame * g->offset_y) % max_height;
927 else /* frames are ordered diagonally */
929 *x = g->src_x + frame * g->offset_x;
930 *y = g->src_y + frame * g->offset_y;
934 void DrawGraphic(int x, int y, int graphic, int frame)
937 if (!IN_SCR_FIELD(x, y))
939 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
940 printf("DrawGraphic(): This should never happen!\n");
945 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
949 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
955 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
956 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
959 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
962 if (!IN_SCR_FIELD(x, y))
964 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
965 printf("DrawGraphicThruMask(): This should never happen!\n");
970 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
975 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
983 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
984 drawing_gc = src_bitmap->stored_clip_gc;
986 GC drawing_gc = src_bitmap->stored_clip_gc;
987 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
988 int src_x = graphic_info[graphic].src_x;
989 int src_y = graphic_info[graphic].src_y;
990 int offset_x = graphic_info[graphic].offset_x;
991 int offset_y = graphic_info[graphic].offset_y;
993 src_x += frame * offset_x;
994 src_y += frame * offset_y;
998 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
999 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1002 void DrawMiniGraphic(int x, int y, int graphic)
1004 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1005 MarkTileDirty(x / 2, y / 2);
1008 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1010 struct GraphicInfo *g = &graphic_info[graphic];
1011 int mini_startx = 0;
1012 int mini_starty = g->bitmap->height * 2 / 3;
1014 *bitmap = g->bitmap;
1015 *x = mini_startx + g->src_x / 2;
1016 *y = mini_starty + g->src_y / 2;
1019 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1024 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1025 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1028 void DrawGraphicShifted(int x, int y, int dx, int dy, int graphic, int frame,
1029 int cut_mode, int mask_mode)
1034 int width = TILEX, height = TILEY;
1040 DrawGraphic(x, y, graphic, frame);
1044 if (dx || dy) /* shifted graphic */
1046 if (x < BX1) /* object enters playfield from the left */
1053 else if (x > BX2) /* object enters playfield from the right */
1059 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1065 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1067 else if (dx) /* general horizontal movement */
1068 MarkTileDirty(x + SIGN(dx), y);
1070 if (y < BY1) /* object enters playfield from the top */
1072 if (cut_mode==CUT_BELOW) /* object completely above top border */
1080 else if (y > BY2) /* object enters playfield from the bottom */
1086 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1092 else if (dy > 0 && cut_mode == CUT_ABOVE)
1094 if (y == BY2) /* object completely above bottom border */
1100 MarkTileDirty(x, y + 1);
1101 } /* object leaves playfield to the bottom */
1102 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1104 else if (dy) /* general vertical movement */
1105 MarkTileDirty(x, y + SIGN(dy));
1109 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1111 src_bitmap = graphic_info[graphic].bitmap;
1112 src_x = graphic_info[graphic].src_x;
1113 src_y = graphic_info[graphic].src_y;
1114 offset_x = graphic_info[graphic].offset_x;
1115 offset_y = graphic_info[graphic].offset_y;
1117 src_x += frame * offset_x;
1118 src_y += frame * offset_y;
1121 drawing_gc = src_bitmap->stored_clip_gc;
1126 dest_x = FX + x * TILEX + dx;
1127 dest_y = FY + y * TILEY + dy;
1130 if (!IN_SCR_FIELD(x,y))
1132 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1133 printf("DrawGraphicShifted(): This should never happen!\n");
1138 if (mask_mode == USE_MASKING)
1140 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1141 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1145 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1148 MarkTileDirty(x, y);
1151 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1152 int frame, int cut_mode)
1154 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1157 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1158 int cut_mode, int mask_mode)
1160 int lx = LEVELX(x), ly = LEVELY(y);
1164 if (IN_LEV_FIELD(lx, ly))
1166 SetRandomAnimationValue(lx, ly);
1168 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1169 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1171 else /* border element */
1173 graphic = el2img(element);
1174 frame = getGraphicAnimationFrame(graphic, -1);
1177 if (element == EL_EXPANDABLE_WALL)
1179 boolean left_stopped = FALSE, right_stopped = FALSE;
1181 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1182 left_stopped = TRUE;
1183 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1184 right_stopped = TRUE;
1186 if (left_stopped && right_stopped)
1188 else if (left_stopped)
1190 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1191 frame = graphic_info[graphic].anim_frames - 1;
1193 else if (right_stopped)
1195 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1196 frame = graphic_info[graphic].anim_frames - 1;
1201 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1202 else if (mask_mode == USE_MASKING)
1203 DrawGraphicThruMask(x, y, graphic, frame);
1205 DrawGraphic(x, y, graphic, frame);
1208 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1209 int cut_mode, int mask_mode)
1211 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1212 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1213 cut_mode, mask_mode);
1216 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1219 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1222 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1225 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1228 void DrawLevelElementThruMask(int x, int y, int element)
1230 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1233 void DrawLevelFieldThruMask(int x, int y)
1235 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1238 #define TILE_GFX_ELEMENT(x, y) \
1239 (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ? \
1240 GfxElement[x][y] : Feld[x][y])
1242 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1246 int sx = SCREENX(x), sy = SCREENY(y);
1248 int width, height, cx, cy, i;
1250 int crumbled_border_size = graphic_info[graphic].border_size;
1252 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1254 static int xy[4][2] =
1263 if (x == 0 && y == 7)
1264 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1265 crumbled_border_size);
1268 if (!IN_LEV_FIELD(x, y))
1271 element = TILE_GFX_ELEMENT(x, y);
1273 /* crumble field itself */
1274 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1276 if (!IN_SCR_FIELD(sx, sy))
1279 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1281 for (i = 0; i < 4; i++)
1283 int xx = x + xy[i][0];
1284 int yy = y + xy[i][1];
1287 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1290 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1293 /* check if neighbour field is of same type */
1294 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1298 if (Feld[x][y] == EL_CUSTOM_START + 123)
1299 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1300 i, Feld[x][y], element,
1301 GFX_CRUMBLED(element), IS_MOVING(x, y));
1304 if (i == 1 || i == 2)
1306 width = crumbled_border_size;
1308 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1314 height = crumbled_border_size;
1316 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1319 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1320 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1323 MarkTileDirty(sx, sy);
1325 else /* crumble neighbour fields */
1328 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1331 for (i = 0; i < 4; i++)
1333 int xx = x + xy[i][0];
1334 int yy = y + xy[i][1];
1335 int sxx = sx + xy[i][0];
1336 int syy = sy + xy[i][1];
1339 if (!IN_LEV_FIELD(xx, yy) ||
1340 !IN_SCR_FIELD(sxx, syy) ||
1344 element = TILE_GFX_ELEMENT(xx, yy);
1346 if (!GFX_CRUMBLED(element))
1349 if (!IN_LEV_FIELD(xx, yy) ||
1350 !IN_SCR_FIELD(sxx, syy) ||
1351 !GFX_CRUMBLED(Feld[xx][yy]) ||
1357 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1358 crumbled_border_size = graphic_info[graphic].border_size;
1360 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1363 if (i == 1 || i == 2)
1365 width = crumbled_border_size;
1367 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1373 height = crumbled_border_size;
1375 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1378 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1379 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1381 MarkTileDirty(sxx, syy);
1386 void DrawLevelFieldCrumbledSand(int x, int y)
1391 if (!IN_LEV_FIELD(x, y))
1394 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1396 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1398 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1402 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1406 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1407 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1409 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1410 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1412 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1413 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1414 int sx = SCREENX(x), sy = SCREENY(y);
1416 DrawGraphic(sx, sy, graphic1, frame1);
1417 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1420 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1422 int sx = SCREENX(x), sy = SCREENY(y);
1423 static int xy[4][2] =
1432 for (i = 0; i < 4; i++)
1434 int xx = x + xy[i][0];
1435 int yy = y + xy[i][1];
1436 int sxx = sx + xy[i][0];
1437 int syy = sy + xy[i][1];
1439 if (!IN_LEV_FIELD(xx, yy) ||
1440 !IN_SCR_FIELD(sxx, syy) ||
1441 !GFX_CRUMBLED(Feld[xx][yy]) ||
1445 DrawLevelField(xx, yy);
1449 static int getBorderElement(int x, int y)
1453 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1454 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1455 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1456 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1457 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1458 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1459 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1461 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1462 int steel_position = (x == -1 && y == -1 ? 0 :
1463 x == lev_fieldx && y == -1 ? 1 :
1464 x == -1 && y == lev_fieldy ? 2 :
1465 x == lev_fieldx && y == lev_fieldy ? 3 :
1466 x == -1 || x == lev_fieldx ? 4 :
1467 y == -1 || y == lev_fieldy ? 5 : 6);
1469 return border[steel_position][steel_type];
1472 void DrawScreenElement(int x, int y, int element)
1474 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1475 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1478 void DrawLevelElement(int x, int y, int element)
1480 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1481 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1484 void DrawScreenField(int x, int y)
1486 int lx = LEVELX(x), ly = LEVELY(y);
1487 int element, content;
1489 if (!IN_LEV_FIELD(lx, ly))
1491 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1494 element = getBorderElement(lx, ly);
1496 DrawScreenElement(x, y, element);
1500 element = Feld[lx][ly];
1501 content = Store[lx][ly];
1503 if (IS_MOVING(lx, ly))
1505 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1506 boolean cut_mode = NO_CUTTING;
1508 if (element == EL_QUICKSAND_EMPTYING ||
1509 element == EL_MAGIC_WALL_EMPTYING ||
1510 element == EL_BD_MAGIC_WALL_EMPTYING ||
1511 element == EL_AMOEBA_DROPPING)
1512 cut_mode = CUT_ABOVE;
1513 else if (element == EL_QUICKSAND_FILLING ||
1514 element == EL_MAGIC_WALL_FILLING ||
1515 element == EL_BD_MAGIC_WALL_FILLING)
1516 cut_mode = CUT_BELOW;
1518 if (cut_mode == CUT_ABOVE)
1519 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1521 DrawScreenElement(x, y, EL_EMPTY);
1524 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1525 else if (cut_mode == NO_CUTTING)
1526 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1528 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1530 if (content == EL_ACID)
1532 int dir = MovDir[lx][ly];
1533 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1534 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1536 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1539 else if (IS_BLOCKED(lx, ly))
1544 boolean cut_mode = NO_CUTTING;
1545 int element_old, content_old;
1547 Blocked2Moving(lx, ly, &oldx, &oldy);
1550 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1551 MovDir[oldx][oldy] == MV_RIGHT);
1553 element_old = Feld[oldx][oldy];
1554 content_old = Store[oldx][oldy];
1556 if (element_old == EL_QUICKSAND_EMPTYING ||
1557 element_old == EL_MAGIC_WALL_EMPTYING ||
1558 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1559 element_old == EL_AMOEBA_DROPPING)
1560 cut_mode = CUT_ABOVE;
1562 DrawScreenElement(x, y, EL_EMPTY);
1565 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1567 else if (cut_mode == NO_CUTTING)
1568 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1571 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1574 else if (IS_DRAWABLE(element))
1575 DrawScreenElement(x, y, element);
1577 DrawScreenElement(x, y, EL_EMPTY);
1580 void DrawLevelField(int x, int y)
1582 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1583 DrawScreenField(SCREENX(x), SCREENY(y));
1584 else if (IS_MOVING(x, y))
1588 Moving2Blocked(x, y, &newx, &newy);
1589 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1590 DrawScreenField(SCREENX(newx), SCREENY(newy));
1592 else if (IS_BLOCKED(x, y))
1596 Blocked2Moving(x, y, &oldx, &oldy);
1597 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1598 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1602 void DrawMiniElement(int x, int y, int element)
1606 graphic = el2edimg(element);
1607 DrawMiniGraphic(x, y, graphic);
1610 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1612 int x = sx + scroll_x, y = sy + scroll_y;
1614 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1615 DrawMiniElement(sx, sy, EL_EMPTY);
1616 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1617 DrawMiniElement(sx, sy, Feld[x][y]);
1619 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1622 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1623 int x, int y, int xsize, int ysize, int font_nr)
1625 int font_width = getFontWidth(font_nr);
1626 int font_height = getFontHeight(font_nr);
1627 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1630 int dst_x = SX + startx + x * font_width;
1631 int dst_y = SY + starty + y * font_height;
1632 int width = graphic_info[graphic].width;
1633 int height = graphic_info[graphic].height;
1634 int inner_width = MAX(width - 2 * font_width, font_width);
1635 int inner_height = MAX(height - 2 * font_height, font_height);
1636 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1637 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1638 boolean draw_masked = graphic_info[graphic].draw_masked;
1640 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1642 if (src_bitmap == NULL || width < font_width || height < font_height)
1644 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1648 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1649 inner_sx + (x - 1) * font_width % inner_width);
1650 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1651 inner_sy + (y - 1) * font_height % inner_height);
1655 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1656 dst_x - src_x, dst_y - src_y);
1657 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1661 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1665 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1667 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1668 boolean draw_masked = graphic_info[graphic].draw_masked;
1669 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1670 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1671 boolean no_delay = (tape.warp_forward);
1672 unsigned long anim_delay = 0;
1673 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1674 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1675 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1676 int font_width = getFontWidth(font_nr);
1677 int font_height = getFontHeight(font_nr);
1678 int max_xsize = level.envelope_xsize[envelope_nr];
1679 int max_ysize = level.envelope_ysize[envelope_nr];
1680 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1681 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1682 int xend = max_xsize;
1683 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1684 int xstep = (xstart < xend ? 1 : 0);
1685 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1688 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1690 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1691 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1692 int sx = (SXSIZE - xsize * font_width) / 2;
1693 int sy = (SYSIZE - ysize * font_height) / 2;
1696 SetDrawtoField(DRAW_BUFFERED);
1698 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1700 SetDrawtoField(DRAW_BACKBUFFER);
1702 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1703 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1705 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1706 level.envelope_text[envelope_nr], font_nr, max_xsize,
1707 xsize - 2, ysize - 2, mask_mode);
1709 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1712 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1716 void ShowEnvelope(int envelope_nr)
1718 int element = EL_ENVELOPE_1 + envelope_nr;
1719 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1720 int sound_opening = element_info[element].sound[ACTION_OPENING];
1721 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1722 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1723 boolean no_delay = (tape.warp_forward);
1724 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1725 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1726 int anim_mode = graphic_info[graphic].anim_mode;
1727 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1728 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1730 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1732 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1734 if (anim_mode == ANIM_DEFAULT)
1735 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1737 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1740 Delay(wait_delay_value);
1742 WaitForEventToContinue();
1744 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1746 if (anim_mode != ANIM_NONE)
1747 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1749 if (anim_mode == ANIM_DEFAULT)
1750 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1752 game.envelope_active = FALSE;
1754 SetDrawtoField(DRAW_BUFFERED);
1756 redraw_mask |= REDRAW_FIELD;
1760 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1762 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1763 int mini_startx = src_bitmap->width * 3 / 4;
1764 int mini_starty = src_bitmap->height * 2 / 3;
1765 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1766 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1768 *bitmap = src_bitmap;
1773 void DrawMicroElement(int xpos, int ypos, int element)
1777 int graphic = el2preimg(element);
1779 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1780 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1788 SetDrawBackgroundMask(REDRAW_NONE);
1791 for (x = BX1; x <= BX2; x++)
1792 for (y = BY1; y <= BY2; y++)
1793 DrawScreenField(x, y);
1795 redraw_mask |= REDRAW_FIELD;
1798 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1802 for (x = 0; x < size_x; x++)
1803 for (y = 0; y < size_y; y++)
1804 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1806 redraw_mask |= REDRAW_FIELD;
1809 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1813 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1815 if (lev_fieldx < STD_LEV_FIELDX)
1816 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1817 if (lev_fieldy < STD_LEV_FIELDY)
1818 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1820 xpos += MICRO_TILEX;
1821 ypos += MICRO_TILEY;
1823 for (x = -1; x <= STD_LEV_FIELDX; x++)
1825 for (y = -1; y <= STD_LEV_FIELDY; y++)
1827 int lx = from_x + x, ly = from_y + y;
1829 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1830 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1831 level.field[lx][ly]);
1832 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1833 && BorderElement != EL_EMPTY)
1834 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1835 getBorderElement(lx, ly));
1839 redraw_mask |= REDRAW_MICROLEVEL;
1842 #define MICROLABEL_EMPTY 0
1843 #define MICROLABEL_LEVEL_NAME 1
1844 #define MICROLABEL_CREATED_BY 2
1845 #define MICROLABEL_LEVEL_AUTHOR 3
1846 #define MICROLABEL_IMPORTED_FROM 4
1847 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1849 static void DrawMicroLevelLabelExt(int mode)
1851 char label_text[MAX_OUTPUT_LINESIZE + 1];
1852 int max_len_label_text;
1853 int font_nr = FONT_TEXT_2;
1855 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1856 font_nr = FONT_TEXT_3;
1858 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1860 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1862 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1863 mode == MICROLABEL_CREATED_BY ? "created by" :
1864 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1865 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1866 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1867 leveldir_current->imported_from : ""),
1868 max_len_label_text);
1869 label_text[max_len_label_text] = '\0';
1871 if (strlen(label_text) > 0)
1873 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1874 int lypos = MICROLABEL_YPOS;
1876 DrawText(lxpos, lypos, label_text, font_nr);
1879 redraw_mask |= REDRAW_MICROLEVEL;
1882 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1884 static unsigned long scroll_delay = 0;
1885 static unsigned long label_delay = 0;
1886 static int from_x, from_y, scroll_direction;
1887 static int label_state, label_counter;
1888 int last_game_status = game_status; /* save current game status */
1890 /* force PREVIEW font on preview level */
1891 game_status = GAME_MODE_PSEUDO_PREVIEW;
1895 from_x = from_y = 0;
1896 scroll_direction = MV_RIGHT;
1900 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1901 DrawMicroLevelLabelExt(label_state);
1903 /* initialize delay counters */
1904 DelayReached(&scroll_delay, 0);
1905 DelayReached(&label_delay, 0);
1907 if (leveldir_current->name)
1909 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1910 int lxpos = SX + (SXSIZE - text_width) / 2;
1911 int lypos = SY + 352;
1913 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1916 game_status = last_game_status; /* restore current game status */
1921 /* scroll micro level, if needed */
1922 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1923 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1925 switch (scroll_direction)
1931 scroll_direction = MV_UP;
1935 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1938 scroll_direction = MV_DOWN;
1945 scroll_direction = MV_RIGHT;
1949 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1952 scroll_direction = MV_LEFT;
1959 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1962 /* redraw micro level label, if needed */
1963 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1964 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1965 strcmp(level.author, leveldir_current->name) != 0 &&
1966 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1968 int max_label_counter = 23;
1970 if (leveldir_current->imported_from != NULL)
1971 max_label_counter += 14;
1973 label_counter = (label_counter + 1) % max_label_counter;
1974 label_state = (label_counter >= 0 && label_counter <= 7 ?
1975 MICROLABEL_LEVEL_NAME :
1976 label_counter >= 9 && label_counter <= 12 ?
1977 MICROLABEL_CREATED_BY :
1978 label_counter >= 14 && label_counter <= 21 ?
1979 MICROLABEL_LEVEL_AUTHOR :
1980 label_counter >= 23 && label_counter <= 26 ?
1981 MICROLABEL_IMPORTED_FROM :
1982 label_counter >= 28 && label_counter <= 35 ?
1983 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1984 DrawMicroLevelLabelExt(label_state);
1987 game_status = last_game_status; /* restore current game status */
1990 void WaitForEventToContinue()
1992 boolean still_wait = TRUE;
1994 /* simulate releasing mouse button over last gadget, if still pressed */
1996 HandleGadgets(-1, -1, 0);
1998 button_status = MB_RELEASED;
2010 case EVENT_BUTTONPRESS:
2011 case EVENT_KEYPRESS:
2015 case EVENT_KEYRELEASE:
2016 ClearPlayerAction();
2020 HandleOtherEvents(&event);
2024 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2031 /* don't eat all CPU time */
2036 #define MAX_REQUEST_LINES 13
2037 #define MAX_REQUEST_LINE_FONT1_LEN 7
2038 #define MAX_REQUEST_LINE_FONT2_LEN 10
2040 boolean Request(char *text, unsigned int req_state)
2042 int mx, my, ty, result = -1;
2043 unsigned int old_door_state;
2044 int last_game_status = game_status; /* save current game status */
2045 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2046 int font_nr = FONT_TEXT_2;
2047 int max_word_len = 0;
2050 for (text_ptr = text; *text_ptr; text_ptr++)
2052 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2054 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2056 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2057 font_nr = FONT_LEVEL_NUMBER;
2064 /* disable deactivated drawing when quick-loading level tape recording */
2065 if (tape.playing && tape.deactivate_display)
2066 TapeDeactivateDisplayOff(TRUE);
2070 SetMouseCursor(CURSOR_DEFAULT);
2073 #if defined(PLATFORM_UNIX)
2074 /* pause network game while waiting for request to answer */
2075 if (options.network &&
2076 game_status == GAME_MODE_PLAYING &&
2077 req_state & REQUEST_WAIT_FOR)
2078 SendToServer_PausePlaying();
2081 old_door_state = GetDoorState();
2083 /* simulate releasing mouse button over last gadget, if still pressed */
2085 HandleGadgets(-1, -1, 0);
2089 CloseDoor(DOOR_CLOSE_1);
2091 /* save old door content */
2092 BlitBitmap(bitmap_db_door, bitmap_db_door,
2093 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2094 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2096 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2098 /* clear door drawing field */
2099 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2101 /* force DOOR font on preview level */
2102 game_status = GAME_MODE_PSEUDO_DOOR;
2104 /* write text for request */
2105 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2107 char text_line[max_request_line_len + 1];
2113 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2116 if (!tc || tc == ' ')
2127 strncpy(text_line, text, tl);
2130 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2131 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2132 text_line, font_nr);
2134 text += tl + (tc == ' ' ? 1 : 0);
2137 game_status = last_game_status; /* restore current game status */
2139 if (req_state & REQ_ASK)
2141 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2142 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2144 else if (req_state & REQ_CONFIRM)
2146 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2148 else if (req_state & REQ_PLAYER)
2150 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2151 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2152 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2153 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2156 /* copy request gadgets to door backbuffer */
2157 BlitBitmap(drawto, bitmap_db_door,
2158 DX, DY, DXSIZE, DYSIZE,
2159 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2161 OpenDoor(DOOR_OPEN_1);
2167 if (!(req_state & REQUEST_WAIT_FOR))
2169 SetDrawBackgroundMask(REDRAW_FIELD);
2174 if (game_status != GAME_MODE_MAIN)
2177 button_status = MB_RELEASED;
2179 request_gadget_id = -1;
2181 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2184 SetMouseCursor(CURSOR_DEFAULT);
2197 case EVENT_BUTTONPRESS:
2198 case EVENT_BUTTONRELEASE:
2199 case EVENT_MOTIONNOTIFY:
2201 if (event.type == EVENT_MOTIONNOTIFY)
2203 if (!PointerInWindow(window))
2204 continue; /* window and pointer are on different screens */
2209 motion_status = TRUE;
2210 mx = ((MotionEvent *) &event)->x;
2211 my = ((MotionEvent *) &event)->y;
2215 motion_status = FALSE;
2216 mx = ((ButtonEvent *) &event)->x;
2217 my = ((ButtonEvent *) &event)->y;
2218 if (event.type == EVENT_BUTTONPRESS)
2219 button_status = ((ButtonEvent *) &event)->button;
2221 button_status = MB_RELEASED;
2224 /* this sets 'request_gadget_id' */
2225 HandleGadgets(mx, my, button_status);
2227 switch(request_gadget_id)
2229 case TOOL_CTRL_ID_YES:
2232 case TOOL_CTRL_ID_NO:
2235 case TOOL_CTRL_ID_CONFIRM:
2236 result = TRUE | FALSE;
2239 case TOOL_CTRL_ID_PLAYER_1:
2242 case TOOL_CTRL_ID_PLAYER_2:
2245 case TOOL_CTRL_ID_PLAYER_3:
2248 case TOOL_CTRL_ID_PLAYER_4:
2259 case EVENT_KEYPRESS:
2260 switch(GetEventKey((KeyEvent *)&event, TRUE))
2273 if (req_state & REQ_PLAYER)
2277 case EVENT_KEYRELEASE:
2278 ClearPlayerAction();
2282 HandleOtherEvents(&event);
2286 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2288 int joy = AnyJoystick();
2290 if (joy & JOY_BUTTON_1)
2292 else if (joy & JOY_BUTTON_2)
2298 /* don't eat all CPU time */
2302 if (game_status != GAME_MODE_MAIN)
2307 if (!(req_state & REQ_STAY_OPEN))
2309 CloseDoor(DOOR_CLOSE_1);
2311 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2313 BlitBitmap(bitmap_db_door, bitmap_db_door,
2314 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2315 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2316 OpenDoor(DOOR_OPEN_1);
2322 SetDrawBackgroundMask(REDRAW_FIELD);
2324 #if defined(PLATFORM_UNIX)
2325 /* continue network game after request */
2326 if (options.network &&
2327 game_status == GAME_MODE_PLAYING &&
2328 req_state & REQUEST_WAIT_FOR)
2329 SendToServer_ContinuePlaying();
2333 /* restore deactivated drawing when quick-loading level tape recording */
2334 if (tape.playing && tape.deactivate_display)
2335 TapeDeactivateDisplayOn();
2341 unsigned int OpenDoor(unsigned int door_state)
2343 unsigned int new_door_state;
2345 if (door_state & DOOR_COPY_BACK)
2347 BlitBitmap(bitmap_db_door, bitmap_db_door,
2348 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2349 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2350 door_state &= ~DOOR_COPY_BACK;
2353 new_door_state = MoveDoor(door_state);
2355 return(new_door_state);
2358 unsigned int CloseDoor(unsigned int door_state)
2360 unsigned int new_door_state;
2362 BlitBitmap(backbuffer, bitmap_db_door,
2363 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2364 BlitBitmap(backbuffer, bitmap_db_door,
2365 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2367 new_door_state = MoveDoor(door_state);
2369 return(new_door_state);
2372 unsigned int GetDoorState()
2374 return MoveDoor(DOOR_GET_STATE);
2377 unsigned int SetDoorState(unsigned int door_state)
2379 return MoveDoor(door_state | DOOR_SET_STATE);
2382 unsigned int MoveDoor(unsigned int door_state)
2384 static int door1 = DOOR_OPEN_1;
2385 static int door2 = DOOR_CLOSE_2;
2386 unsigned long door_delay = 0;
2387 unsigned long door_delay_value;
2390 if (door_state == DOOR_GET_STATE)
2391 return(door1 | door2);
2393 if (door_state & DOOR_SET_STATE)
2395 if (door_state & DOOR_ACTION_1)
2396 door1 = door_state & DOOR_ACTION_1;
2397 if (door_state & DOOR_ACTION_2)
2398 door2 = door_state & DOOR_ACTION_2;
2400 return(door1 | door2);
2403 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2404 door_state &= ~DOOR_OPEN_1;
2405 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2406 door_state &= ~DOOR_CLOSE_1;
2407 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2408 door_state &= ~DOOR_OPEN_2;
2409 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2410 door_state &= ~DOOR_CLOSE_2;
2412 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2415 if (setup.quick_doors)
2417 stepsize = 20; /* must be choosen to always draw last frame */
2418 door_delay_value = 0;
2421 StopSound(SND_DOOR_OPENING);
2422 StopSound(SND_DOOR_CLOSING);
2426 if (global.autoplay_leveldir)
2428 door_state |= DOOR_NO_DELAY;
2429 door_state &= ~DOOR_CLOSE_ALL;
2432 if (door_state & DOOR_ACTION)
2434 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2435 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2436 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2437 int end = (door_state & DOOR_ACTION_1 &&
2438 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2441 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2443 /* opening door sound has priority over simultaneously closing door */
2444 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2445 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2446 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2447 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2450 for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2452 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2453 GC gc = bitmap->stored_clip_gc;
2455 if (door_state & DOOR_ACTION_1)
2457 int a = MIN(x * door_1.step_offset, end);
2458 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2462 BlitBitmap(bitmap_db_door, drawto,
2463 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2464 DXSIZE,DYSIZE - i / 2, DX, DY);
2466 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2469 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2471 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2472 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2473 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2474 int dst2_x = DX, dst2_y = DY;
2475 int width = i, height = DYSIZE;
2477 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2478 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2481 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2482 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2485 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2487 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2488 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2489 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2490 int dst2_x = DX, dst2_y = DY;
2491 int width = DXSIZE, height = i;
2493 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2494 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2497 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2498 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2501 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2503 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2505 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2506 BlitBitmapMasked(bitmap, drawto,
2507 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2508 DX + DXSIZE - i, DY + j);
2509 BlitBitmapMasked(bitmap, drawto,
2510 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2511 DX + DXSIZE - i, DY + 140 + j);
2512 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2513 DY - (DOOR_GFX_PAGEY1 + j));
2514 BlitBitmapMasked(bitmap, drawto,
2515 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2517 BlitBitmapMasked(bitmap, drawto,
2518 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2521 BlitBitmapMasked(bitmap, drawto,
2522 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2524 BlitBitmapMasked(bitmap, drawto,
2525 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2527 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2528 BlitBitmapMasked(bitmap, drawto,
2529 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2530 DX + DXSIZE - i, DY + 77 + j);
2531 BlitBitmapMasked(bitmap, drawto,
2532 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2533 DX + DXSIZE - i, DY + 203 + j);
2536 redraw_mask |= REDRAW_DOOR_1;
2537 door_1_done = (a == end);
2540 if (door_state & DOOR_ACTION_2)
2542 int a = MIN(x * door_2.step_offset, VXSIZE);
2543 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2547 BlitBitmap(bitmap_db_door, drawto,
2548 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2549 VXSIZE, VYSIZE - i / 2, VX, VY);
2551 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2554 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2556 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2557 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2558 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2559 int dst2_x = VX, dst2_y = VY;
2560 int width = i, height = VYSIZE;
2562 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2563 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2566 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2567 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2570 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2572 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2573 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2574 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2575 int dst2_x = VX, dst2_y = VY;
2576 int width = VXSIZE, height = i;
2578 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2579 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2582 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2583 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2586 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2588 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2590 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2591 BlitBitmapMasked(bitmap, drawto,
2592 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2593 VX + VXSIZE - i, VY + j);
2594 SetClipOrigin(bitmap, gc,
2595 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2596 BlitBitmapMasked(bitmap, drawto,
2597 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2600 BlitBitmapMasked(bitmap, drawto,
2601 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2602 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2603 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2604 BlitBitmapMasked(bitmap, drawto,
2605 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2607 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2610 redraw_mask |= REDRAW_DOOR_2;
2611 door_2_done = (a == VXSIZE);
2616 if (game_status == GAME_MODE_MAIN)
2619 if (!(door_state & DOOR_NO_DELAY))
2620 WaitUntilDelayReached(&door_delay, door_delay_value);
2625 if (setup.quick_doors)
2627 StopSound(SND_DOOR_OPENING);
2628 StopSound(SND_DOOR_CLOSING);
2632 if (door_state & DOOR_ACTION_1)
2633 door1 = door_state & DOOR_ACTION_1;
2634 if (door_state & DOOR_ACTION_2)
2635 door2 = door_state & DOOR_ACTION_2;
2637 return (door1 | door2);
2640 void DrawSpecialEditorDoor()
2642 /* draw bigger toolbox window */
2643 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2644 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2646 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2647 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2650 redraw_mask |= REDRAW_ALL;
2653 void UndrawSpecialEditorDoor()
2655 /* draw normal tape recorder window */
2656 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2657 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2660 redraw_mask |= REDRAW_ALL;
2664 /* ---------- new tool button stuff ---------------------------------------- */
2666 /* graphic position values for tool buttons */
2667 #define TOOL_BUTTON_YES_XPOS 2
2668 #define TOOL_BUTTON_YES_YPOS 250
2669 #define TOOL_BUTTON_YES_GFX_YPOS 0
2670 #define TOOL_BUTTON_YES_XSIZE 46
2671 #define TOOL_BUTTON_YES_YSIZE 28
2672 #define TOOL_BUTTON_NO_XPOS 52
2673 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2674 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2675 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2676 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2677 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2678 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2679 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2680 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2681 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2682 #define TOOL_BUTTON_PLAYER_XSIZE 30
2683 #define TOOL_BUTTON_PLAYER_YSIZE 30
2684 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2685 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2686 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2687 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2688 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2689 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2690 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2691 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2692 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2693 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2694 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2695 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2696 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2697 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2698 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2699 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2700 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2701 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2702 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2703 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2712 } toolbutton_info[NUM_TOOL_BUTTONS] =
2715 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2716 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2717 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2722 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2723 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2724 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2729 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2730 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2731 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2732 TOOL_CTRL_ID_CONFIRM,
2736 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2737 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2738 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2739 TOOL_CTRL_ID_PLAYER_1,
2743 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2744 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2745 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2746 TOOL_CTRL_ID_PLAYER_2,
2750 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2751 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2752 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2753 TOOL_CTRL_ID_PLAYER_3,
2757 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2758 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2759 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2760 TOOL_CTRL_ID_PLAYER_4,
2765 void CreateToolButtons()
2769 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2771 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2772 Bitmap *deco_bitmap = None;
2773 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2774 struct GadgetInfo *gi;
2775 unsigned long event_mask;
2776 int gd_xoffset, gd_yoffset;
2777 int gd_x1, gd_x2, gd_y;
2780 event_mask = GD_EVENT_RELEASED;
2782 gd_xoffset = toolbutton_info[i].xpos;
2783 gd_yoffset = toolbutton_info[i].ypos;
2784 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2785 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2786 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2788 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2790 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2792 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2793 &deco_bitmap, &deco_x, &deco_y);
2794 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2795 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2798 gi = CreateGadget(GDI_CUSTOM_ID, id,
2799 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2800 GDI_X, DX + toolbutton_info[i].x,
2801 GDI_Y, DY + toolbutton_info[i].y,
2802 GDI_WIDTH, toolbutton_info[i].width,
2803 GDI_HEIGHT, toolbutton_info[i].height,
2804 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2805 GDI_STATE, GD_BUTTON_UNPRESSED,
2806 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2807 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2808 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2809 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2810 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2811 GDI_DECORATION_SHIFTING, 1, 1,
2812 GDI_EVENT_MASK, event_mask,
2813 GDI_CALLBACK_ACTION, HandleToolButtons,
2817 Error(ERR_EXIT, "cannot create gadget");
2819 tool_gadget[id] = gi;
2823 void FreeToolButtons()
2827 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2828 FreeGadget(tool_gadget[i]);
2831 static void UnmapToolButtons()
2835 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2836 UnmapGadget(tool_gadget[i]);
2839 static void HandleToolButtons(struct GadgetInfo *gi)
2841 request_gadget_id = gi->custom_id;
2844 int get_next_element(int element)
2848 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2849 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2850 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2851 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2852 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2853 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2854 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2856 default: return element;
2860 int el_act_dir2img(int element, int action, int direction)
2862 element = GFX_ELEMENT(element);
2863 direction = MV_DIR_BIT(direction);
2865 return element_info[element].direction_graphic[action][direction];
2868 static int el_act_dir2crm(int element, int action, int direction)
2870 element = GFX_ELEMENT(element);
2871 direction = MV_DIR_BIT(direction);
2873 return element_info[element].direction_crumbled[action][direction];
2876 int el_act2img(int element, int action)
2878 element = GFX_ELEMENT(element);
2880 return element_info[element].graphic[action];
2883 int el_act2crm(int element, int action)
2885 element = GFX_ELEMENT(element);
2887 return element_info[element].crumbled[action];
2890 int el_dir2img(int element, int direction)
2892 element = GFX_ELEMENT(element);
2894 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2897 int el2baseimg(int element)
2899 return element_info[element].graphic[ACTION_DEFAULT];
2902 int el2img(int element)
2904 element = GFX_ELEMENT(element);
2906 return element_info[element].graphic[ACTION_DEFAULT];
2909 int el2edimg(int element)
2911 element = GFX_ELEMENT(element);
2913 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2916 int el2preimg(int element)
2918 element = GFX_ELEMENT(element);
2920 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];