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 SetDrawtoField(int mode)
45 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
56 drawto_field = fieldbuffer;
58 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
69 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
73 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
75 if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
81 width = gfx.sxsize + 2 * TILEX;
82 height = gfx.sysize + 2 * TILEY;
85 if (force_redraw || setup.direct_draw)
88 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
89 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
91 if (setup.direct_draw)
92 SetDrawtoField(DRAW_BACKBUFFER);
94 for(xx=BX1; xx<=BX2; xx++)
95 for(yy=BY1; yy<=BY2; yy++)
96 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
97 DrawScreenField(xx, yy);
100 if (setup.direct_draw)
101 SetDrawtoField(DRAW_DIRECT);
104 if (setup.soft_scrolling)
106 int fx = FX, fy = FY;
108 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
109 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
111 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
115 BlitBitmap(drawto, window, x, y, width, height, x, y);
121 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
123 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
124 redraw_mask &= ~REDRAW_MAIN;
126 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
127 redraw_mask |= REDRAW_FIELD;
129 if (redraw_mask & REDRAW_FIELD)
130 redraw_mask &= ~REDRAW_TILES;
132 if (redraw_mask == REDRAW_NONE)
135 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
137 static boolean last_frame_skipped = FALSE;
138 boolean skip_even_when_not_scrolling = TRUE;
139 boolean just_scrolling = (ScreenMovDir != 0);
140 boolean verbose = FALSE;
142 if (global.fps_slowdown_factor > 1 &&
143 (FrameCounter % global.fps_slowdown_factor) &&
144 (just_scrolling || skip_even_when_not_scrolling))
146 redraw_mask &= ~REDRAW_MAIN;
148 last_frame_skipped = TRUE;
151 printf("FRAME SKIPPED\n");
155 if (last_frame_skipped)
156 redraw_mask |= REDRAW_FIELD;
158 last_frame_skipped = FALSE;
161 printf("frame not skipped\n");
165 /* synchronize X11 graphics at this point; if we would synchronize the
166 display immediately after the buffer switching (after the XFlush),
167 this could mean that we have to wait for the graphics to complete,
168 although we could go on doing calculations for the next frame */
172 if (redraw_mask & REDRAW_ALL)
174 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
178 if (redraw_mask & REDRAW_FIELD)
180 if (game_status != GAME_MODE_PLAYING ||
181 redraw_mask & REDRAW_FROM_BACKBUFFER)
183 BlitBitmap(backbuffer, window,
184 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
188 int fx = FX, fy = FY;
190 if (setup.soft_scrolling)
192 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
193 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
196 if (setup.soft_scrolling ||
197 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
198 ABS(ScreenMovPos) == ScrollStepSize ||
199 redraw_tiles > REDRAWTILES_THRESHOLD)
201 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
205 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
207 (setup.soft_scrolling ?
208 "setup.soft_scrolling" :
209 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
210 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
211 ABS(ScreenGfxPos) == ScrollStepSize ?
212 "ABS(ScreenGfxPos) == ScrollStepSize" :
213 "redraw_tiles > REDRAWTILES_THRESHOLD"));
219 redraw_mask &= ~REDRAW_MAIN;
222 if (redraw_mask & REDRAW_DOORS)
224 if (redraw_mask & REDRAW_DOOR_1)
225 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
226 if (redraw_mask & REDRAW_DOOR_2)
228 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
229 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
232 if (redraw_mask & REDRAW_VIDEO_1)
233 BlitBitmap(backbuffer, window,
234 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
235 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
236 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
237 if (redraw_mask & REDRAW_VIDEO_2)
238 BlitBitmap(backbuffer, window,
239 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
240 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
241 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
242 if (redraw_mask & REDRAW_VIDEO_3)
243 BlitBitmap(backbuffer, window,
244 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
245 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
246 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
250 if (redraw_mask & REDRAW_DOOR_3)
251 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
253 redraw_mask &= ~REDRAW_DOORS;
256 if (redraw_mask & REDRAW_MICROLEVEL)
258 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
259 SX, SY + 10 * TILEY);
261 redraw_mask &= ~REDRAW_MICROLEVEL;
264 if (redraw_mask & REDRAW_TILES)
266 for(x=0; x<SCR_FIELDX; x++)
267 for(y=0; y<SCR_FIELDY; y++)
268 if (redraw[redraw_x1 + x][redraw_y1 + y])
269 BlitBitmap(buffer, window,
270 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
271 SX + x * TILEX, SY + y * TILEY);
274 if (redraw_mask & REDRAW_FPS) /* display frames per second */
279 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
280 if (!global.fps_slowdown)
283 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
284 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
289 for(x=0; x<MAX_BUF_XSIZE; x++)
290 for(y=0; y<MAX_BUF_YSIZE; y++)
293 redraw_mask = REDRAW_NONE;
299 long fading_delay = 300;
301 if (setup.fading && (redraw_mask & REDRAW_FIELD))
308 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
311 for(i=0;i<2*FULL_SYSIZE;i++)
313 for(y=0;y<FULL_SYSIZE;y++)
315 BlitBitmap(backbuffer, window,
316 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
324 for(i=1;i<FULL_SYSIZE;i+=2)
325 BlitBitmap(backbuffer, window,
326 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
332 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
333 BlitBitmapMasked(backbuffer, window,
334 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
339 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
340 BlitBitmapMasked(backbuffer, window,
341 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
346 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
347 BlitBitmapMasked(backbuffer, window,
348 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
353 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
354 BlitBitmapMasked(backbuffer, window,
355 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
360 redraw_mask &= ~REDRAW_MAIN;
367 void SetMainBackgroundImage(int graphic)
369 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
370 graphic_info[graphic].bitmap ?
371 graphic_info[graphic].bitmap :
372 graphic_info[IMG_BACKGROUND].bitmap);
375 void SetDoorBackgroundImage(int graphic)
377 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
378 graphic_info[graphic].bitmap ?
379 graphic_info[graphic].bitmap :
380 graphic_info[IMG_BACKGROUND].bitmap);
383 void DrawBackground(int dest_x, int dest_y, int width, int height)
385 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
387 redraw_mask |= REDRAW_FIELD;
392 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
394 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
396 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
397 SetDrawtoField(DRAW_BUFFERED);
400 SetDrawtoField(DRAW_BACKBUFFER);
402 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
404 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
405 SetDrawtoField(DRAW_DIRECT);
409 void MarkTileDirty(int x, int y)
411 int xx = redraw_x1 + x;
412 int yy = redraw_y1 + y;
417 redraw[xx][yy] = TRUE;
418 redraw_mask |= REDRAW_TILES;
421 void SetBorderElement()
425 BorderElement = EL_EMPTY;
427 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
429 for(x=0; x<lev_fieldx; x++)
431 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
432 BorderElement = EL_STEELWALL;
434 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
440 void SetRandomAnimationValue(int x, int y)
442 gfx.anim_random_frame = GfxRandom[x][y];
445 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
447 /* animation synchronized with global frame counter, not move position */
448 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
449 sync_frame = FrameCounter;
451 return getAnimationFrame(graphic_info[graphic].anim_frames,
452 graphic_info[graphic].anim_delay,
453 graphic_info[graphic].anim_mode,
454 graphic_info[graphic].anim_start_frame,
458 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
459 int graphic, int sync_frame, int mask_mode)
461 int frame = getGraphicAnimationFrame(graphic, sync_frame);
463 if (mask_mode == USE_MASKING)
464 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
466 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
469 inline void DrawGraphicAnimation(int x, int y, int graphic)
471 int lx = LEVELX(x), ly = LEVELY(y);
473 if (!IN_SCR_FIELD(x, y))
476 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
477 graphic, GfxFrame[lx][ly], NO_MASKING);
481 void DrawLevelGraphicAnimation(int x, int y, int graphic)
483 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
486 void DrawLevelElementAnimation(int x, int y, int element)
489 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
491 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
493 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
497 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
499 int sx = SCREENX(x), sy = SCREENY(y);
501 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
504 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
507 DrawGraphicAnimation(sx, sy, graphic);
509 if (GFX_CRUMBLED(Feld[x][y]))
510 DrawLevelFieldCrumbledSand(x, y);
513 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
515 int sx = SCREENX(x), sy = SCREENY(y);
518 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
521 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
523 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
526 DrawGraphicAnimation(sx, sy, graphic);
528 if (GFX_CRUMBLED(element))
529 DrawLevelFieldCrumbledSand(x, y);
532 static int getPlayerAction(struct PlayerInfo *player, int move_dir)
534 int action = (player->is_pushing ? ACTION_PUSHING :
535 player->is_digging ? ACTION_DIGGING :
536 player->is_collecting ? ACTION_COLLECTING :
537 player->is_moving ? ACTION_MOVING :
538 player->is_snapping ? ACTION_SNAPPING :
539 player->is_sleeping ? ACTION_SLEEPING :
540 player->is_bored ? ACTION_BORING :
541 player->is_waiting ? ACTION_WAITING : ACTION_DEFAULT);
543 if (player->is_sleeping)
545 if (player->num_special_action_sleeping > 0)
547 if (player->anim_delay_counter == 0 && player->post_delay_counter == 0)
550 ACTION_BORING_1 + SimpleRND(player->num_special_action_sleeping);
551 int special_graphic =
552 el_act_dir2img(player->element_nr, special_action, move_dir);
554 player->anim_delay_counter =
555 graphic_info[special_graphic].anim_delay_fixed +
556 SimpleRND(graphic_info[special_graphic].anim_delay_random);
557 player->post_delay_counter =
558 graphic_info[special_graphic].post_delay_fixed +
559 SimpleRND(graphic_info[special_graphic].post_delay_random);
561 player->special_action_sleeping = special_action;
564 if (player->anim_delay_counter > 0)
566 action = player->special_action_sleeping;
567 player->anim_delay_counter--;
569 else if (player->post_delay_counter > 0)
571 player->post_delay_counter--;
575 else if (player->is_bored)
577 if (player->num_special_action_bored > 0)
579 if (player->anim_delay_counter == 0 && player->post_delay_counter == 0)
582 ACTION_BORING_1 + SimpleRND(player->num_special_action_bored);
583 int special_graphic =
584 el_act_dir2img(player->element_nr, special_action, move_dir);
586 player->anim_delay_counter =
587 graphic_info[special_graphic].anim_delay_fixed +
588 SimpleRND(graphic_info[special_graphic].anim_delay_random);
589 player->post_delay_counter =
590 graphic_info[special_graphic].post_delay_fixed +
591 SimpleRND(graphic_info[special_graphic].post_delay_random);
593 player->special_action_bored = special_action;
596 if (player->anim_delay_counter > 0)
598 action = player->special_action_bored;
599 player->anim_delay_counter--;
601 else if (player->post_delay_counter > 0)
603 player->post_delay_counter--;
611 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
613 if (player->use_murphy_graphic)
615 /* this works only because currently only one player can be "murphy" ... */
616 static int last_horizontal_dir = MV_LEFT;
617 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
619 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
620 last_horizontal_dir = move_dir;
622 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
624 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
626 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
632 return el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
635 static boolean equalGraphics(int graphic1, int graphic2)
637 struct GraphicInfo *g1 = &graphic_info[graphic1];
638 struct GraphicInfo *g2 = &graphic_info[graphic2];
640 return (g1->bitmap == g2->bitmap &&
641 g1->src_x == g2->src_x &&
642 g1->src_y == g2->src_y &&
643 g1->anim_frames == g2->anim_frames &&
644 g1->anim_delay == g2->anim_delay &&
645 g1->anim_mode == g2->anim_mode);
648 void DrawAllPlayers()
652 for(i=0; i<MAX_PLAYERS; i++)
653 if (stored_player[i].active)
654 DrawPlayer(&stored_player[i]);
657 void DrawPlayerField(int x, int y)
659 if (!IS_PLAYER(x, y))
662 DrawPlayer(PLAYERINFO(x, y));
665 void DrawPlayer(struct PlayerInfo *player)
669 int move_dir = player->MovDir;
671 int last_jx = player->last_jx;
672 int last_jy = player->last_jy;
673 int next_jx = jx + (jx - last_jx);
674 int next_jy = jy + (jy - last_jy);
675 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
677 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
678 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
679 int last_jx = (player->is_moving ? jx - dx : jx);
680 int last_jy = (player->is_moving ? jy - dy : jy);
681 int next_jx = jx + dx;
682 int next_jy = jy + dy;
683 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
685 int sx = SCREENX(jx), sy = SCREENY(jy);
686 int sxx = 0, syy = 0;
687 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
689 int action = ACTION_DEFAULT;
690 int last_player_graphic = getPlayerGraphic(player, move_dir);
691 int last_player_frame = player->Frame;
694 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
698 if (!IN_LEV_FIELD(jx, jy))
700 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
701 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
702 printf("DrawPlayerField(): This should never happen!\n");
707 if (element == EL_EXPLOSION)
712 action = getPlayerAction(player, move_dir);
716 action = (player->is_pushing ? ACTION_PUSHING :
717 player->is_digging ? ACTION_DIGGING :
718 player->is_collecting ? ACTION_COLLECTING :
719 player->is_moving ? ACTION_MOVING :
720 player->is_snapping ? ACTION_SNAPPING :
721 player->is_sleeping ? ACTION_SLEEPING :
722 player->is_bored ? ACTION_BORING :
723 player->is_waiting ? ACTION_WAITING : ACTION_DEFAULT);
725 if (player->is_bored && player->num_special_action_bored > 0)
727 if (player->anim_delay_counter == 0 && player->post_delay_counter == 0)
731 action = ACTION_BORING_1 + SimpleRND(player->num_special_action_bored);
732 special_graphic = el_act_dir2img(EL_SP_MURPHY, action, move_dir);
734 player->anim_delay_counter =
735 graphic_info[special_graphic].anim_delay_fixed +
736 SimpleRND(graphic_info[special_graphic].anim_delay_random);
737 player->post_delay_counter =
738 graphic_info[special_graphic].post_delay_fixed +
739 SimpleRND(graphic_info[special_graphic].post_delay_random);
740 player->special_action_bored = action;
743 if (player->anim_delay_counter > 0)
745 action = player->special_action_bored;
746 player->anim_delay_counter--;
749 if (player->post_delay_counter > 0)
751 player->post_delay_counter--;
757 printf("::: '%s'\n", element_action_info[action].suffix);
760 InitPlayerGfxAnimation(player, action, move_dir);
762 /* ----------------------------------------------------------------------- */
763 /* draw things in the field the player is leaving, if needed */
764 /* ----------------------------------------------------------------------- */
767 if (player->is_moving)
769 if (player_is_moving)
772 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
774 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
776 if (last_element == EL_DYNAMITE_ACTIVE ||
777 last_element == EL_SP_DISK_RED_ACTIVE)
778 DrawDynamite(last_jx, last_jy);
780 DrawLevelFieldThruMask(last_jx, last_jy);
782 else if (last_element == EL_DYNAMITE_ACTIVE ||
783 last_element == EL_SP_DISK_RED_ACTIVE)
784 DrawDynamite(last_jx, last_jy);
786 DrawLevelField(last_jx, last_jy);
788 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
789 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
792 if (!IN_SCR_FIELD(sx, sy))
795 if (setup.direct_draw)
796 SetDrawtoField(DRAW_BUFFERED);
798 /* ----------------------------------------------------------------------- */
799 /* draw things behind the player, if needed */
800 /* ----------------------------------------------------------------------- */
803 DrawLevelElement(jx, jy, Back[jx][jy]);
804 else if (IS_ACTIVE_BOMB(element))
805 DrawLevelElement(jx, jy, EL_EMPTY);
808 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
810 if (GFX_CRUMBLED(GfxElement[jx][jy]))
811 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
814 int old_element = GfxElement[jx][jy];
815 int old_graphic = el_act_dir2img(old_element, action, move_dir);
816 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
818 DrawGraphic(sx, sy, old_graphic, frame);
823 GfxElement[jx][jy] = EL_UNDEFINED;
825 DrawLevelField(jx, jy);
829 /* ----------------------------------------------------------------------- */
830 /* draw player himself */
831 /* ----------------------------------------------------------------------- */
835 graphic = getPlayerGraphic(player, move_dir);
837 /* in the case of changed player action or direction, prevent the current
838 animation frame from being restarted for identical animations */
839 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
840 player->Frame = last_player_frame;
844 if (player->use_murphy_graphic)
846 static int last_horizontal_dir = MV_LEFT;
848 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
849 last_horizontal_dir = move_dir;
851 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
853 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
855 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
857 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
861 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
865 frame = getGraphicAnimationFrame(graphic, player->Frame);
869 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
870 sxx = player->GfxPos;
872 syy = player->GfxPos;
875 if (!setup.soft_scrolling && ScreenMovPos)
878 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
880 if (SHIELD_ON(player))
882 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
883 IMG_SHIELD_NORMAL_ACTIVE);
884 int frame = getGraphicAnimationFrame(graphic, -1);
886 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
889 /* ----------------------------------------------------------------------- */
890 /* draw things the player is pushing, if needed */
891 /* ----------------------------------------------------------------------- */
894 printf("::: %d, %d [%d, %d] [%d]\n",
895 player->is_pushing, player_is_moving, player->GfxAction,
896 player->is_moving, player_is_moving);
900 if (player->is_pushing && player->is_moving)
902 if (player->is_pushing && player_is_moving)
905 int px = SCREENX(next_jx), py = SCREENY(next_jy);
907 if (Back[next_jx][next_jy])
908 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
910 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
911 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
915 int element = MovingOrBlocked2Element(next_jx, next_jy);
916 int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
918 int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
920 int frame = getGraphicAnimationFrame(graphic, player->Frame);
923 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
924 NO_CUTTING, NO_MASKING);
928 /* ----------------------------------------------------------------------- */
929 /* draw things in front of player (active dynamite or dynabombs) */
930 /* ----------------------------------------------------------------------- */
932 if (IS_ACTIVE_BOMB(element))
934 graphic = el2img(element);
935 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
937 if (game.emulation == EMU_SUPAPLEX)
938 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
940 DrawGraphicThruMask(sx, sy, graphic, frame);
943 if (player_is_moving && last_element == EL_EXPLOSION)
945 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
946 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
947 int phase = ExplodePhase[last_jx][last_jy] - 1;
948 int frame = getGraphicAnimationFrame(graphic, phase - delay);
951 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
954 /* ----------------------------------------------------------------------- */
955 /* draw elements the player is just walking/passing through/under */
956 /* ----------------------------------------------------------------------- */
958 /* handle the field the player is leaving ... */
959 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
960 DrawLevelField(last_jx, last_jy);
961 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
962 DrawLevelFieldThruMask(last_jx, last_jy);
964 /* ... and the field the player is entering */
965 if (IS_ACCESSIBLE_INSIDE(element))
966 DrawLevelField(jx, jy);
967 else if (IS_ACCESSIBLE_UNDER(element))
968 DrawLevelFieldThruMask(jx, jy);
970 if (setup.direct_draw)
972 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
973 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
974 int x_size = TILEX * (1 + ABS(jx - last_jx));
975 int y_size = TILEY * (1 + ABS(jy - last_jy));
977 BlitBitmap(drawto_field, window,
978 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
979 SetDrawtoField(DRAW_DIRECT);
982 MarkTileDirty(sx,sy);
985 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
987 struct GraphicInfo *g = &graphic_info[graphic];
991 if (g->offset_y == 0) /* frames are ordered horizontally */
993 int max_width = g->anim_frames_per_line * g->width;
995 *x = (g->src_x + frame * g->offset_x) % max_width;
996 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
998 else if (g->offset_x == 0) /* frames are ordered vertically */
1000 int max_height = g->anim_frames_per_line * g->height;
1002 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
1003 *y = (g->src_y + frame * g->offset_y) % max_height;
1005 else /* frames are ordered diagonally */
1007 *x = g->src_x + frame * g->offset_x;
1008 *y = g->src_y + frame * g->offset_y;
1012 void DrawGraphic(int x, int y, int graphic, int frame)
1015 if (!IN_SCR_FIELD(x, y))
1017 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1018 printf("DrawGraphic(): This should never happen!\n");
1023 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1024 MarkTileDirty(x, y);
1027 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1033 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1034 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1037 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1040 if (!IN_SCR_FIELD(x, y))
1042 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1043 printf("DrawGraphicThruMask(): This should never happen!\n");
1048 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1050 MarkTileDirty(x, y);
1053 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
1061 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1062 drawing_gc = src_bitmap->stored_clip_gc;
1064 GC drawing_gc = src_bitmap->stored_clip_gc;
1065 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1066 int src_x = graphic_info[graphic].src_x;
1067 int src_y = graphic_info[graphic].src_y;
1068 int offset_x = graphic_info[graphic].offset_x;
1069 int offset_y = graphic_info[graphic].offset_y;
1071 src_x += frame * offset_x;
1072 src_y += frame * offset_y;
1076 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1077 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1080 void DrawMiniGraphic(int x, int y, int graphic)
1082 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1083 MarkTileDirty(x / 2, y / 2);
1086 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1088 struct GraphicInfo *g = &graphic_info[graphic];
1089 int mini_startx = 0;
1090 int mini_starty = g->bitmap->height * 2 / 3;
1092 *bitmap = g->bitmap;
1093 *x = mini_startx + g->src_x / 2;
1094 *y = mini_starty + g->src_y / 2;
1097 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1102 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1103 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1106 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
1107 int cut_mode, int mask_mode)
1112 int width = TILEX, height = TILEY;
1118 DrawGraphic(x, y, graphic, frame);
1122 if (dx || dy) /* shifted graphic */
1124 if (x < BX1) /* object enters playfield from the left */
1131 else if (x > BX2) /* object enters playfield from the right */
1137 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1143 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1145 else if (dx) /* general horizontal movement */
1146 MarkTileDirty(x + SIGN(dx), y);
1148 if (y < BY1) /* object enters playfield from the top */
1150 if (cut_mode==CUT_BELOW) /* object completely above top border */
1158 else if (y > BY2) /* object enters playfield from the bottom */
1164 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1170 else if (dy > 0 && cut_mode == CUT_ABOVE)
1172 if (y == BY2) /* object completely above bottom border */
1178 MarkTileDirty(x, y + 1);
1179 } /* object leaves playfield to the bottom */
1180 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1182 else if (dy) /* general vertical movement */
1183 MarkTileDirty(x, y + SIGN(dy));
1187 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1189 src_bitmap = graphic_info[graphic].bitmap;
1190 src_x = graphic_info[graphic].src_x;
1191 src_y = graphic_info[graphic].src_y;
1192 offset_x = graphic_info[graphic].offset_x;
1193 offset_y = graphic_info[graphic].offset_y;
1195 src_x += frame * offset_x;
1196 src_y += frame * offset_y;
1199 drawing_gc = src_bitmap->stored_clip_gc;
1204 dest_x = FX + x * TILEX + dx;
1205 dest_y = FY + y * TILEY + dy;
1208 if (!IN_SCR_FIELD(x,y))
1210 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1211 printf("DrawGraphicShifted(): This should never happen!\n");
1216 if (mask_mode == USE_MASKING)
1218 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1219 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1223 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1229 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1230 int frame, int cut_mode)
1232 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1235 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1236 int cut_mode, int mask_mode)
1238 int lx = LEVELX(x), ly = LEVELY(y);
1242 if (IN_LEV_FIELD(lx, ly))
1244 SetRandomAnimationValue(lx, ly);
1246 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1247 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1249 else /* border element */
1251 graphic = el2img(element);
1252 frame = getGraphicAnimationFrame(graphic, -1);
1255 if (element == EL_EXPANDABLE_WALL)
1257 boolean left_stopped = FALSE, right_stopped = FALSE;
1259 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1260 left_stopped = TRUE;
1261 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1262 right_stopped = TRUE;
1264 if (left_stopped && right_stopped)
1266 else if (left_stopped)
1268 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1269 frame = graphic_info[graphic].anim_frames - 1;
1271 else if (right_stopped)
1273 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1274 frame = graphic_info[graphic].anim_frames - 1;
1279 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1280 else if (mask_mode == USE_MASKING)
1281 DrawGraphicThruMask(x, y, graphic, frame);
1283 DrawGraphic(x, y, graphic, frame);
1286 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1287 int cut_mode, int mask_mode)
1289 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1290 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1291 cut_mode, mask_mode);
1294 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1297 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1300 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1303 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1306 void DrawLevelElementThruMask(int x, int y, int element)
1308 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1311 void DrawLevelFieldThruMask(int x, int y)
1313 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1316 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1320 int sx = SCREENX(x), sy = SCREENY(y);
1322 int width, height, cx, cy, i;
1324 int crumbled_border_size = graphic_info[graphic].border_size;
1326 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1328 static int xy[4][2] =
1337 if (x == 0 && y == 7)
1338 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1339 crumbled_border_size);
1342 if (!IN_LEV_FIELD(x, y))
1345 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1346 GfxElement[x][y] : Feld[x][y]);
1348 /* crumble field itself */
1349 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1351 if (!IN_SCR_FIELD(sx, sy))
1354 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1358 int xx = x + xy[i][0];
1359 int yy = y + xy[i][1];
1361 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1363 /* check if neighbour field is of same type */
1364 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1368 if (Feld[x][y] == EL_CUSTOM_START + 123)
1369 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1370 i, Feld[x][y], element,
1371 GFX_CRUMBLED(element), IS_MOVING(x, y));
1374 if (i == 1 || i == 2)
1376 width = crumbled_border_size;
1378 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1384 height = crumbled_border_size;
1386 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1389 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1390 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1393 MarkTileDirty(sx, sy);
1395 else /* crumble neighbour fields */
1398 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1403 int xx = x + xy[i][0];
1404 int yy = y + xy[i][1];
1405 int sxx = sx + xy[i][0];
1406 int syy = sy + xy[i][1];
1408 if (!IN_LEV_FIELD(xx, yy) ||
1409 !IN_SCR_FIELD(sxx, syy) ||
1410 !GFX_CRUMBLED(Feld[xx][yy]) ||
1415 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1416 crumbled_border_size = graphic_info[graphic].border_size;
1418 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1421 if (i == 1 || i == 2)
1423 width = crumbled_border_size;
1425 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1431 height = crumbled_border_size;
1433 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1436 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1437 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1439 MarkTileDirty(sxx, syy);
1444 void DrawLevelFieldCrumbledSand(int x, int y)
1449 if (!IN_LEV_FIELD(x, y))
1452 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1454 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1456 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1460 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1464 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1465 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1467 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1468 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1470 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1471 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1472 int sx = SCREENX(x), sy = SCREENY(y);
1474 DrawGraphic(sx, sy, graphic1, frame1);
1475 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1478 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1480 int sx = SCREENX(x), sy = SCREENY(y);
1481 static int xy[4][2] =
1492 int xx = x + xy[i][0];
1493 int yy = y + xy[i][1];
1494 int sxx = sx + xy[i][0];
1495 int syy = sy + xy[i][1];
1497 if (!IN_LEV_FIELD(xx, yy) ||
1498 !IN_SCR_FIELD(sxx, syy) ||
1499 !GFX_CRUMBLED(Feld[xx][yy]) ||
1503 DrawLevelField(xx, yy);
1507 static int getBorderElement(int x, int y)
1511 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1512 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1513 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1514 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1515 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1516 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1517 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1519 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1520 int steel_position = (x == -1 && y == -1 ? 0 :
1521 x == lev_fieldx && y == -1 ? 1 :
1522 x == -1 && y == lev_fieldy ? 2 :
1523 x == lev_fieldx && y == lev_fieldy ? 3 :
1524 x == -1 || x == lev_fieldx ? 4 :
1525 y == -1 || y == lev_fieldy ? 5 : 6);
1527 return border[steel_position][steel_type];
1530 void DrawScreenElement(int x, int y, int element)
1532 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1533 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1536 void DrawLevelElement(int x, int y, int element)
1538 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1539 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1542 void DrawScreenField(int x, int y)
1544 int lx = LEVELX(x), ly = LEVELY(y);
1545 int element, content;
1547 if (!IN_LEV_FIELD(lx, ly))
1549 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1552 element = getBorderElement(lx, ly);
1554 DrawScreenElement(x, y, element);
1558 element = Feld[lx][ly];
1559 content = Store[lx][ly];
1561 if (IS_MOVING(lx, ly))
1563 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1564 boolean cut_mode = NO_CUTTING;
1566 if (element == EL_QUICKSAND_EMPTYING ||
1567 element == EL_MAGIC_WALL_EMPTYING ||
1568 element == EL_BD_MAGIC_WALL_EMPTYING ||
1569 element == EL_AMOEBA_DROPPING)
1570 cut_mode = CUT_ABOVE;
1571 else if (element == EL_QUICKSAND_FILLING ||
1572 element == EL_MAGIC_WALL_FILLING ||
1573 element == EL_BD_MAGIC_WALL_FILLING)
1574 cut_mode = CUT_BELOW;
1576 if (cut_mode == CUT_ABOVE)
1577 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1579 DrawScreenElement(x, y, EL_EMPTY);
1582 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1583 else if (cut_mode == NO_CUTTING)
1584 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1586 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1588 if (content == EL_ACID)
1589 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1591 else if (IS_BLOCKED(lx, ly))
1596 boolean cut_mode = NO_CUTTING;
1597 int element_old, content_old;
1599 Blocked2Moving(lx, ly, &oldx, &oldy);
1602 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1603 MovDir[oldx][oldy] == MV_RIGHT);
1605 element_old = Feld[oldx][oldy];
1606 content_old = Store[oldx][oldy];
1608 if (element_old == EL_QUICKSAND_EMPTYING ||
1609 element_old == EL_MAGIC_WALL_EMPTYING ||
1610 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1611 element_old == EL_AMOEBA_DROPPING)
1612 cut_mode = CUT_ABOVE;
1614 DrawScreenElement(x, y, EL_EMPTY);
1617 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1619 else if (cut_mode == NO_CUTTING)
1620 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1623 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1626 else if (IS_DRAWABLE(element))
1627 DrawScreenElement(x, y, element);
1629 DrawScreenElement(x, y, EL_EMPTY);
1632 void DrawLevelField(int x, int y)
1634 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1635 DrawScreenField(SCREENX(x), SCREENY(y));
1636 else if (IS_MOVING(x, y))
1640 Moving2Blocked(x, y, &newx, &newy);
1641 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1642 DrawScreenField(SCREENX(newx), SCREENY(newy));
1644 else if (IS_BLOCKED(x, y))
1648 Blocked2Moving(x, y, &oldx, &oldy);
1649 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1650 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1654 void DrawMiniElement(int x, int y, int element)
1658 graphic = el2edimg(element);
1659 DrawMiniGraphic(x, y, graphic);
1662 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1664 int x = sx + scroll_x, y = sy + scroll_y;
1666 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1667 DrawMiniElement(sx, sy, EL_EMPTY);
1668 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1669 DrawMiniElement(sx, sy, Feld[x][y]);
1671 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1674 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1675 int x, int y, int xsize, int ysize, int font_nr)
1677 int font_width = getFontWidth(font_nr);
1678 int font_height = getFontHeight(font_nr);
1679 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1682 int dst_x = SX + startx + x * font_width;
1683 int dst_y = SY + starty + y * font_height;
1684 int width = graphic_info[graphic].width;
1685 int height = graphic_info[graphic].height;
1686 int inner_width = MAX(width - 2 * font_width, font_width);
1687 int inner_height = MAX(height - 2 * font_height, font_height);
1688 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1689 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1690 boolean draw_masked = graphic_info[graphic].draw_masked;
1692 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1694 if (src_bitmap == NULL || width < font_width || height < font_height)
1696 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1700 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1701 inner_sx + (x - 1) * font_width % inner_width);
1702 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1703 inner_sy + (y - 1) * font_height % inner_height);
1707 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1708 dst_x - src_x, dst_y - src_y);
1709 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1713 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1717 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1719 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1720 boolean draw_masked = graphic_info[graphic].draw_masked;
1721 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1722 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1723 unsigned long anim_delay = 0;
1724 int anim_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1725 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1726 int font_width = getFontWidth(font_nr);
1727 int font_height = getFontHeight(font_nr);
1728 int max_xsize = level.envelope_xsize[envelope_nr];
1729 int max_ysize = level.envelope_ysize[envelope_nr];
1730 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1731 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1732 int xend = max_xsize;
1733 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1734 int xstep = (xstart < xend ? 1 : 0);
1735 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1738 for (x=xstart, y=ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1740 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1741 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1742 int sx = (SXSIZE - xsize * font_width) / 2;
1743 int sy = (SYSIZE - ysize * font_height) / 2;
1746 SetDrawtoField(DRAW_BUFFERED);
1748 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1750 SetDrawtoField(DRAW_BACKBUFFER);
1752 for (yy=0; yy < ysize; yy++) for (xx=0; xx < xsize; xx++)
1753 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1755 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1756 level.envelope_text[envelope_nr], font_nr, max_xsize,
1757 xsize - 2, ysize - 2, mask_mode);
1759 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1762 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1766 void ShowEnvelope(int envelope_nr)
1768 int element = EL_ENVELOPE_1 + envelope_nr;
1769 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1770 int sound_opening = element_info[element].sound[ACTION_OPENING];
1771 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1772 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1773 int wait_delay_value = (ffwd_delay ? 500 : 1000);
1774 int anim_mode = graphic_info[graphic].anim_mode;
1775 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1776 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1778 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1780 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1782 if (anim_mode == ANIM_DEFAULT)
1783 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1785 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1788 Delay(wait_delay_value);
1790 WaitForEventToContinue();
1792 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1794 if (anim_mode != ANIM_NONE)
1795 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1797 if (anim_mode == ANIM_DEFAULT)
1798 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1800 game.envelope_active = FALSE;
1802 SetDrawtoField(DRAW_BUFFERED);
1804 redraw_mask |= REDRAW_FIELD;
1808 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1810 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1811 int mini_startx = src_bitmap->width * 3 / 4;
1812 int mini_starty = src_bitmap->height * 2 / 3;
1813 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1814 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1816 *bitmap = src_bitmap;
1821 void DrawMicroElement(int xpos, int ypos, int element)
1825 int graphic = el2preimg(element);
1827 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1828 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1836 SetDrawBackgroundMask(REDRAW_NONE);
1839 for(x=BX1; x<=BX2; x++)
1840 for(y=BY1; y<=BY2; y++)
1841 DrawScreenField(x, y);
1843 redraw_mask |= REDRAW_FIELD;
1846 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1850 for(x=0; x<size_x; x++)
1851 for(y=0; y<size_y; y++)
1852 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1854 redraw_mask |= REDRAW_FIELD;
1857 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1861 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1863 if (lev_fieldx < STD_LEV_FIELDX)
1864 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1865 if (lev_fieldy < STD_LEV_FIELDY)
1866 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1868 xpos += MICRO_TILEX;
1869 ypos += MICRO_TILEY;
1871 for(x=-1; x<=STD_LEV_FIELDX; x++)
1873 for(y=-1; y<=STD_LEV_FIELDY; y++)
1875 int lx = from_x + x, ly = from_y + y;
1877 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1878 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1879 level.field[lx][ly]);
1880 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1881 && BorderElement != EL_EMPTY)
1882 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1883 getBorderElement(lx, ly));
1887 redraw_mask |= REDRAW_MICROLEVEL;
1890 #define MICROLABEL_EMPTY 0
1891 #define MICROLABEL_LEVEL_NAME 1
1892 #define MICROLABEL_CREATED_BY 2
1893 #define MICROLABEL_LEVEL_AUTHOR 3
1894 #define MICROLABEL_IMPORTED_FROM 4
1895 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1897 static void DrawMicroLevelLabelExt(int mode)
1899 char label_text[MAX_OUTPUT_LINESIZE + 1];
1900 int max_len_label_text;
1901 int font_nr = FONT_TEXT_2;
1903 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1904 font_nr = FONT_TEXT_3;
1906 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1908 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1910 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1911 mode == MICROLABEL_CREATED_BY ? "created by" :
1912 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1913 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1914 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1915 leveldir_current->imported_from : ""),
1916 max_len_label_text);
1917 label_text[max_len_label_text] = '\0';
1919 if (strlen(label_text) > 0)
1921 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1922 int lypos = MICROLABEL_YPOS;
1924 DrawText(lxpos, lypos, label_text, font_nr);
1927 redraw_mask |= REDRAW_MICROLEVEL;
1930 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1932 static unsigned long scroll_delay = 0;
1933 static unsigned long label_delay = 0;
1934 static int from_x, from_y, scroll_direction;
1935 static int label_state, label_counter;
1936 int last_game_status = game_status; /* save current game status */
1938 /* force PREVIEW font on preview level */
1939 game_status = GAME_MODE_PSEUDO_PREVIEW;
1943 from_x = from_y = 0;
1944 scroll_direction = MV_RIGHT;
1948 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1949 DrawMicroLevelLabelExt(label_state);
1951 /* initialize delay counters */
1952 DelayReached(&scroll_delay, 0);
1953 DelayReached(&label_delay, 0);
1955 if (leveldir_current->name)
1957 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1958 int lxpos = SX + (SXSIZE - text_width) / 2;
1959 int lypos = SY + 352;
1961 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1964 game_status = last_game_status; /* restore current game status */
1969 /* scroll micro level, if needed */
1970 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1971 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1973 switch (scroll_direction)
1979 scroll_direction = MV_UP;
1983 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1986 scroll_direction = MV_DOWN;
1993 scroll_direction = MV_RIGHT;
1997 if (from_y < lev_fieldy - STD_LEV_FIELDY)
2000 scroll_direction = MV_LEFT;
2007 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
2010 /* redraw micro level label, if needed */
2011 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
2012 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
2013 strcmp(level.author, leveldir_current->name) != 0 &&
2014 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2016 int max_label_counter = 23;
2018 if (leveldir_current->imported_from != NULL)
2019 max_label_counter += 14;
2021 label_counter = (label_counter + 1) % max_label_counter;
2022 label_state = (label_counter >= 0 && label_counter <= 7 ?
2023 MICROLABEL_LEVEL_NAME :
2024 label_counter >= 9 && label_counter <= 12 ?
2025 MICROLABEL_CREATED_BY :
2026 label_counter >= 14 && label_counter <= 21 ?
2027 MICROLABEL_LEVEL_AUTHOR :
2028 label_counter >= 23 && label_counter <= 26 ?
2029 MICROLABEL_IMPORTED_FROM :
2030 label_counter >= 28 && label_counter <= 35 ?
2031 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
2032 DrawMicroLevelLabelExt(label_state);
2035 game_status = last_game_status; /* restore current game status */
2038 void WaitForEventToContinue()
2040 boolean still_wait = TRUE;
2042 /* simulate releasing mouse button over last gadget, if still pressed */
2044 HandleGadgets(-1, -1, 0);
2046 button_status = MB_RELEASED;
2058 case EVENT_BUTTONPRESS:
2059 case EVENT_KEYPRESS:
2063 case EVENT_KEYRELEASE:
2064 ClearPlayerAction();
2068 HandleOtherEvents(&event);
2072 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2079 /* don't eat all CPU time */
2084 #define MAX_REQUEST_LINES 13
2085 #define MAX_REQUEST_LINE_LEN 7
2087 boolean Request(char *text, unsigned int req_state)
2089 int mx, my, ty, result = -1;
2090 unsigned int old_door_state;
2091 int last_game_status = game_status; /* save current game status */
2094 SetMouseCursor(CURSOR_DEFAULT);
2097 #if defined(PLATFORM_UNIX)
2098 /* pause network game while waiting for request to answer */
2099 if (options.network &&
2100 game_status == GAME_MODE_PLAYING &&
2101 req_state & REQUEST_WAIT_FOR)
2102 SendToServer_PausePlaying();
2105 old_door_state = GetDoorState();
2107 /* simulate releasing mouse button over last gadget, if still pressed */
2109 HandleGadgets(-1, -1, 0);
2113 CloseDoor(DOOR_CLOSE_1);
2115 /* save old door content */
2116 BlitBitmap(bitmap_db_door, bitmap_db_door,
2117 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2118 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2120 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2122 /* clear door drawing field */
2123 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2125 /* force DOOR font on preview level */
2126 game_status = GAME_MODE_PSEUDO_DOOR;
2128 /* write text for request */
2129 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
2131 char text_line[MAX_REQUEST_LINE_LEN + 1];
2137 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
2140 if (!tc || tc == ' ')
2151 strncpy(text_line, text, tl);
2154 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
2155 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
2156 text_line, FONT_TEXT_2);
2158 text += tl + (tc == ' ' ? 1 : 0);
2161 game_status = last_game_status; /* restore current game status */
2163 if (req_state & REQ_ASK)
2165 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2166 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2168 else if (req_state & REQ_CONFIRM)
2170 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2172 else if (req_state & REQ_PLAYER)
2174 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2175 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2176 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2177 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2180 /* copy request gadgets to door backbuffer */
2181 BlitBitmap(drawto, bitmap_db_door,
2182 DX, DY, DXSIZE, DYSIZE,
2183 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2185 OpenDoor(DOOR_OPEN_1);
2191 if (!(req_state & REQUEST_WAIT_FOR))
2193 SetDrawBackgroundMask(REDRAW_FIELD);
2198 if (game_status != GAME_MODE_MAIN)
2201 button_status = MB_RELEASED;
2203 request_gadget_id = -1;
2205 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2208 SetMouseCursor(CURSOR_DEFAULT);
2221 case EVENT_BUTTONPRESS:
2222 case EVENT_BUTTONRELEASE:
2223 case EVENT_MOTIONNOTIFY:
2225 if (event.type == EVENT_MOTIONNOTIFY)
2227 if (!PointerInWindow(window))
2228 continue; /* window and pointer are on different screens */
2233 motion_status = TRUE;
2234 mx = ((MotionEvent *) &event)->x;
2235 my = ((MotionEvent *) &event)->y;
2239 motion_status = FALSE;
2240 mx = ((ButtonEvent *) &event)->x;
2241 my = ((ButtonEvent *) &event)->y;
2242 if (event.type == EVENT_BUTTONPRESS)
2243 button_status = ((ButtonEvent *) &event)->button;
2245 button_status = MB_RELEASED;
2248 /* this sets 'request_gadget_id' */
2249 HandleGadgets(mx, my, button_status);
2251 switch(request_gadget_id)
2253 case TOOL_CTRL_ID_YES:
2256 case TOOL_CTRL_ID_NO:
2259 case TOOL_CTRL_ID_CONFIRM:
2260 result = TRUE | FALSE;
2263 case TOOL_CTRL_ID_PLAYER_1:
2266 case TOOL_CTRL_ID_PLAYER_2:
2269 case TOOL_CTRL_ID_PLAYER_3:
2272 case TOOL_CTRL_ID_PLAYER_4:
2283 case EVENT_KEYPRESS:
2284 switch(GetEventKey((KeyEvent *)&event, TRUE))
2297 if (req_state & REQ_PLAYER)
2301 case EVENT_KEYRELEASE:
2302 ClearPlayerAction();
2306 HandleOtherEvents(&event);
2310 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2312 int joy = AnyJoystick();
2314 if (joy & JOY_BUTTON_1)
2316 else if (joy & JOY_BUTTON_2)
2322 /* don't eat all CPU time */
2326 if (game_status != GAME_MODE_MAIN)
2331 if (!(req_state & REQ_STAY_OPEN))
2333 CloseDoor(DOOR_CLOSE_1);
2335 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2337 BlitBitmap(bitmap_db_door, bitmap_db_door,
2338 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2339 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2340 OpenDoor(DOOR_OPEN_1);
2346 SetDrawBackgroundMask(REDRAW_FIELD);
2348 #if defined(PLATFORM_UNIX)
2349 /* continue network game after request */
2350 if (options.network &&
2351 game_status == GAME_MODE_PLAYING &&
2352 req_state & REQUEST_WAIT_FOR)
2353 SendToServer_ContinuePlaying();
2359 unsigned int OpenDoor(unsigned int door_state)
2361 unsigned int new_door_state;
2363 if (door_state & DOOR_COPY_BACK)
2365 BlitBitmap(bitmap_db_door, bitmap_db_door,
2366 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2367 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2368 door_state &= ~DOOR_COPY_BACK;
2371 new_door_state = MoveDoor(door_state);
2373 return(new_door_state);
2376 unsigned int CloseDoor(unsigned int door_state)
2378 unsigned int new_door_state;
2380 BlitBitmap(backbuffer, bitmap_db_door,
2381 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2382 BlitBitmap(backbuffer, bitmap_db_door,
2383 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2385 new_door_state = MoveDoor(door_state);
2387 return(new_door_state);
2390 unsigned int GetDoorState()
2392 return MoveDoor(DOOR_GET_STATE);
2395 unsigned int SetDoorState(unsigned int door_state)
2397 return MoveDoor(door_state | DOOR_SET_STATE);
2400 unsigned int MoveDoor(unsigned int door_state)
2402 static int door1 = DOOR_OPEN_1;
2403 static int door2 = DOOR_CLOSE_2;
2404 unsigned long door_delay = 0;
2405 unsigned long door_delay_value;
2408 if (door_state == DOOR_GET_STATE)
2409 return(door1 | door2);
2411 if (door_state & DOOR_SET_STATE)
2413 if (door_state & DOOR_ACTION_1)
2414 door1 = door_state & DOOR_ACTION_1;
2415 if (door_state & DOOR_ACTION_2)
2416 door2 = door_state & DOOR_ACTION_2;
2418 return(door1 | door2);
2421 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2422 door_state &= ~DOOR_OPEN_1;
2423 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2424 door_state &= ~DOOR_CLOSE_1;
2425 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2426 door_state &= ~DOOR_OPEN_2;
2427 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2428 door_state &= ~DOOR_CLOSE_2;
2430 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2433 if (setup.quick_doors)
2435 stepsize = 20; /* must be choosen to always draw last frame */
2436 door_delay_value = 0;
2438 StopSound(SND_DOOR_OPENING);
2439 StopSound(SND_DOOR_CLOSING);
2442 if (global.autoplay_leveldir)
2444 door_state |= DOOR_NO_DELAY;
2445 door_state &= ~DOOR_CLOSE_ALL;
2448 if (door_state & DOOR_ACTION)
2450 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2451 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2452 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2453 int end = (door_state & DOOR_ACTION_1 &&
2454 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2457 if (!(door_state & DOOR_NO_DELAY))
2459 /* opening door sound has priority over simultaneously closing door */
2460 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2461 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2462 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2463 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2466 for(x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2468 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2469 GC gc = bitmap->stored_clip_gc;
2471 if (door_state & DOOR_ACTION_1)
2473 int a = MIN(x * door_1.step_offset, end);
2474 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2478 BlitBitmap(bitmap_db_door, drawto,
2479 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2480 DXSIZE,DYSIZE - i / 2, DX, DY);
2482 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2485 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2487 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2488 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2489 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2490 int dst2_x = DX, dst2_y = DY;
2491 int width = i, height = DYSIZE;
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 (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2503 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2504 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2505 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2506 int dst2_x = DX, dst2_y = DY;
2507 int width = DXSIZE, height = i;
2509 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2510 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2513 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2514 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2517 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2519 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2521 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2522 BlitBitmapMasked(bitmap, drawto,
2523 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2524 DX + DXSIZE - i, DY + j);
2525 BlitBitmapMasked(bitmap, drawto,
2526 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2527 DX + DXSIZE - i, DY + 140 + j);
2528 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2529 DY - (DOOR_GFX_PAGEY1 + j));
2530 BlitBitmapMasked(bitmap, drawto,
2531 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2533 BlitBitmapMasked(bitmap, drawto,
2534 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2537 BlitBitmapMasked(bitmap, drawto,
2538 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2540 BlitBitmapMasked(bitmap, drawto,
2541 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2543 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2544 BlitBitmapMasked(bitmap, drawto,
2545 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2546 DX + DXSIZE - i, DY + 77 + j);
2547 BlitBitmapMasked(bitmap, drawto,
2548 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2549 DX + DXSIZE - i, DY + 203 + j);
2552 redraw_mask |= REDRAW_DOOR_1;
2553 door_1_done = (a == end);
2556 if (door_state & DOOR_ACTION_2)
2558 int a = MIN(x * door_2.step_offset, VXSIZE);
2559 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2563 BlitBitmap(bitmap_db_door, drawto,
2564 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2565 VXSIZE, VYSIZE - i / 2, VX, VY);
2567 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2570 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2572 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2573 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2574 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2575 int dst2_x = VX, dst2_y = VY;
2576 int width = i, height = VYSIZE;
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 (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2588 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2589 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2590 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2591 int dst2_x = VX, dst2_y = VY;
2592 int width = VXSIZE, height = i;
2594 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2595 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2598 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2599 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2602 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2604 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2606 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2607 BlitBitmapMasked(bitmap, drawto,
2608 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2609 VX + VXSIZE - i, VY + j);
2610 SetClipOrigin(bitmap, gc,
2611 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2612 BlitBitmapMasked(bitmap, drawto,
2613 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2616 BlitBitmapMasked(bitmap, drawto,
2617 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2618 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2619 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2620 BlitBitmapMasked(bitmap, drawto,
2621 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2623 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2626 redraw_mask |= REDRAW_DOOR_2;
2627 door_2_done = (a == VXSIZE);
2632 if (game_status == GAME_MODE_MAIN)
2635 if (!(door_state & DOOR_NO_DELAY))
2636 WaitUntilDelayReached(&door_delay, door_delay_value);
2640 if (setup.quick_doors)
2642 StopSound(SND_DOOR_OPENING);
2643 StopSound(SND_DOOR_CLOSING);
2646 if (door_state & DOOR_ACTION_1)
2647 door1 = door_state & DOOR_ACTION_1;
2648 if (door_state & DOOR_ACTION_2)
2649 door2 = door_state & DOOR_ACTION_2;
2651 return (door1 | door2);
2654 void DrawSpecialEditorDoor()
2656 /* draw bigger toolbox window */
2657 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2658 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2660 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2661 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2664 redraw_mask |= REDRAW_ALL;
2667 void UndrawSpecialEditorDoor()
2669 /* draw normal tape recorder window */
2670 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2671 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2674 redraw_mask |= REDRAW_ALL;
2678 /* ---------- new tool button stuff ---------------------------------------- */
2680 /* graphic position values for tool buttons */
2681 #define TOOL_BUTTON_YES_XPOS 2
2682 #define TOOL_BUTTON_YES_YPOS 250
2683 #define TOOL_BUTTON_YES_GFX_YPOS 0
2684 #define TOOL_BUTTON_YES_XSIZE 46
2685 #define TOOL_BUTTON_YES_YSIZE 28
2686 #define TOOL_BUTTON_NO_XPOS 52
2687 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2688 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2689 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2690 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2691 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2692 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2693 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2694 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2695 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2696 #define TOOL_BUTTON_PLAYER_XSIZE 30
2697 #define TOOL_BUTTON_PLAYER_YSIZE 30
2698 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2699 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2700 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2701 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2702 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2703 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2704 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2705 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2706 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2707 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2708 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2709 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2710 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2711 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2712 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2713 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2714 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2715 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2716 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2717 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2726 } toolbutton_info[NUM_TOOL_BUTTONS] =
2729 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2730 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2731 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2736 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2737 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2738 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2743 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2744 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2745 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2746 TOOL_CTRL_ID_CONFIRM,
2750 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2751 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2752 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2753 TOOL_CTRL_ID_PLAYER_1,
2757 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2758 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2759 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2760 TOOL_CTRL_ID_PLAYER_2,
2764 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2765 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2766 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2767 TOOL_CTRL_ID_PLAYER_3,
2771 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2772 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2773 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2774 TOOL_CTRL_ID_PLAYER_4,
2779 void CreateToolButtons()
2783 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2785 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2786 Bitmap *deco_bitmap = None;
2787 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2788 struct GadgetInfo *gi;
2789 unsigned long event_mask;
2790 int gd_xoffset, gd_yoffset;
2791 int gd_x1, gd_x2, gd_y;
2794 event_mask = GD_EVENT_RELEASED;
2796 gd_xoffset = toolbutton_info[i].xpos;
2797 gd_yoffset = toolbutton_info[i].ypos;
2798 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2799 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2800 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2802 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2804 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2806 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2807 &deco_bitmap, &deco_x, &deco_y);
2808 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2809 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2812 gi = CreateGadget(GDI_CUSTOM_ID, id,
2813 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2814 GDI_X, DX + toolbutton_info[i].x,
2815 GDI_Y, DY + toolbutton_info[i].y,
2816 GDI_WIDTH, toolbutton_info[i].width,
2817 GDI_HEIGHT, toolbutton_info[i].height,
2818 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2819 GDI_STATE, GD_BUTTON_UNPRESSED,
2820 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2821 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2822 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2823 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2824 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2825 GDI_DECORATION_SHIFTING, 1, 1,
2826 GDI_EVENT_MASK, event_mask,
2827 GDI_CALLBACK_ACTION, HandleToolButtons,
2831 Error(ERR_EXIT, "cannot create gadget");
2833 tool_gadget[id] = gi;
2837 void FreeToolButtons()
2841 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2842 FreeGadget(tool_gadget[i]);
2845 static void UnmapToolButtons()
2849 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2850 UnmapGadget(tool_gadget[i]);
2853 static void HandleToolButtons(struct GadgetInfo *gi)
2855 request_gadget_id = gi->custom_id;
2858 int get_next_element(int element)
2862 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2863 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2864 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2865 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2866 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2867 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2868 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2870 default: return element;
2874 int el_act_dir2img(int element, int action, int direction)
2876 element = GFX_ELEMENT(element);
2877 direction = MV_DIR_BIT(direction);
2879 return element_info[element].direction_graphic[action][direction];
2882 static int el_act_dir2crm(int element, int action, int direction)
2884 element = GFX_ELEMENT(element);
2885 direction = MV_DIR_BIT(direction);
2887 return element_info[element].direction_crumbled[action][direction];
2890 int el_act2img(int element, int action)
2892 element = GFX_ELEMENT(element);
2894 return element_info[element].graphic[action];
2897 int el_act2crm(int element, int action)
2899 element = GFX_ELEMENT(element);
2901 return element_info[element].crumbled[action];
2904 int el_dir2img(int element, int direction)
2906 element = GFX_ELEMENT(element);
2908 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2911 int el2img(int element)
2913 element = GFX_ELEMENT(element);
2915 return element_info[element].graphic[ACTION_DEFAULT];
2918 int el2edimg(int element)
2920 element = GFX_ELEMENT(element);
2922 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2925 int el2preimg(int element)
2927 element = GFX_ELEMENT(element);
2929 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];