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 getPlayerGraphic(struct PlayerInfo *player, int move_dir)
534 if (player->use_murphy_graphic)
536 /* this works only because currently only one player can be "murphy" ... */
537 static int last_horizontal_dir = MV_LEFT;
538 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
540 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
541 last_horizontal_dir = move_dir;
543 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
545 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
547 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
553 return el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
556 static boolean equalGraphics(int graphic1, int graphic2)
558 struct GraphicInfo *g1 = &graphic_info[graphic1];
559 struct GraphicInfo *g2 = &graphic_info[graphic2];
561 return (g1->bitmap == g2->bitmap &&
562 g1->src_x == g2->src_x &&
563 g1->src_y == g2->src_y &&
564 g1->anim_frames == g2->anim_frames &&
565 g1->anim_delay == g2->anim_delay &&
566 g1->anim_mode == g2->anim_mode);
569 void DrawAllPlayers()
573 for(i=0; i<MAX_PLAYERS; i++)
574 if (stored_player[i].active)
575 DrawPlayer(&stored_player[i]);
578 void DrawPlayerField(int x, int y)
580 if (!IS_PLAYER(x, y))
583 DrawPlayer(PLAYERINFO(x, y));
586 void DrawPlayer(struct PlayerInfo *player)
590 int move_dir = player->MovDir;
592 int last_jx = player->last_jx;
593 int last_jy = player->last_jy;
594 int next_jx = jx + (jx - last_jx);
595 int next_jy = jy + (jy - last_jy);
596 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
598 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
599 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
600 int last_jx = (player->is_moving ? jx - dx : jx);
601 int last_jy = (player->is_moving ? jy - dy : jy);
602 int next_jx = jx + dx;
603 int next_jy = jy + dy;
604 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
606 int sx = SCREENX(jx), sy = SCREENY(jy);
607 int sxx = 0, syy = 0;
608 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
610 int action = ACTION_DEFAULT;
611 int last_player_graphic = getPlayerGraphic(player, move_dir);
612 int last_player_frame = player->Frame;
615 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
619 if (!IN_LEV_FIELD(jx, jy))
621 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
622 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
623 printf("DrawPlayerField(): This should never happen!\n");
628 if (element == EL_EXPLOSION)
631 action = (player->is_pushing ? ACTION_PUSHING :
632 player->is_digging ? ACTION_DIGGING :
633 player->is_collecting ? ACTION_COLLECTING :
634 player->is_moving ? ACTION_MOVING :
635 player->is_snapping ? ACTION_SNAPPING :
636 player->is_sleeping ? ACTION_SLEEPING :
637 player->is_bored ? ACTION_BORING :
638 player->is_waiting ? ACTION_WAITING : ACTION_DEFAULT);
640 if (player->is_bored || player->is_sleeping)
646 printf("::: '%s'\n", element_action_info[action].suffix);
649 InitPlayerGfxAnimation(player, action, move_dir);
651 /* ----------------------------------------------------------------------- */
652 /* draw things in the field the player is leaving, if needed */
653 /* ----------------------------------------------------------------------- */
656 if (player->is_moving)
658 if (player_is_moving)
661 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
663 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
665 if (last_element == EL_DYNAMITE_ACTIVE ||
666 last_element == EL_SP_DISK_RED_ACTIVE)
667 DrawDynamite(last_jx, last_jy);
669 DrawLevelFieldThruMask(last_jx, last_jy);
671 else if (last_element == EL_DYNAMITE_ACTIVE ||
672 last_element == EL_SP_DISK_RED_ACTIVE)
673 DrawDynamite(last_jx, last_jy);
675 DrawLevelField(last_jx, last_jy);
677 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
678 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
681 if (!IN_SCR_FIELD(sx, sy))
684 if (setup.direct_draw)
685 SetDrawtoField(DRAW_BUFFERED);
687 /* ----------------------------------------------------------------------- */
688 /* draw things behind the player, if needed */
689 /* ----------------------------------------------------------------------- */
692 DrawLevelElement(jx, jy, Back[jx][jy]);
693 else if (IS_ACTIVE_BOMB(element))
694 DrawLevelElement(jx, jy, EL_EMPTY);
697 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
699 if (GFX_CRUMBLED(GfxElement[jx][jy]))
700 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
703 int old_element = GfxElement[jx][jy];
704 int old_graphic = el_act_dir2img(old_element, action, move_dir);
705 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
707 DrawGraphic(sx, sy, old_graphic, frame);
712 GfxElement[jx][jy] = EL_UNDEFINED;
714 DrawLevelField(jx, jy);
718 /* ----------------------------------------------------------------------- */
719 /* draw player himself */
720 /* ----------------------------------------------------------------------- */
724 graphic = getPlayerGraphic(player, move_dir);
726 /* in the case of changed player action or direction, prevent the current
727 animation frame from being restarted for identical animations */
728 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
729 player->Frame = last_player_frame;
733 if (player->use_murphy_graphic)
735 static int last_horizontal_dir = MV_LEFT;
737 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
738 last_horizontal_dir = move_dir;
740 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
742 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
744 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
746 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
750 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
754 frame = getGraphicAnimationFrame(graphic, player->Frame);
758 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
759 sxx = player->GfxPos;
761 syy = player->GfxPos;
764 if (!setup.soft_scrolling && ScreenMovPos)
767 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
769 if (SHIELD_ON(player))
771 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
772 IMG_SHIELD_NORMAL_ACTIVE);
773 int frame = getGraphicAnimationFrame(graphic, -1);
775 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
778 /* ----------------------------------------------------------------------- */
779 /* draw things the player is pushing, if needed */
780 /* ----------------------------------------------------------------------- */
783 printf("::: %d, %d [%d, %d] [%d]\n",
784 player->is_pushing, player_is_moving, player->GfxAction,
785 player->is_moving, player_is_moving);
789 if (player->is_pushing && player->is_moving)
791 if (player->is_pushing && player_is_moving)
794 int px = SCREENX(next_jx), py = SCREENY(next_jy);
796 if (Back[next_jx][next_jy])
797 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
799 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
800 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
804 int element = MovingOrBlocked2Element(next_jx, next_jy);
805 int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
807 int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
809 int frame = getGraphicAnimationFrame(graphic, player->Frame);
812 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
813 NO_CUTTING, NO_MASKING);
817 /* ----------------------------------------------------------------------- */
818 /* draw things in front of player (active dynamite or dynabombs) */
819 /* ----------------------------------------------------------------------- */
821 if (IS_ACTIVE_BOMB(element))
823 graphic = el2img(element);
824 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
826 if (game.emulation == EMU_SUPAPLEX)
827 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
829 DrawGraphicThruMask(sx, sy, graphic, frame);
832 if (player_is_moving && last_element == EL_EXPLOSION)
834 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
835 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
836 int phase = ExplodePhase[last_jx][last_jy] - 1;
837 int frame = getGraphicAnimationFrame(graphic, phase - delay);
840 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
843 /* ----------------------------------------------------------------------- */
844 /* draw elements the player is just walking/passing through/under */
845 /* ----------------------------------------------------------------------- */
847 /* handle the field the player is leaving ... */
848 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
849 DrawLevelField(last_jx, last_jy);
850 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
851 DrawLevelFieldThruMask(last_jx, last_jy);
853 /* ... and the field the player is entering */
854 if (IS_ACCESSIBLE_INSIDE(element))
855 DrawLevelField(jx, jy);
856 else if (IS_ACCESSIBLE_UNDER(element))
857 DrawLevelFieldThruMask(jx, jy);
859 if (setup.direct_draw)
861 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
862 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
863 int x_size = TILEX * (1 + ABS(jx - last_jx));
864 int y_size = TILEY * (1 + ABS(jy - last_jy));
866 BlitBitmap(drawto_field, window,
867 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
868 SetDrawtoField(DRAW_DIRECT);
871 MarkTileDirty(sx,sy);
874 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
876 struct GraphicInfo *g = &graphic_info[graphic];
880 if (g->offset_y == 0) /* frames are ordered horizontally */
882 int max_width = g->anim_frames_per_line * g->width;
884 *x = (g->src_x + frame * g->offset_x) % max_width;
885 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
887 else if (g->offset_x == 0) /* frames are ordered vertically */
889 int max_height = g->anim_frames_per_line * g->height;
891 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
892 *y = (g->src_y + frame * g->offset_y) % max_height;
894 else /* frames are ordered diagonally */
896 *x = g->src_x + frame * g->offset_x;
897 *y = g->src_y + frame * g->offset_y;
901 void DrawGraphic(int x, int y, int graphic, int frame)
904 if (!IN_SCR_FIELD(x, y))
906 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
907 printf("DrawGraphic(): This should never happen!\n");
912 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
916 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
922 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
923 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
926 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
929 if (!IN_SCR_FIELD(x, y))
931 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
932 printf("DrawGraphicThruMask(): This should never happen!\n");
937 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
942 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
950 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
951 drawing_gc = src_bitmap->stored_clip_gc;
953 GC drawing_gc = src_bitmap->stored_clip_gc;
954 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
955 int src_x = graphic_info[graphic].src_x;
956 int src_y = graphic_info[graphic].src_y;
957 int offset_x = graphic_info[graphic].offset_x;
958 int offset_y = graphic_info[graphic].offset_y;
960 src_x += frame * offset_x;
961 src_y += frame * offset_y;
965 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
966 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
969 void DrawMiniGraphic(int x, int y, int graphic)
971 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
972 MarkTileDirty(x / 2, y / 2);
975 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
977 struct GraphicInfo *g = &graphic_info[graphic];
979 int mini_starty = g->bitmap->height * 2 / 3;
982 *x = mini_startx + g->src_x / 2;
983 *y = mini_starty + g->src_y / 2;
986 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
991 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
992 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
995 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
996 int cut_mode, int mask_mode)
1001 int width = TILEX, height = TILEY;
1007 DrawGraphic(x, y, graphic, frame);
1011 if (dx || dy) /* shifted graphic */
1013 if (x < BX1) /* object enters playfield from the left */
1020 else if (x > BX2) /* object enters playfield from the right */
1026 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1032 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1034 else if (dx) /* general horizontal movement */
1035 MarkTileDirty(x + SIGN(dx), y);
1037 if (y < BY1) /* object enters playfield from the top */
1039 if (cut_mode==CUT_BELOW) /* object completely above top border */
1047 else if (y > BY2) /* object enters playfield from the bottom */
1053 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1059 else if (dy > 0 && cut_mode == CUT_ABOVE)
1061 if (y == BY2) /* object completely above bottom border */
1067 MarkTileDirty(x, y + 1);
1068 } /* object leaves playfield to the bottom */
1069 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1071 else if (dy) /* general vertical movement */
1072 MarkTileDirty(x, y + SIGN(dy));
1076 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1078 src_bitmap = graphic_info[graphic].bitmap;
1079 src_x = graphic_info[graphic].src_x;
1080 src_y = graphic_info[graphic].src_y;
1081 offset_x = graphic_info[graphic].offset_x;
1082 offset_y = graphic_info[graphic].offset_y;
1084 src_x += frame * offset_x;
1085 src_y += frame * offset_y;
1088 drawing_gc = src_bitmap->stored_clip_gc;
1093 dest_x = FX + x * TILEX + dx;
1094 dest_y = FY + y * TILEY + dy;
1097 if (!IN_SCR_FIELD(x,y))
1099 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1100 printf("DrawGraphicShifted(): This should never happen!\n");
1105 if (mask_mode == USE_MASKING)
1107 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1108 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1112 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1118 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1119 int frame, int cut_mode)
1121 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1124 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1125 int cut_mode, int mask_mode)
1127 int lx = LEVELX(x), ly = LEVELY(y);
1131 if (IN_LEV_FIELD(lx, ly))
1133 SetRandomAnimationValue(lx, ly);
1135 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1136 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1138 else /* border element */
1140 graphic = el2img(element);
1141 frame = getGraphicAnimationFrame(graphic, -1);
1144 if (element == EL_EXPANDABLE_WALL)
1146 boolean left_stopped = FALSE, right_stopped = FALSE;
1148 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1149 left_stopped = TRUE;
1150 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1151 right_stopped = TRUE;
1153 if (left_stopped && right_stopped)
1155 else if (left_stopped)
1157 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1158 frame = graphic_info[graphic].anim_frames - 1;
1160 else if (right_stopped)
1162 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1163 frame = graphic_info[graphic].anim_frames - 1;
1168 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1169 else if (mask_mode == USE_MASKING)
1170 DrawGraphicThruMask(x, y, graphic, frame);
1172 DrawGraphic(x, y, graphic, frame);
1175 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1176 int cut_mode, int mask_mode)
1178 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1179 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1180 cut_mode, mask_mode);
1183 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1186 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1189 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1192 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1195 void DrawLevelElementThruMask(int x, int y, int element)
1197 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1200 void DrawLevelFieldThruMask(int x, int y)
1202 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1205 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1209 int sx = SCREENX(x), sy = SCREENY(y);
1211 int width, height, cx, cy, i;
1213 int crumbled_border_size = graphic_info[graphic].border_size;
1215 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1217 static int xy[4][2] =
1226 if (x == 0 && y == 7)
1227 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1228 crumbled_border_size);
1231 if (!IN_LEV_FIELD(x, y))
1234 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1235 GfxElement[x][y] : Feld[x][y]);
1237 /* crumble field itself */
1238 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1240 if (!IN_SCR_FIELD(sx, sy))
1243 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1247 int xx = x + xy[i][0];
1248 int yy = y + xy[i][1];
1250 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1252 /* check if neighbour field is of same type */
1253 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1257 if (Feld[x][y] == EL_CUSTOM_START + 123)
1258 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1259 i, Feld[x][y], element,
1260 GFX_CRUMBLED(element), IS_MOVING(x, y));
1263 if (i == 1 || i == 2)
1265 width = crumbled_border_size;
1267 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1273 height = crumbled_border_size;
1275 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1278 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1279 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1282 MarkTileDirty(sx, sy);
1284 else /* crumble neighbour fields */
1287 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1292 int xx = x + xy[i][0];
1293 int yy = y + xy[i][1];
1294 int sxx = sx + xy[i][0];
1295 int syy = sy + xy[i][1];
1297 if (!IN_LEV_FIELD(xx, yy) ||
1298 !IN_SCR_FIELD(sxx, syy) ||
1299 !GFX_CRUMBLED(Feld[xx][yy]) ||
1304 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1305 crumbled_border_size = graphic_info[graphic].border_size;
1307 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1310 if (i == 1 || i == 2)
1312 width = crumbled_border_size;
1314 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1320 height = crumbled_border_size;
1322 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1325 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1326 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1328 MarkTileDirty(sxx, syy);
1333 void DrawLevelFieldCrumbledSand(int x, int y)
1338 if (!IN_LEV_FIELD(x, y))
1341 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1343 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1345 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1349 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1353 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1354 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1356 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1357 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1359 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1360 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1361 int sx = SCREENX(x), sy = SCREENY(y);
1363 DrawGraphic(sx, sy, graphic1, frame1);
1364 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1367 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1369 int sx = SCREENX(x), sy = SCREENY(y);
1370 static int xy[4][2] =
1381 int xx = x + xy[i][0];
1382 int yy = y + xy[i][1];
1383 int sxx = sx + xy[i][0];
1384 int syy = sy + xy[i][1];
1386 if (!IN_LEV_FIELD(xx, yy) ||
1387 !IN_SCR_FIELD(sxx, syy) ||
1388 !GFX_CRUMBLED(Feld[xx][yy]) ||
1392 DrawLevelField(xx, yy);
1396 static int getBorderElement(int x, int y)
1400 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1401 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1402 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1403 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1404 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1405 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1406 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1408 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1409 int steel_position = (x == -1 && y == -1 ? 0 :
1410 x == lev_fieldx && y == -1 ? 1 :
1411 x == -1 && y == lev_fieldy ? 2 :
1412 x == lev_fieldx && y == lev_fieldy ? 3 :
1413 x == -1 || x == lev_fieldx ? 4 :
1414 y == -1 || y == lev_fieldy ? 5 : 6);
1416 return border[steel_position][steel_type];
1419 void DrawScreenElement(int x, int y, int element)
1421 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1422 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1425 void DrawLevelElement(int x, int y, int element)
1427 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1428 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1431 void DrawScreenField(int x, int y)
1433 int lx = LEVELX(x), ly = LEVELY(y);
1434 int element, content;
1436 if (!IN_LEV_FIELD(lx, ly))
1438 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1441 element = getBorderElement(lx, ly);
1443 DrawScreenElement(x, y, element);
1447 element = Feld[lx][ly];
1448 content = Store[lx][ly];
1450 if (IS_MOVING(lx, ly))
1452 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1453 boolean cut_mode = NO_CUTTING;
1455 if (element == EL_QUICKSAND_EMPTYING ||
1456 element == EL_MAGIC_WALL_EMPTYING ||
1457 element == EL_BD_MAGIC_WALL_EMPTYING ||
1458 element == EL_AMOEBA_DROPPING)
1459 cut_mode = CUT_ABOVE;
1460 else if (element == EL_QUICKSAND_FILLING ||
1461 element == EL_MAGIC_WALL_FILLING ||
1462 element == EL_BD_MAGIC_WALL_FILLING)
1463 cut_mode = CUT_BELOW;
1465 if (cut_mode == CUT_ABOVE)
1466 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1468 DrawScreenElement(x, y, EL_EMPTY);
1471 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1472 else if (cut_mode == NO_CUTTING)
1473 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1475 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1477 if (content == EL_ACID)
1478 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1480 else if (IS_BLOCKED(lx, ly))
1485 boolean cut_mode = NO_CUTTING;
1486 int element_old, content_old;
1488 Blocked2Moving(lx, ly, &oldx, &oldy);
1491 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1492 MovDir[oldx][oldy] == MV_RIGHT);
1494 element_old = Feld[oldx][oldy];
1495 content_old = Store[oldx][oldy];
1497 if (element_old == EL_QUICKSAND_EMPTYING ||
1498 element_old == EL_MAGIC_WALL_EMPTYING ||
1499 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1500 element_old == EL_AMOEBA_DROPPING)
1501 cut_mode = CUT_ABOVE;
1503 DrawScreenElement(x, y, EL_EMPTY);
1506 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1508 else if (cut_mode == NO_CUTTING)
1509 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1512 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1515 else if (IS_DRAWABLE(element))
1516 DrawScreenElement(x, y, element);
1518 DrawScreenElement(x, y, EL_EMPTY);
1521 void DrawLevelField(int x, int y)
1523 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1524 DrawScreenField(SCREENX(x), SCREENY(y));
1525 else if (IS_MOVING(x, y))
1529 Moving2Blocked(x, y, &newx, &newy);
1530 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1531 DrawScreenField(SCREENX(newx), SCREENY(newy));
1533 else if (IS_BLOCKED(x, y))
1537 Blocked2Moving(x, y, &oldx, &oldy);
1538 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1539 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1543 void DrawMiniElement(int x, int y, int element)
1547 graphic = el2edimg(element);
1548 DrawMiniGraphic(x, y, graphic);
1551 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1553 int x = sx + scroll_x, y = sy + scroll_y;
1555 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1556 DrawMiniElement(sx, sy, EL_EMPTY);
1557 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1558 DrawMiniElement(sx, sy, Feld[x][y]);
1560 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1563 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1564 int x, int y, int xsize, int ysize, int font_nr)
1566 int font_width = getFontWidth(font_nr);
1567 int font_height = getFontHeight(font_nr);
1568 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1571 int dst_x = SX + startx + x * font_width;
1572 int dst_y = SY + starty + y * font_height;
1573 int width = graphic_info[graphic].width;
1574 int height = graphic_info[graphic].height;
1575 int inner_width = MAX(width - 2 * font_width, font_width);
1576 int inner_height = MAX(height - 2 * font_height, font_height);
1577 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1578 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1579 boolean draw_masked = graphic_info[graphic].draw_masked;
1581 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1583 if (src_bitmap == NULL || width < font_width || height < font_height)
1585 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1589 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1590 inner_sx + (x - 1) * font_width % inner_width);
1591 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1592 inner_sy + (y - 1) * font_height % inner_height);
1596 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1597 dst_x - src_x, dst_y - src_y);
1598 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1602 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1606 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1608 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1609 boolean draw_masked = graphic_info[graphic].draw_masked;
1610 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1611 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1612 unsigned long anim_delay = 0;
1613 int anim_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1614 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1615 int font_width = getFontWidth(font_nr);
1616 int font_height = getFontHeight(font_nr);
1617 int max_xsize = level.envelope_xsize[envelope_nr];
1618 int max_ysize = level.envelope_ysize[envelope_nr];
1619 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1620 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1621 int xend = max_xsize;
1622 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1623 int xstep = (xstart < xend ? 1 : 0);
1624 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1627 for (x=xstart, y=ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1629 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1630 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1631 int sx = (SXSIZE - xsize * font_width) / 2;
1632 int sy = (SYSIZE - ysize * font_height) / 2;
1635 SetDrawtoField(DRAW_BUFFERED);
1637 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1639 SetDrawtoField(DRAW_BACKBUFFER);
1641 for (yy=0; yy < ysize; yy++) for (xx=0; xx < xsize; xx++)
1642 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1644 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1645 level.envelope_text[envelope_nr], font_nr, max_xsize,
1646 xsize - 2, ysize - 2, mask_mode);
1648 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1651 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1655 void ShowEnvelope(int envelope_nr)
1657 int element = EL_ENVELOPE_1 + envelope_nr;
1658 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1659 int sound_opening = element_info[element].sound[ACTION_OPENING];
1660 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1661 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1662 int wait_delay_value = (ffwd_delay ? 500 : 1000);
1663 int anim_mode = graphic_info[graphic].anim_mode;
1664 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1665 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1667 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1669 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1671 if (anim_mode == ANIM_DEFAULT)
1672 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1674 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1677 Delay(wait_delay_value);
1679 WaitForEventToContinue();
1681 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1683 if (anim_mode != ANIM_NONE)
1684 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1686 if (anim_mode == ANIM_DEFAULT)
1687 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1689 game.envelope_active = FALSE;
1691 SetDrawtoField(DRAW_BUFFERED);
1693 redraw_mask |= REDRAW_FIELD;
1697 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1699 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1700 int mini_startx = src_bitmap->width * 3 / 4;
1701 int mini_starty = src_bitmap->height * 2 / 3;
1702 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1703 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1705 *bitmap = src_bitmap;
1710 void DrawMicroElement(int xpos, int ypos, int element)
1714 int graphic = el2preimg(element);
1716 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1717 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1725 SetDrawBackgroundMask(REDRAW_NONE);
1728 for(x=BX1; x<=BX2; x++)
1729 for(y=BY1; y<=BY2; y++)
1730 DrawScreenField(x, y);
1732 redraw_mask |= REDRAW_FIELD;
1735 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1739 for(x=0; x<size_x; x++)
1740 for(y=0; y<size_y; y++)
1741 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1743 redraw_mask |= REDRAW_FIELD;
1746 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1750 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1752 if (lev_fieldx < STD_LEV_FIELDX)
1753 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1754 if (lev_fieldy < STD_LEV_FIELDY)
1755 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1757 xpos += MICRO_TILEX;
1758 ypos += MICRO_TILEY;
1760 for(x=-1; x<=STD_LEV_FIELDX; x++)
1762 for(y=-1; y<=STD_LEV_FIELDY; y++)
1764 int lx = from_x + x, ly = from_y + y;
1766 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1767 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1768 level.field[lx][ly]);
1769 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1770 && BorderElement != EL_EMPTY)
1771 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1772 getBorderElement(lx, ly));
1776 redraw_mask |= REDRAW_MICROLEVEL;
1779 #define MICROLABEL_EMPTY 0
1780 #define MICROLABEL_LEVEL_NAME 1
1781 #define MICROLABEL_CREATED_BY 2
1782 #define MICROLABEL_LEVEL_AUTHOR 3
1783 #define MICROLABEL_IMPORTED_FROM 4
1784 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1786 static void DrawMicroLevelLabelExt(int mode)
1788 char label_text[MAX_OUTPUT_LINESIZE + 1];
1789 int max_len_label_text;
1790 int font_nr = FONT_TEXT_2;
1792 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1793 font_nr = FONT_TEXT_3;
1795 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1797 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1799 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1800 mode == MICROLABEL_CREATED_BY ? "created by" :
1801 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1802 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1803 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1804 leveldir_current->imported_from : ""),
1805 max_len_label_text);
1806 label_text[max_len_label_text] = '\0';
1808 if (strlen(label_text) > 0)
1810 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1811 int lypos = MICROLABEL_YPOS;
1813 DrawText(lxpos, lypos, label_text, font_nr);
1816 redraw_mask |= REDRAW_MICROLEVEL;
1819 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1821 static unsigned long scroll_delay = 0;
1822 static unsigned long label_delay = 0;
1823 static int from_x, from_y, scroll_direction;
1824 static int label_state, label_counter;
1825 int last_game_status = game_status; /* save current game status */
1827 /* force PREVIEW font on preview level */
1828 game_status = GAME_MODE_PSEUDO_PREVIEW;
1832 from_x = from_y = 0;
1833 scroll_direction = MV_RIGHT;
1837 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1838 DrawMicroLevelLabelExt(label_state);
1840 /* initialize delay counters */
1841 DelayReached(&scroll_delay, 0);
1842 DelayReached(&label_delay, 0);
1844 if (leveldir_current->name)
1846 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1847 int lxpos = SX + (SXSIZE - text_width) / 2;
1848 int lypos = SY + 352;
1850 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1853 game_status = last_game_status; /* restore current game status */
1858 /* scroll micro level, if needed */
1859 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1860 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1862 switch (scroll_direction)
1868 scroll_direction = MV_UP;
1872 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1875 scroll_direction = MV_DOWN;
1882 scroll_direction = MV_RIGHT;
1886 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1889 scroll_direction = MV_LEFT;
1896 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1899 /* redraw micro level label, if needed */
1900 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1901 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1902 strcmp(level.author, leveldir_current->name) != 0 &&
1903 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1905 int max_label_counter = 23;
1907 if (leveldir_current->imported_from != NULL)
1908 max_label_counter += 14;
1910 label_counter = (label_counter + 1) % max_label_counter;
1911 label_state = (label_counter >= 0 && label_counter <= 7 ?
1912 MICROLABEL_LEVEL_NAME :
1913 label_counter >= 9 && label_counter <= 12 ?
1914 MICROLABEL_CREATED_BY :
1915 label_counter >= 14 && label_counter <= 21 ?
1916 MICROLABEL_LEVEL_AUTHOR :
1917 label_counter >= 23 && label_counter <= 26 ?
1918 MICROLABEL_IMPORTED_FROM :
1919 label_counter >= 28 && label_counter <= 35 ?
1920 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1921 DrawMicroLevelLabelExt(label_state);
1924 game_status = last_game_status; /* restore current game status */
1927 void WaitForEventToContinue()
1929 boolean still_wait = TRUE;
1931 /* simulate releasing mouse button over last gadget, if still pressed */
1933 HandleGadgets(-1, -1, 0);
1935 button_status = MB_RELEASED;
1947 case EVENT_BUTTONPRESS:
1948 case EVENT_KEYPRESS:
1952 case EVENT_KEYRELEASE:
1953 ClearPlayerAction();
1957 HandleOtherEvents(&event);
1961 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1968 /* don't eat all CPU time */
1973 #define MAX_REQUEST_LINES 13
1974 #define MAX_REQUEST_LINE_LEN 7
1976 boolean Request(char *text, unsigned int req_state)
1978 int mx, my, ty, result = -1;
1979 unsigned int old_door_state;
1980 int last_game_status = game_status; /* save current game status */
1983 SetMouseCursor(CURSOR_DEFAULT);
1986 #if defined(PLATFORM_UNIX)
1987 /* pause network game while waiting for request to answer */
1988 if (options.network &&
1989 game_status == GAME_MODE_PLAYING &&
1990 req_state & REQUEST_WAIT_FOR)
1991 SendToServer_PausePlaying();
1994 old_door_state = GetDoorState();
1996 /* simulate releasing mouse button over last gadget, if still pressed */
1998 HandleGadgets(-1, -1, 0);
2002 CloseDoor(DOOR_CLOSE_1);
2004 /* save old door content */
2005 BlitBitmap(bitmap_db_door, bitmap_db_door,
2006 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2007 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2009 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2011 /* clear door drawing field */
2012 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2014 /* force DOOR font on preview level */
2015 game_status = GAME_MODE_PSEUDO_DOOR;
2017 /* write text for request */
2018 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
2020 char text_line[MAX_REQUEST_LINE_LEN + 1];
2026 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
2029 if (!tc || tc == ' ')
2040 strncpy(text_line, text, tl);
2043 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
2044 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
2045 text_line, FONT_TEXT_2);
2047 text += tl + (tc == ' ' ? 1 : 0);
2050 game_status = last_game_status; /* restore current game status */
2052 if (req_state & REQ_ASK)
2054 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2055 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2057 else if (req_state & REQ_CONFIRM)
2059 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2061 else if (req_state & REQ_PLAYER)
2063 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2064 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2065 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2066 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2069 /* copy request gadgets to door backbuffer */
2070 BlitBitmap(drawto, bitmap_db_door,
2071 DX, DY, DXSIZE, DYSIZE,
2072 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2074 OpenDoor(DOOR_OPEN_1);
2080 if (!(req_state & REQUEST_WAIT_FOR))
2082 SetDrawBackgroundMask(REDRAW_FIELD);
2087 if (game_status != GAME_MODE_MAIN)
2090 button_status = MB_RELEASED;
2092 request_gadget_id = -1;
2094 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2097 SetMouseCursor(CURSOR_DEFAULT);
2110 case EVENT_BUTTONPRESS:
2111 case EVENT_BUTTONRELEASE:
2112 case EVENT_MOTIONNOTIFY:
2114 if (event.type == EVENT_MOTIONNOTIFY)
2116 if (!PointerInWindow(window))
2117 continue; /* window and pointer are on different screens */
2122 motion_status = TRUE;
2123 mx = ((MotionEvent *) &event)->x;
2124 my = ((MotionEvent *) &event)->y;
2128 motion_status = FALSE;
2129 mx = ((ButtonEvent *) &event)->x;
2130 my = ((ButtonEvent *) &event)->y;
2131 if (event.type == EVENT_BUTTONPRESS)
2132 button_status = ((ButtonEvent *) &event)->button;
2134 button_status = MB_RELEASED;
2137 /* this sets 'request_gadget_id' */
2138 HandleGadgets(mx, my, button_status);
2140 switch(request_gadget_id)
2142 case TOOL_CTRL_ID_YES:
2145 case TOOL_CTRL_ID_NO:
2148 case TOOL_CTRL_ID_CONFIRM:
2149 result = TRUE | FALSE;
2152 case TOOL_CTRL_ID_PLAYER_1:
2155 case TOOL_CTRL_ID_PLAYER_2:
2158 case TOOL_CTRL_ID_PLAYER_3:
2161 case TOOL_CTRL_ID_PLAYER_4:
2172 case EVENT_KEYPRESS:
2173 switch(GetEventKey((KeyEvent *)&event, TRUE))
2186 if (req_state & REQ_PLAYER)
2190 case EVENT_KEYRELEASE:
2191 ClearPlayerAction();
2195 HandleOtherEvents(&event);
2199 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2201 int joy = AnyJoystick();
2203 if (joy & JOY_BUTTON_1)
2205 else if (joy & JOY_BUTTON_2)
2211 /* don't eat all CPU time */
2215 if (game_status != GAME_MODE_MAIN)
2220 if (!(req_state & REQ_STAY_OPEN))
2222 CloseDoor(DOOR_CLOSE_1);
2224 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2226 BlitBitmap(bitmap_db_door, bitmap_db_door,
2227 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2228 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2229 OpenDoor(DOOR_OPEN_1);
2235 SetDrawBackgroundMask(REDRAW_FIELD);
2237 #if defined(PLATFORM_UNIX)
2238 /* continue network game after request */
2239 if (options.network &&
2240 game_status == GAME_MODE_PLAYING &&
2241 req_state & REQUEST_WAIT_FOR)
2242 SendToServer_ContinuePlaying();
2248 unsigned int OpenDoor(unsigned int door_state)
2250 unsigned int new_door_state;
2252 if (door_state & DOOR_COPY_BACK)
2254 BlitBitmap(bitmap_db_door, bitmap_db_door,
2255 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2256 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2257 door_state &= ~DOOR_COPY_BACK;
2260 new_door_state = MoveDoor(door_state);
2262 return(new_door_state);
2265 unsigned int CloseDoor(unsigned int door_state)
2267 unsigned int new_door_state;
2269 BlitBitmap(backbuffer, bitmap_db_door,
2270 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2271 BlitBitmap(backbuffer, bitmap_db_door,
2272 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2274 new_door_state = MoveDoor(door_state);
2276 return(new_door_state);
2279 unsigned int GetDoorState()
2281 return MoveDoor(DOOR_GET_STATE);
2284 unsigned int SetDoorState(unsigned int door_state)
2286 return MoveDoor(door_state | DOOR_SET_STATE);
2289 unsigned int MoveDoor(unsigned int door_state)
2291 static int door1 = DOOR_OPEN_1;
2292 static int door2 = DOOR_CLOSE_2;
2293 unsigned long door_delay = 0;
2294 unsigned long door_delay_value;
2297 if (door_state == DOOR_GET_STATE)
2298 return(door1 | door2);
2300 if (door_state & DOOR_SET_STATE)
2302 if (door_state & DOOR_ACTION_1)
2303 door1 = door_state & DOOR_ACTION_1;
2304 if (door_state & DOOR_ACTION_2)
2305 door2 = door_state & DOOR_ACTION_2;
2307 return(door1 | door2);
2310 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2311 door_state &= ~DOOR_OPEN_1;
2312 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2313 door_state &= ~DOOR_CLOSE_1;
2314 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2315 door_state &= ~DOOR_OPEN_2;
2316 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2317 door_state &= ~DOOR_CLOSE_2;
2319 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2322 if (setup.quick_doors)
2324 stepsize = 20; /* must be choosen to always draw last frame */
2325 door_delay_value = 0;
2327 StopSound(SND_DOOR_OPENING);
2328 StopSound(SND_DOOR_CLOSING);
2331 if (global.autoplay_leveldir)
2333 door_state |= DOOR_NO_DELAY;
2334 door_state &= ~DOOR_CLOSE_ALL;
2337 if (door_state & DOOR_ACTION)
2339 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2340 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2341 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2342 int end = (door_state & DOOR_ACTION_1 &&
2343 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2346 if (!(door_state & DOOR_NO_DELAY))
2348 /* opening door sound has priority over simultaneously closing door */
2349 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2350 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2351 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2352 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2355 for(x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2357 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2358 GC gc = bitmap->stored_clip_gc;
2360 if (door_state & DOOR_ACTION_1)
2362 int a = MIN(x * door_1.step_offset, end);
2363 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2367 BlitBitmap(bitmap_db_door, drawto,
2368 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2369 DXSIZE,DYSIZE - i / 2, DX, DY);
2371 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2374 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2376 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2377 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2378 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2379 int dst2_x = DX, dst2_y = DY;
2380 int width = i, height = DYSIZE;
2382 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2383 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2386 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2387 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2390 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2392 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2393 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2394 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2395 int dst2_x = DX, dst2_y = DY;
2396 int width = DXSIZE, height = i;
2398 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2399 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2402 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2403 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2406 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2408 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2410 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2411 BlitBitmapMasked(bitmap, drawto,
2412 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2413 DX + DXSIZE - i, DY + j);
2414 BlitBitmapMasked(bitmap, drawto,
2415 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2416 DX + DXSIZE - i, DY + 140 + j);
2417 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2418 DY - (DOOR_GFX_PAGEY1 + j));
2419 BlitBitmapMasked(bitmap, drawto,
2420 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2422 BlitBitmapMasked(bitmap, drawto,
2423 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2426 BlitBitmapMasked(bitmap, drawto,
2427 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2429 BlitBitmapMasked(bitmap, drawto,
2430 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2432 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2433 BlitBitmapMasked(bitmap, drawto,
2434 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2435 DX + DXSIZE - i, DY + 77 + j);
2436 BlitBitmapMasked(bitmap, drawto,
2437 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2438 DX + DXSIZE - i, DY + 203 + j);
2441 redraw_mask |= REDRAW_DOOR_1;
2442 door_1_done = (a == end);
2445 if (door_state & DOOR_ACTION_2)
2447 int a = MIN(x * door_2.step_offset, VXSIZE);
2448 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2452 BlitBitmap(bitmap_db_door, drawto,
2453 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2454 VXSIZE, VYSIZE - i / 2, VX, VY);
2456 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2459 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2461 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2462 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2463 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2464 int dst2_x = VX, dst2_y = VY;
2465 int width = i, height = VYSIZE;
2467 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2468 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2471 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2472 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2475 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2477 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2478 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2479 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2480 int dst2_x = VX, dst2_y = VY;
2481 int width = VXSIZE, height = i;
2483 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2484 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2487 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2488 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2491 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2493 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2495 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2496 BlitBitmapMasked(bitmap, drawto,
2497 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2498 VX + VXSIZE - i, VY + j);
2499 SetClipOrigin(bitmap, gc,
2500 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2501 BlitBitmapMasked(bitmap, drawto,
2502 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2505 BlitBitmapMasked(bitmap, drawto,
2506 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2507 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2508 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2509 BlitBitmapMasked(bitmap, drawto,
2510 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2512 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2515 redraw_mask |= REDRAW_DOOR_2;
2516 door_2_done = (a == VXSIZE);
2521 if (game_status == GAME_MODE_MAIN)
2524 if (!(door_state & DOOR_NO_DELAY))
2525 WaitUntilDelayReached(&door_delay, door_delay_value);
2529 if (setup.quick_doors)
2531 StopSound(SND_DOOR_OPENING);
2532 StopSound(SND_DOOR_CLOSING);
2535 if (door_state & DOOR_ACTION_1)
2536 door1 = door_state & DOOR_ACTION_1;
2537 if (door_state & DOOR_ACTION_2)
2538 door2 = door_state & DOOR_ACTION_2;
2540 return (door1 | door2);
2543 void DrawSpecialEditorDoor()
2545 /* draw bigger toolbox window */
2546 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2547 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2549 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2550 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2553 redraw_mask |= REDRAW_ALL;
2556 void UndrawSpecialEditorDoor()
2558 /* draw normal tape recorder window */
2559 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2560 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2563 redraw_mask |= REDRAW_ALL;
2567 /* ---------- new tool button stuff ---------------------------------------- */
2569 /* graphic position values for tool buttons */
2570 #define TOOL_BUTTON_YES_XPOS 2
2571 #define TOOL_BUTTON_YES_YPOS 250
2572 #define TOOL_BUTTON_YES_GFX_YPOS 0
2573 #define TOOL_BUTTON_YES_XSIZE 46
2574 #define TOOL_BUTTON_YES_YSIZE 28
2575 #define TOOL_BUTTON_NO_XPOS 52
2576 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2577 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2578 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2579 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2580 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2581 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2582 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2583 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2584 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2585 #define TOOL_BUTTON_PLAYER_XSIZE 30
2586 #define TOOL_BUTTON_PLAYER_YSIZE 30
2587 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2588 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2589 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2590 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2591 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2592 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2593 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2594 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2595 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2596 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2597 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2598 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2599 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2600 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2601 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2602 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2603 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2604 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2605 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2606 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2615 } toolbutton_info[NUM_TOOL_BUTTONS] =
2618 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2619 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2620 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2625 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2626 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2627 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2632 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2633 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2634 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2635 TOOL_CTRL_ID_CONFIRM,
2639 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2640 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2641 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2642 TOOL_CTRL_ID_PLAYER_1,
2646 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2647 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2648 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2649 TOOL_CTRL_ID_PLAYER_2,
2653 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2654 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2655 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2656 TOOL_CTRL_ID_PLAYER_3,
2660 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2661 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2662 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2663 TOOL_CTRL_ID_PLAYER_4,
2668 void CreateToolButtons()
2672 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2674 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2675 Bitmap *deco_bitmap = None;
2676 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2677 struct GadgetInfo *gi;
2678 unsigned long event_mask;
2679 int gd_xoffset, gd_yoffset;
2680 int gd_x1, gd_x2, gd_y;
2683 event_mask = GD_EVENT_RELEASED;
2685 gd_xoffset = toolbutton_info[i].xpos;
2686 gd_yoffset = toolbutton_info[i].ypos;
2687 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2688 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2689 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2691 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2693 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2695 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2696 &deco_bitmap, &deco_x, &deco_y);
2697 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2698 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2701 gi = CreateGadget(GDI_CUSTOM_ID, id,
2702 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2703 GDI_X, DX + toolbutton_info[i].x,
2704 GDI_Y, DY + toolbutton_info[i].y,
2705 GDI_WIDTH, toolbutton_info[i].width,
2706 GDI_HEIGHT, toolbutton_info[i].height,
2707 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2708 GDI_STATE, GD_BUTTON_UNPRESSED,
2709 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2710 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2711 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2712 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2713 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2714 GDI_DECORATION_SHIFTING, 1, 1,
2715 GDI_EVENT_MASK, event_mask,
2716 GDI_CALLBACK_ACTION, HandleToolButtons,
2720 Error(ERR_EXIT, "cannot create gadget");
2722 tool_gadget[id] = gi;
2726 void FreeToolButtons()
2730 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2731 FreeGadget(tool_gadget[i]);
2734 static void UnmapToolButtons()
2738 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2739 UnmapGadget(tool_gadget[i]);
2742 static void HandleToolButtons(struct GadgetInfo *gi)
2744 request_gadget_id = gi->custom_id;
2747 int get_next_element(int element)
2751 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2752 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2753 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2754 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2755 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2756 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2757 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2759 default: return element;
2763 int el_act_dir2img(int element, int action, int direction)
2765 element = GFX_ELEMENT(element);
2766 direction = MV_DIR_BIT(direction);
2768 return element_info[element].direction_graphic[action][direction];
2771 static int el_act_dir2crm(int element, int action, int direction)
2773 element = GFX_ELEMENT(element);
2774 direction = MV_DIR_BIT(direction);
2776 return element_info[element].direction_crumbled[action][direction];
2779 int el_act2img(int element, int action)
2781 element = GFX_ELEMENT(element);
2783 return element_info[element].graphic[action];
2786 int el_act2crm(int element, int action)
2788 element = GFX_ELEMENT(element);
2790 return element_info[element].crumbled[action];
2793 int el_dir2img(int element, int direction)
2795 element = GFX_ELEMENT(element);
2797 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2800 int el2img(int element)
2802 element = GFX_ELEMENT(element);
2804 return element_info[element].graphic[ACTION_DEFAULT];
2807 int el2edimg(int element)
2809 element = GFX_ELEMENT(element);
2811 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2814 int el2preimg(int element)
2816 element = GFX_ELEMENT(element);
2818 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];